diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 554faa2c3fdf..57fcc8094912 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,8 @@ jobs: with: node-version: '20.x' - name: Install dependencies + env: + YARN_ENABLE_HARDENED_MODE: 0 run: yarn install --immutable --immutable-cache - name: Check formatting of project files run: yarn format:diff @@ -47,6 +49,8 @@ jobs: with: node-version: '20.x' - name: Install dependencies + env: + YARN_ENABLE_HARDENED_MODE: 0 run: yarn install --immutable --immutable-cache - name: Lint JavaScript files run: yarn lint @@ -72,6 +76,8 @@ jobs: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', 'packages/**/yarn.lock') }} - name: Install dependencies + env: + YARN_ENABLE_HARDENED_MODE: 0 run: yarn install --immutable --immutable-cache - name: Build project run: yarn build @@ -104,6 +110,8 @@ jobs: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', 'packages/**/yarn.lock') }} - name: Install dependencies + env: + YARN_ENABLE_HARDENED_MODE: 0 run: yarn install --immutable --immutable-cache - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: filter @@ -148,6 +156,8 @@ jobs: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', 'packages/**/yarn.lock') }} - name: Install dependencies + env: + YARN_ENABLE_HARDENED_MODE: 0 run: yarn install --immutable --immutable-cache - name: Install browsers run: yarn playwright install --with-deps @@ -215,6 +225,8 @@ jobs: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', 'packages/**/yarn.lock') }} - name: Install dependencies + env: + YARN_ENABLE_HARDENED_MODE: 0 run: yarn install --immutable --immutable-cache - name: Install browsers run: yarn playwright install --with-deps @@ -278,6 +290,8 @@ jobs: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', 'packages/**/yarn.lock') }} - name: Install dependencies + env: + YARN_ENABLE_HARDENED_MODE: 0 run: yarn install --immutable --immutable-cache - name: Download vrt blob reports from GitHub Actions Artifacts diff --git a/.github/workflows/deploy-web-components-storybook.yml b/.github/workflows/deploy-web-components-storybook.yml new file mode 100644 index 000000000000..ba5093a23662 --- /dev/null +++ b/.github/workflows/deploy-web-components-storybook.yml @@ -0,0 +1,53 @@ +name: Deploy Web Components storybook to GH pages + +on: + workflow_dispatch: + push: + tags: + # Matches tags that have the shape `vX.Y.Z`. Reference: + # https://help.github.com/en/articles/workflow-syntax-for-github-actions#onpushpull_requesttagsbranches + - 'v[0-9]+.[0-9]+.[0-9]+' + + # Ignore tags that use a preid after `vX.Y.Z`, for example: vX.Y.Z-alpha.0 + # https://help.github.com/en/articles/workflow-syntax-for-github-actions#example-using-positive-and-negative-patterns + - '!v[0-9]+.[0-9]+.[0-9]+-*' + - '!v10*' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Use Node.js 20.x + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b #v4.0.3 + with: + node-version: '20.x' + - name: Install dependencies + run: yarn install --immutable --immutable-cache + - name: Build project + run: yarn build + - name: Build static Web Components storybook + run: | + cd packages/web-components + yarn storybook:build + - name: Create CNAME + run: | + touch packages/web-components/storybook-static/CNAME + echo "web-components.carbondesignsystem.com" > packages/web-components/storybook-static/CNAME + - name: Push to Web Components repo + uses: cpina/github-action-push-to-another-repository@07c4d7b3def0a8ebe788a8f2c843a4e1de4f6900 #v1.7.2 + env: + API_TOKEN_GITHUB: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + with: + source-directory: 'packages/web-components/storybook-static' + destination-github-username: 'carbon-design-system' + destination-repository-name: 'carbon-web-components-storybook-v2' + user-name: carbon-bot + user-email: carbon@us.ibm.com + target-branch: main + commit-message: 'chore(website): update to latest' diff --git a/.github/workflows/publish-web-components-cdn.yml b/.github/workflows/publish-web-components-cdn.yml new file mode 100644 index 000000000000..6f0c33652283 --- /dev/null +++ b/.github/workflows/publish-web-components-cdn.yml @@ -0,0 +1,89 @@ +name: Publish Web Components CDN artifacts to Cloud Object Storage + +on: + workflow_dispatch: + push: + tags: + # Matches tags that have the shape `vX.Y.Z` or `vX.Y.Z-rc.X` Reference: + # https://help.github.com/en/articles/workflow-syntax-for-github-actions#onpushpull_requesttagsbranches + - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-*' + - '!v10*' + +concurrency: + group: deploy-${{ github.ref }} + cancel-in-progress: true + +jobs: + publish-cdn: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + fetch-depth: '0' + - name: Use Node.js 18.x + uses: actions/setup-node@v4 + with: + node-version: '18.x' + cache: 'yarn' + - name: Install dependencies + run: yarn install + - name: Build Web Components package + run: | + cd packages/web-components + yarn build + - name: Check release type + if: contains(github.ref_name, '-rc.') + run: echo "PRE_RELEASE=true" >> $GITHUB_ENV + - name: Get version of web components from package.json + id: package-version + uses: martinbeentjes/npm-get-version-action@v1.3.1 + with: + path: packages/web-components + + # If tag is a release candidate, upload the CDN artifacts to the `next` tag folder + # ie. https://1.www.s81c.com/common/carbon/web-components/tag/v2/next/breadcrumb.min.js + - name: Upload to COS under the `next` folder + if: ${{ env.PRE_RELEASE }} + uses: jakejarvis/s3-sync-action@master + with: + args: --acl public-read --follow-symlinks + env: + AWS_S3_BUCKET: ${{ secrets.COMMON_COS_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.COMMON_COS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.COMMON_COS_SECRET_ACCESS_KEY }} + AWS_REGION: ${{ secrets.COMMON_COS_REGION }} + AWS_S3_ENDPOINT: https://${{ secrets.COMMON_COS_ENDPOINT }} + SOURCE_DIR: 'packages/web-components/dist' + DEST_DIR: 'common/carbon/web-components/tag/v2/next' + + # If tag is a full release, upload the CDN artifacts to the `latest` tag folder + # ie. https://1.www.s81c.com/common/carbon/web-components/tag/v2/latest/breadcrumb.min.js + - name: Upload to COS under the `latest` folder + if: ${{ !env.PRE_RELEASE }} + uses: jakejarvis/s3-sync-action@master + with: + args: --acl public-read --follow-symlinks + env: + AWS_S3_BUCKET: ${{ secrets.COMMON_COS_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.COMMON_COS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.COMMON_COS_SECRET_ACCESS_KEY }} + AWS_REGION: ${{ secrets.COMMON_COS_REGION }} + AWS_S3_ENDPOINT: https://${{ secrets.COMMON_COS_ENDPOINT }} + SOURCE_DIR: 'packages/web-components/dist' + DEST_DIR: 'common/carbon/web-components/tag/v2/latest' + + # Upload the CDN artifacts to versioned folder + # ie. https://1.www.s81c.com/common/carbon/web-components/version/v2.12.0/breadcrumb.min.js + - name: Upload to COS under the versioned folder + uses: jakejarvis/s3-sync-action@master + with: + args: --acl public-read --follow-symlinks + env: + AWS_S3_BUCKET: ${{ secrets.COMMON_COS_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.COMMON_COS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.COMMON_COS_SECRET_ACCESS_KEY }} + AWS_REGION: ${{ secrets.COMMON_COS_REGION }} + AWS_S3_ENDPOINT: https://${{ secrets.COMMON_COS_ENDPOINT }} + SOURCE_DIR: 'packages/web-components/dist' + DEST_DIR: 'common/carbon/web-components/version/v${{steps.package-version.outputs.current-version}}' diff --git a/.yarn/cache/@actions-core-npm-1.10.0-6885534582-40f94a994d.zip b/.yarn/cache/@actions-core-npm-1.10.0-6885534582-40f94a994d.zip deleted file mode 100644 index a10b01ab534f..000000000000 Binary files a/.yarn/cache/@actions-core-npm-1.10.0-6885534582-40f94a994d.zip and /dev/null differ diff --git a/.yarn/cache/@actions-core-npm-1.10.1-3cb1000b4d-d32af783ec.zip b/.yarn/cache/@actions-core-npm-1.10.1-3cb1000b4d-d32af783ec.zip new file mode 100644 index 000000000000..e5b133de6cd9 Binary files /dev/null and b/.yarn/cache/@actions-core-npm-1.10.1-3cb1000b4d-d32af783ec.zip differ diff --git a/.yarn/cache/@actions-http-client-npm-2.2.0-5cded732ee-af2051e056.zip b/.yarn/cache/@actions-http-client-npm-2.2.0-5cded732ee-af2051e056.zip deleted file mode 100644 index 672c1e8d2c05..000000000000 Binary files a/.yarn/cache/@actions-http-client-npm-2.2.0-5cded732ee-af2051e056.zip and /dev/null differ diff --git a/.yarn/cache/@actions-http-client-npm-2.2.1-1cd331df79-b7338f1346.zip b/.yarn/cache/@actions-http-client-npm-2.2.1-1cd331df79-b7338f1346.zip new file mode 100644 index 000000000000..0df0cf39ea7e Binary files /dev/null and b/.yarn/cache/@actions-http-client-npm-2.2.1-1cd331df79-b7338f1346.zip differ diff --git a/.yarn/cache/@adobe-css-tools-npm-4.2.0-26da6de88a-d6d2b48963.zip b/.yarn/cache/@adobe-css-tools-npm-4.2.0-26da6de88a-d6d2b48963.zip deleted file mode 100644 index f6b77ad30598..000000000000 Binary files a/.yarn/cache/@adobe-css-tools-npm-4.2.0-26da6de88a-d6d2b48963.zip and /dev/null differ diff --git a/.yarn/cache/@adobe-css-tools-npm-4.4.0-3e89ecd033-9c6315fe9e.zip b/.yarn/cache/@adobe-css-tools-npm-4.4.0-3e89ecd033-9c6315fe9e.zip new file mode 100644 index 000000000000..677e6bf04684 Binary files /dev/null and b/.yarn/cache/@adobe-css-tools-npm-4.4.0-3e89ecd033-9c6315fe9e.zip differ diff --git a/.yarn/cache/@ampproject-remapping-npm-2.2.1-3da3d624be-e15fecbf3b.zip b/.yarn/cache/@ampproject-remapping-npm-2.2.1-3da3d624be-e15fecbf3b.zip deleted file mode 100644 index 96e09e94a33e..000000000000 Binary files a/.yarn/cache/@ampproject-remapping-npm-2.2.1-3da3d624be-e15fecbf3b.zip and /dev/null differ diff --git a/.yarn/cache/@ampproject-remapping-npm-2.3.0-559c14eee4-f345152537.zip b/.yarn/cache/@ampproject-remapping-npm-2.3.0-559c14eee4-f345152537.zip new file mode 100644 index 000000000000..6e57c13493dc Binary files /dev/null and b/.yarn/cache/@ampproject-remapping-npm-2.3.0-559c14eee4-f345152537.zip differ diff --git a/.yarn/cache/@babel-eslint-parser-npm-7.24.7-974e6645c3-4d7f1704cf.zip b/.yarn/cache/@babel-eslint-parser-npm-7.24.7-974e6645c3-4d7f1704cf.zip deleted file mode 100644 index 94c40d7173dc..000000000000 Binary files a/.yarn/cache/@babel-eslint-parser-npm-7.24.7-974e6645c3-4d7f1704cf.zip and /dev/null differ diff --git a/.yarn/cache/@babel-eslint-parser-npm-7.25.1-7c262e0e5f-9a2ddab3ac.zip b/.yarn/cache/@babel-eslint-parser-npm-7.25.1-7c262e0e5f-9a2ddab3ac.zip new file mode 100644 index 000000000000..3a0948ec22f8 Binary files /dev/null and b/.yarn/cache/@babel-eslint-parser-npm-7.25.1-7c262e0e5f-9a2ddab3ac.zip differ diff --git a/.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.24.7-076821f821-8ecb1c2acc.zip b/.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.24.7-076821f821-8ecb1c2acc.zip deleted file mode 100644 index a5a98c61edd1..000000000000 Binary files a/.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.24.7-076821f821-8ecb1c2acc.zip and /dev/null differ diff --git a/.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.25.0-8c1a9bf7ca-d0f6b63bd3.zip b/.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.25.0-8c1a9bf7ca-d0f6b63bd3.zip new file mode 100644 index 000000000000..ca26fed7cc75 Binary files /dev/null and b/.yarn/cache/@babel-helper-create-class-features-plugin-npm-7.25.0-8c1a9bf7ca-d0f6b63bd3.zip differ diff --git a/.yarn/cache/@babel-helper-environment-visitor-npm-7.24.7-9a965bf523-079d86e657.zip b/.yarn/cache/@babel-helper-environment-visitor-npm-7.24.7-9a965bf523-079d86e657.zip deleted file mode 100644 index 8fe4b856a734..000000000000 Binary files a/.yarn/cache/@babel-helper-environment-visitor-npm-7.24.7-9a965bf523-079d86e657.zip and /dev/null differ diff --git a/.yarn/cache/@babel-helper-function-name-npm-7.24.7-4f88fa6768-2ceb3d9b2b.zip b/.yarn/cache/@babel-helper-function-name-npm-7.24.7-4f88fa6768-2ceb3d9b2b.zip deleted file mode 100644 index 7b2e24b5061e..000000000000 Binary files a/.yarn/cache/@babel-helper-function-name-npm-7.24.7-4f88fa6768-2ceb3d9b2b.zip and /dev/null differ diff --git a/.yarn/cache/@babel-helper-split-export-declaration-npm-7.24.7-77b1fc1a1c-ff04a30716.zip b/.yarn/cache/@babel-helper-split-export-declaration-npm-7.24.7-77b1fc1a1c-ff04a30716.zip deleted file mode 100644 index 7ed84c9d64b1..000000000000 Binary files a/.yarn/cache/@babel-helper-split-export-declaration-npm-7.24.7-77b1fc1a1c-ff04a30716.zip and /dev/null differ diff --git a/.yarn/cache/@babel-node-npm-7.24.7-74cf6a2cb7-48c6907478.zip b/.yarn/cache/@babel-node-npm-7.24.7-74cf6a2cb7-48c6907478.zip deleted file mode 100644 index 9eb170544170..000000000000 Binary files a/.yarn/cache/@babel-node-npm-7.24.7-74cf6a2cb7-48c6907478.zip and /dev/null differ diff --git a/.yarn/cache/@babel-node-npm-7.25.0-fc4a249b19-eb157c1d89.zip b/.yarn/cache/@babel-node-npm-7.25.0-fc4a249b19-eb157c1d89.zip new file mode 100644 index 000000000000..9d1869883724 Binary files /dev/null and b/.yarn/cache/@babel-node-npm-7.25.0-fc4a249b19-eb157c1d89.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-react-constant-elements-npm-7.24.7-0b04ecb934-f0e1031920.zip b/.yarn/cache/@babel-plugin-transform-react-constant-elements-npm-7.24.7-0b04ecb934-f0e1031920.zip deleted file mode 100644 index 6def5514f03c..000000000000 Binary files a/.yarn/cache/@babel-plugin-transform-react-constant-elements-npm-7.24.7-0b04ecb934-f0e1031920.zip and /dev/null differ diff --git a/.yarn/cache/@babel-plugin-transform-react-constant-elements-npm-7.25.1-71586d859d-c0c4bb7dee.zip b/.yarn/cache/@babel-plugin-transform-react-constant-elements-npm-7.25.1-71586d859d-c0c4bb7dee.zip new file mode 100644 index 000000000000..2f74c6f2595f Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-react-constant-elements-npm-7.25.1-71586d859d-c0c4bb7dee.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-react-jsx-npm-7.24.7-e626253a5c-422952e034.zip b/.yarn/cache/@babel-plugin-transform-react-jsx-npm-7.24.7-e626253a5c-422952e034.zip deleted file mode 100644 index 08546cce9179..000000000000 Binary files a/.yarn/cache/@babel-plugin-transform-react-jsx-npm-7.24.7-e626253a5c-422952e034.zip and /dev/null differ diff --git a/.yarn/cache/@babel-plugin-transform-react-jsx-npm-7.25.2-1cc057ac5e-4cab884962.zip b/.yarn/cache/@babel-plugin-transform-react-jsx-npm-7.25.2-1cc057ac5e-4cab884962.zip new file mode 100644 index 000000000000..2aa0dee2c0a6 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-react-jsx-npm-7.25.2-1cc057ac5e-4cab884962.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-react-jsx-self-npm-7.21.0-9f64a88644-696f74c04a.zip b/.yarn/cache/@babel-plugin-transform-react-jsx-self-npm-7.21.0-9f64a88644-696f74c04a.zip deleted file mode 100644 index 6f802b04761f..000000000000 Binary files a/.yarn/cache/@babel-plugin-transform-react-jsx-self-npm-7.21.0-9f64a88644-696f74c04a.zip and /dev/null differ diff --git a/.yarn/cache/@babel-plugin-transform-react-jsx-self-npm-7.24.7-c9c51f3b98-56115b4a6c.zip b/.yarn/cache/@babel-plugin-transform-react-jsx-self-npm-7.24.7-c9c51f3b98-56115b4a6c.zip new file mode 100644 index 000000000000..ab17211746bf Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-react-jsx-self-npm-7.24.7-c9c51f3b98-56115b4a6c.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-react-jsx-source-npm-7.19.6-f7b8cba2b3-1e9e29a4ef.zip b/.yarn/cache/@babel-plugin-transform-react-jsx-source-npm-7.19.6-f7b8cba2b3-1e9e29a4ef.zip deleted file mode 100644 index 475edd372b77..000000000000 Binary files a/.yarn/cache/@babel-plugin-transform-react-jsx-source-npm-7.19.6-f7b8cba2b3-1e9e29a4ef.zip and /dev/null differ diff --git a/.yarn/cache/@babel-plugin-transform-react-jsx-source-npm-7.24.7-3460f8935a-682e2ae15d.zip b/.yarn/cache/@babel-plugin-transform-react-jsx-source-npm-7.24.7-3460f8935a-682e2ae15d.zip new file mode 100644 index 000000000000..aba982bb1c3b Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-react-jsx-source-npm-7.24.7-3460f8935a-682e2ae15d.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-typescript-npm-7.24.7-72a8b52c30-6a4af5a96a.zip b/.yarn/cache/@babel-plugin-transform-typescript-npm-7.24.7-72a8b52c30-6a4af5a96a.zip deleted file mode 100644 index 5d7547e0b8da..000000000000 Binary files a/.yarn/cache/@babel-plugin-transform-typescript-npm-7.24.7-72a8b52c30-6a4af5a96a.zip and /dev/null differ diff --git a/.yarn/cache/@babel-plugin-transform-typescript-npm-7.25.2-99d4e753c3-50e017ffd1.zip b/.yarn/cache/@babel-plugin-transform-typescript-npm-7.25.2-99d4e753c3-50e017ffd1.zip new file mode 100644 index 000000000000..0036f40a9eb7 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-typescript-npm-7.25.2-99d4e753c3-50e017ffd1.zip differ diff --git a/.yarn/cache/@babel-runtime-npm-7.24.7-035e043b00-7b77f56616.zip b/.yarn/cache/@babel-runtime-npm-7.24.7-035e043b00-7b77f56616.zip deleted file mode 100644 index 59afc15b3210..000000000000 Binary files a/.yarn/cache/@babel-runtime-npm-7.24.7-035e043b00-7b77f56616.zip and /dev/null differ diff --git a/.yarn/cache/@babel-runtime-npm-7.25.0-a7bca33687-6870e9e0e9.zip b/.yarn/cache/@babel-runtime-npm-7.25.0-a7bca33687-6870e9e0e9.zip new file mode 100644 index 000000000000..e10a95626cbb Binary files /dev/null and b/.yarn/cache/@babel-runtime-npm-7.25.0-a7bca33687-6870e9e0e9.zip differ diff --git a/.yarn/cache/@carbon-colors-npm-11.24.0-baa2aca6ab-0e20f8c710.zip b/.yarn/cache/@carbon-colors-npm-11.24.0-baa2aca6ab-0e20f8c710.zip new file mode 100644 index 000000000000..e87bb489777e Binary files /dev/null and b/.yarn/cache/@carbon-colors-npm-11.24.0-baa2aca6ab-0e20f8c710.zip differ diff --git a/.yarn/cache/@carbon-feature-flags-npm-0.21.0-a726e739fc-c8d9377cfd.zip b/.yarn/cache/@carbon-feature-flags-npm-0.21.0-a726e739fc-c8d9377cfd.zip new file mode 100644 index 000000000000..e577350b9bb7 Binary files /dev/null and b/.yarn/cache/@carbon-feature-flags-npm-0.21.0-a726e739fc-c8d9377cfd.zip differ diff --git a/.yarn/cache/@carbon-grid-npm-11.25.0-52711f35a8-3f6e01a8a4.zip b/.yarn/cache/@carbon-grid-npm-11.25.0-52711f35a8-3f6e01a8a4.zip new file mode 100644 index 000000000000..2dc976f1dac9 Binary files /dev/null and b/.yarn/cache/@carbon-grid-npm-11.25.0-52711f35a8-3f6e01a8a4.zip differ diff --git a/.yarn/cache/@carbon-ibm-products-styles-npm-2.41.0-25232690f1-655cdfe81e.zip b/.yarn/cache/@carbon-ibm-products-styles-npm-2.41.0-25232690f1-655cdfe81e.zip new file mode 100644 index 000000000000..6effef859aa0 Binary files /dev/null and b/.yarn/cache/@carbon-ibm-products-styles-npm-2.41.0-25232690f1-655cdfe81e.zip differ diff --git a/.yarn/cache/@carbon-icon-helpers-npm-10.47.0-ebf51b8989-fafdf544c0.zip b/.yarn/cache/@carbon-icon-helpers-npm-10.47.0-ebf51b8989-fafdf544c0.zip new file mode 100644 index 000000000000..a0cac0a32626 Binary files /dev/null and b/.yarn/cache/@carbon-icon-helpers-npm-10.47.0-ebf51b8989-fafdf544c0.zip differ diff --git a/.yarn/cache/@carbon-icons-npm-11.45.0-ef2a754b42-901baa6f7f.zip b/.yarn/cache/@carbon-icons-npm-11.45.0-ef2a754b42-901baa6f7f.zip new file mode 100644 index 000000000000..4d9920b37a1f Binary files /dev/null and b/.yarn/cache/@carbon-icons-npm-11.45.0-ef2a754b42-901baa6f7f.zip differ diff --git a/.yarn/cache/@carbon-layout-npm-11.24.0-46aafe539d-f09cb9fdc1.zip b/.yarn/cache/@carbon-layout-npm-11.24.0-46aafe539d-f09cb9fdc1.zip new file mode 100644 index 000000000000..9725b5a5e0aa Binary files /dev/null and b/.yarn/cache/@carbon-layout-npm-11.24.0-46aafe539d-f09cb9fdc1.zip differ diff --git a/.yarn/cache/@carbon-motion-npm-11.20.0-3186fa3a66-a5fe6123fc.zip b/.yarn/cache/@carbon-motion-npm-11.20.0-3186fa3a66-a5fe6123fc.zip new file mode 100644 index 000000000000..052eee910363 Binary files /dev/null and b/.yarn/cache/@carbon-motion-npm-11.20.0-3186fa3a66-a5fe6123fc.zip differ diff --git a/.yarn/cache/@carbon-styles-npm-1.63.1-724cdb195c-fe83a42fc0.zip b/.yarn/cache/@carbon-styles-npm-1.63.1-724cdb195c-fe83a42fc0.zip new file mode 100644 index 000000000000..f0bc3e85b514 Binary files /dev/null and b/.yarn/cache/@carbon-styles-npm-1.63.1-724cdb195c-fe83a42fc0.zip differ diff --git a/.yarn/cache/@carbon-themes-npm-11.38.0-11c235d00e-d756fae116.zip b/.yarn/cache/@carbon-themes-npm-11.38.0-11c235d00e-d756fae116.zip new file mode 100644 index 000000000000..91e9eb2c39f7 Binary files /dev/null and b/.yarn/cache/@carbon-themes-npm-11.38.0-11c235d00e-d756fae116.zip differ diff --git a/.yarn/cache/@carbon-type-npm-11.29.0-215728b524-5bf2a36d22.zip b/.yarn/cache/@carbon-type-npm-11.29.0-215728b524-5bf2a36d22.zip new file mode 100644 index 000000000000..6e57897db84b Binary files /dev/null and b/.yarn/cache/@carbon-type-npm-11.29.0-215728b524-5bf2a36d22.zip differ diff --git a/.yarn/cache/@commitlint-cli-npm-18.2.0-8b4567663b-4c2dcac432.zip b/.yarn/cache/@commitlint-cli-npm-18.2.0-8b4567663b-4c2dcac432.zip deleted file mode 100644 index 0b859dd3864e..000000000000 Binary files a/.yarn/cache/@commitlint-cli-npm-18.2.0-8b4567663b-4c2dcac432.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-cli-npm-18.6.1-caf27e769a-3aa3791658.zip b/.yarn/cache/@commitlint-cli-npm-18.6.1-caf27e769a-3aa3791658.zip new file mode 100644 index 000000000000..7ddcf33d59f6 Binary files /dev/null and b/.yarn/cache/@commitlint-cli-npm-18.6.1-caf27e769a-3aa3791658.zip differ diff --git a/.yarn/cache/@commitlint-config-conventional-npm-18.1.0-b93abfed15-1cbb05b52f.zip b/.yarn/cache/@commitlint-config-conventional-npm-18.1.0-b93abfed15-1cbb05b52f.zip deleted file mode 100644 index 957eb1a5592f..000000000000 Binary files a/.yarn/cache/@commitlint-config-conventional-npm-18.1.0-b93abfed15-1cbb05b52f.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-config-conventional-npm-18.6.3-1057bfca92-888c016c37.zip b/.yarn/cache/@commitlint-config-conventional-npm-18.6.3-1057bfca92-888c016c37.zip new file mode 100644 index 000000000000..55b9eb8f3644 Binary files /dev/null and b/.yarn/cache/@commitlint-config-conventional-npm-18.6.3-1057bfca92-888c016c37.zip differ diff --git a/.yarn/cache/@commitlint-config-validator-npm-18.1.0-009b2596c9-3ceb6e8a21.zip b/.yarn/cache/@commitlint-config-validator-npm-18.1.0-009b2596c9-3ceb6e8a21.zip deleted file mode 100644 index 9a98afb49fa2..000000000000 Binary files a/.yarn/cache/@commitlint-config-validator-npm-18.1.0-009b2596c9-3ceb6e8a21.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-config-validator-npm-18.6.1-cbb4e197cf-4e5b5ba01d.zip b/.yarn/cache/@commitlint-config-validator-npm-18.6.1-cbb4e197cf-4e5b5ba01d.zip new file mode 100644 index 000000000000..dd8d2020e91e Binary files /dev/null and b/.yarn/cache/@commitlint-config-validator-npm-18.6.1-cbb4e197cf-4e5b5ba01d.zip differ diff --git a/.yarn/cache/@commitlint-ensure-npm-18.1.0-91319a0e3b-3d181d44f8.zip b/.yarn/cache/@commitlint-ensure-npm-18.1.0-91319a0e3b-3d181d44f8.zip deleted file mode 100644 index d64789deb047..000000000000 Binary files a/.yarn/cache/@commitlint-ensure-npm-18.1.0-91319a0e3b-3d181d44f8.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-ensure-npm-18.6.1-0e285c0eb6-0a5c284dcc.zip b/.yarn/cache/@commitlint-ensure-npm-18.6.1-0e285c0eb6-0a5c284dcc.zip new file mode 100644 index 000000000000..5b68bab299c6 Binary files /dev/null and b/.yarn/cache/@commitlint-ensure-npm-18.6.1-0e285c0eb6-0a5c284dcc.zip differ diff --git a/.yarn/cache/@commitlint-execute-rule-npm-18.1.0-607c5aa132-c0040df75e.zip b/.yarn/cache/@commitlint-execute-rule-npm-18.1.0-607c5aa132-c0040df75e.zip deleted file mode 100644 index ef1e1a1a41bd..000000000000 Binary files a/.yarn/cache/@commitlint-execute-rule-npm-18.1.0-607c5aa132-c0040df75e.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-execute-rule-npm-18.6.1-22fef67cdf-4bb7945b90.zip b/.yarn/cache/@commitlint-execute-rule-npm-18.6.1-22fef67cdf-4bb7945b90.zip new file mode 100644 index 000000000000..1dfc867443d6 Binary files /dev/null and b/.yarn/cache/@commitlint-execute-rule-npm-18.6.1-22fef67cdf-4bb7945b90.zip differ diff --git a/.yarn/cache/@commitlint-format-npm-18.1.0-1dfc3241ff-ad631b7ab2.zip b/.yarn/cache/@commitlint-format-npm-18.1.0-1dfc3241ff-ad631b7ab2.zip deleted file mode 100644 index 8ee3f5e794ce..000000000000 Binary files a/.yarn/cache/@commitlint-format-npm-18.1.0-1dfc3241ff-ad631b7ab2.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-format-npm-18.6.1-4937158534-c079b1d3a0.zip b/.yarn/cache/@commitlint-format-npm-18.6.1-4937158534-c079b1d3a0.zip new file mode 100644 index 000000000000..4fd94f82b37c Binary files /dev/null and b/.yarn/cache/@commitlint-format-npm-18.6.1-4937158534-c079b1d3a0.zip differ diff --git a/.yarn/cache/@commitlint-is-ignored-npm-18.1.0-8d5432023d-650c4e6833.zip b/.yarn/cache/@commitlint-is-ignored-npm-18.1.0-8d5432023d-650c4e6833.zip deleted file mode 100644 index e9a5e7ebcbd7..000000000000 Binary files a/.yarn/cache/@commitlint-is-ignored-npm-18.1.0-8d5432023d-650c4e6833.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-is-ignored-npm-18.6.1-72e9942760-fffe73b283.zip b/.yarn/cache/@commitlint-is-ignored-npm-18.6.1-72e9942760-fffe73b283.zip new file mode 100644 index 000000000000..8961b93ff6e1 Binary files /dev/null and b/.yarn/cache/@commitlint-is-ignored-npm-18.6.1-72e9942760-fffe73b283.zip differ diff --git a/.yarn/cache/@commitlint-lint-npm-18.1.0-e4cdb02879-337a175746.zip b/.yarn/cache/@commitlint-lint-npm-18.1.0-e4cdb02879-337a175746.zip deleted file mode 100644 index f2f1984fbbfd..000000000000 Binary files a/.yarn/cache/@commitlint-lint-npm-18.1.0-e4cdb02879-337a175746.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-lint-npm-18.6.1-be36d4ec2f-36329c65d8.zip b/.yarn/cache/@commitlint-lint-npm-18.6.1-be36d4ec2f-36329c65d8.zip new file mode 100644 index 000000000000..beca1902a578 Binary files /dev/null and b/.yarn/cache/@commitlint-lint-npm-18.6.1-be36d4ec2f-36329c65d8.zip differ diff --git a/.yarn/cache/@commitlint-load-npm-18.2.0-0f8adee39a-df624f81e9.zip b/.yarn/cache/@commitlint-load-npm-18.2.0-0f8adee39a-df624f81e9.zip deleted file mode 100644 index ca3c7445aa77..000000000000 Binary files a/.yarn/cache/@commitlint-load-npm-18.2.0-0f8adee39a-df624f81e9.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-load-npm-18.6.1-9efb038367-383a9a59c5.zip b/.yarn/cache/@commitlint-load-npm-18.6.1-9efb038367-383a9a59c5.zip new file mode 100644 index 000000000000..54666b9381c8 Binary files /dev/null and b/.yarn/cache/@commitlint-load-npm-18.6.1-9efb038367-383a9a59c5.zip differ diff --git a/.yarn/cache/@commitlint-message-npm-18.1.0-ae93165913-b002d38a00.zip b/.yarn/cache/@commitlint-message-npm-18.1.0-ae93165913-b002d38a00.zip deleted file mode 100644 index b6ce2269e721..000000000000 Binary files a/.yarn/cache/@commitlint-message-npm-18.1.0-ae93165913-b002d38a00.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-message-npm-18.6.1-bd3f7b65e0-e9a0b7f17b.zip b/.yarn/cache/@commitlint-message-npm-18.6.1-bd3f7b65e0-e9a0b7f17b.zip new file mode 100644 index 000000000000..930ed73f9be7 Binary files /dev/null and b/.yarn/cache/@commitlint-message-npm-18.6.1-bd3f7b65e0-e9a0b7f17b.zip differ diff --git a/.yarn/cache/@commitlint-parse-npm-18.1.0-a363fe031c-35feae6b9b.zip b/.yarn/cache/@commitlint-parse-npm-18.1.0-a363fe031c-35feae6b9b.zip deleted file mode 100644 index 85cd1554fccc..000000000000 Binary files a/.yarn/cache/@commitlint-parse-npm-18.1.0-a363fe031c-35feae6b9b.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-parse-npm-18.6.1-4234cbc168-74891afc03.zip b/.yarn/cache/@commitlint-parse-npm-18.6.1-4234cbc168-74891afc03.zip new file mode 100644 index 000000000000..6128afeb77c3 Binary files /dev/null and b/.yarn/cache/@commitlint-parse-npm-18.6.1-4234cbc168-74891afc03.zip differ diff --git a/.yarn/cache/@commitlint-read-npm-18.1.0-2da9e3a77b-3169febebe.zip b/.yarn/cache/@commitlint-read-npm-18.1.0-2da9e3a77b-3169febebe.zip deleted file mode 100644 index 8d47ddac37a9..000000000000 Binary files a/.yarn/cache/@commitlint-read-npm-18.1.0-2da9e3a77b-3169febebe.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-read-npm-18.6.1-f035cba03f-fae8939982.zip b/.yarn/cache/@commitlint-read-npm-18.6.1-f035cba03f-fae8939982.zip new file mode 100644 index 000000000000..7cdd2f67573b Binary files /dev/null and b/.yarn/cache/@commitlint-read-npm-18.6.1-f035cba03f-fae8939982.zip differ diff --git a/.yarn/cache/@commitlint-resolve-extends-npm-18.1.0-c5f6c23580-41ef9a38c5.zip b/.yarn/cache/@commitlint-resolve-extends-npm-18.1.0-c5f6c23580-41ef9a38c5.zip deleted file mode 100644 index bb6cfb747a13..000000000000 Binary files a/.yarn/cache/@commitlint-resolve-extends-npm-18.1.0-c5f6c23580-41ef9a38c5.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-resolve-extends-npm-18.6.1-177c8b9a6c-d9077b4beb.zip b/.yarn/cache/@commitlint-resolve-extends-npm-18.6.1-177c8b9a6c-d9077b4beb.zip new file mode 100644 index 000000000000..e25d86851200 Binary files /dev/null and b/.yarn/cache/@commitlint-resolve-extends-npm-18.6.1-177c8b9a6c-d9077b4beb.zip differ diff --git a/.yarn/cache/@commitlint-rules-npm-18.1.0-122a3a4d79-c4e5ce76bc.zip b/.yarn/cache/@commitlint-rules-npm-18.1.0-122a3a4d79-c4e5ce76bc.zip deleted file mode 100644 index 54b2ad4f85b2..000000000000 Binary files a/.yarn/cache/@commitlint-rules-npm-18.1.0-122a3a4d79-c4e5ce76bc.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-rules-npm-18.6.1-75a854366c-2b7b940d34.zip b/.yarn/cache/@commitlint-rules-npm-18.6.1-75a854366c-2b7b940d34.zip new file mode 100644 index 000000000000..06cc632ae2d2 Binary files /dev/null and b/.yarn/cache/@commitlint-rules-npm-18.6.1-75a854366c-2b7b940d34.zip differ diff --git a/.yarn/cache/@commitlint-to-lines-npm-18.1.0-f350778019-90da051ce2.zip b/.yarn/cache/@commitlint-to-lines-npm-18.1.0-f350778019-90da051ce2.zip deleted file mode 100644 index 31ce3ea97c30..000000000000 Binary files a/.yarn/cache/@commitlint-to-lines-npm-18.1.0-f350778019-90da051ce2.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-to-lines-npm-18.6.1-f9add16bf8-eb5bb658a9.zip b/.yarn/cache/@commitlint-to-lines-npm-18.6.1-f9add16bf8-eb5bb658a9.zip new file mode 100644 index 000000000000..555c5bfb80aa Binary files /dev/null and b/.yarn/cache/@commitlint-to-lines-npm-18.6.1-f9add16bf8-eb5bb658a9.zip differ diff --git a/.yarn/cache/@commitlint-top-level-npm-18.1.0-a81169286c-62729536fd.zip b/.yarn/cache/@commitlint-top-level-npm-18.1.0-a81169286c-62729536fd.zip deleted file mode 100644 index b838c87aa556..000000000000 Binary files a/.yarn/cache/@commitlint-top-level-npm-18.1.0-a81169286c-62729536fd.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-top-level-npm-18.6.1-2068f4fd78-059ff78ac7.zip b/.yarn/cache/@commitlint-top-level-npm-18.6.1-2068f4fd78-059ff78ac7.zip new file mode 100644 index 000000000000..a637ca5e3356 Binary files /dev/null and b/.yarn/cache/@commitlint-top-level-npm-18.6.1-2068f4fd78-059ff78ac7.zip differ diff --git a/.yarn/cache/@commitlint-types-npm-18.1.0-6b24f49909-50501399dd.zip b/.yarn/cache/@commitlint-types-npm-18.1.0-6b24f49909-50501399dd.zip deleted file mode 100644 index 08d53c054723..000000000000 Binary files a/.yarn/cache/@commitlint-types-npm-18.1.0-6b24f49909-50501399dd.zip and /dev/null differ diff --git a/.yarn/cache/@commitlint-types-npm-18.6.1-e00c113558-fb37bdefd2.zip b/.yarn/cache/@commitlint-types-npm-18.6.1-e00c113558-fb37bdefd2.zip new file mode 100644 index 000000000000..985d17c46268 Binary files /dev/null and b/.yarn/cache/@commitlint-types-npm-18.6.1-e00c113558-fb37bdefd2.zip differ diff --git a/.yarn/cache/@csstools-css-parser-algorithms-npm-2.3.0-b7ef496af2-a5c2d9029f.zip b/.yarn/cache/@csstools-css-parser-algorithms-npm-2.3.0-b7ef496af2-a5c2d9029f.zip deleted file mode 100644 index 6aa9ba2d1ac6..000000000000 Binary files a/.yarn/cache/@csstools-css-parser-algorithms-npm-2.3.0-b7ef496af2-a5c2d9029f.zip and /dev/null differ diff --git a/.yarn/cache/@csstools-css-parser-algorithms-npm-2.7.1-8dc62b9586-939b23652c.zip b/.yarn/cache/@csstools-css-parser-algorithms-npm-2.7.1-8dc62b9586-939b23652c.zip new file mode 100644 index 000000000000..6ddd74202805 Binary files /dev/null and b/.yarn/cache/@csstools-css-parser-algorithms-npm-2.7.1-8dc62b9586-939b23652c.zip differ diff --git a/.yarn/cache/@csstools-css-tokenizer-npm-2.1.1-267c589583-79b63aabea.zip b/.yarn/cache/@csstools-css-tokenizer-npm-2.1.1-267c589583-79b63aabea.zip deleted file mode 100644 index 095cb3c50b3b..000000000000 Binary files a/.yarn/cache/@csstools-css-tokenizer-npm-2.1.1-267c589583-79b63aabea.zip and /dev/null differ diff --git a/.yarn/cache/@csstools-css-tokenizer-npm-2.4.1-51184be252-a368e5c96d.zip b/.yarn/cache/@csstools-css-tokenizer-npm-2.4.1-51184be252-a368e5c96d.zip new file mode 100644 index 000000000000..c3c135bc4be8 Binary files /dev/null and b/.yarn/cache/@csstools-css-tokenizer-npm-2.4.1-51184be252-a368e5c96d.zip differ diff --git a/.yarn/cache/@csstools-media-query-list-parser-npm-2.1.13-cb3cb9a768-4a771d94eb.zip b/.yarn/cache/@csstools-media-query-list-parser-npm-2.1.13-cb3cb9a768-4a771d94eb.zip new file mode 100644 index 000000000000..7909ff2d5f36 Binary files /dev/null and b/.yarn/cache/@csstools-media-query-list-parser-npm-2.1.13-cb3cb9a768-4a771d94eb.zip differ diff --git a/.yarn/cache/@csstools-media-query-list-parser-npm-2.1.2-27e56ce5bc-02cb4bbbc1.zip b/.yarn/cache/@csstools-media-query-list-parser-npm-2.1.2-27e56ce5bc-02cb4bbbc1.zip deleted file mode 100644 index a458b30fa6f3..000000000000 Binary files a/.yarn/cache/@csstools-media-query-list-parser-npm-2.1.2-27e56ce5bc-02cb4bbbc1.zip and /dev/null differ diff --git a/.yarn/cache/@csstools-selector-specificity-npm-3.0.0-c3934051c2-4a2dfe6999.zip b/.yarn/cache/@csstools-selector-specificity-npm-3.0.0-c3934051c2-4a2dfe6999.zip deleted file mode 100644 index bc28b85bc771..000000000000 Binary files a/.yarn/cache/@csstools-selector-specificity-npm-3.0.0-c3934051c2-4a2dfe6999.zip and /dev/null differ diff --git a/.yarn/cache/@csstools-selector-specificity-npm-3.1.1-85fd5757fc-3786a6afea.zip b/.yarn/cache/@csstools-selector-specificity-npm-3.1.1-85fd5757fc-3786a6afea.zip new file mode 100644 index 000000000000..ab9c573c5d5b Binary files /dev/null and b/.yarn/cache/@csstools-selector-specificity-npm-3.1.1-85fd5757fc-3786a6afea.zip differ diff --git a/.yarn/cache/@emnapi-core-npm-1.2.0-16d3729431-b0b32b7702.zip b/.yarn/cache/@emnapi-core-npm-1.2.0-16d3729431-b0b32b7702.zip new file mode 100644 index 000000000000..7093d38372c0 Binary files /dev/null and b/.yarn/cache/@emnapi-core-npm-1.2.0-16d3729431-b0b32b7702.zip differ diff --git a/.yarn/cache/@emnapi-runtime-npm-1.2.0-36d2203035-c954b36493.zip b/.yarn/cache/@emnapi-runtime-npm-1.2.0-36d2203035-c954b36493.zip new file mode 100644 index 000000000000..8f5a470d4e94 Binary files /dev/null and b/.yarn/cache/@emnapi-runtime-npm-1.2.0-36d2203035-c954b36493.zip differ diff --git a/.yarn/cache/@emnapi-wasi-threads-npm-1.0.1-a3701691ed-949f8bdcb1.zip b/.yarn/cache/@emnapi-wasi-threads-npm-1.0.1-a3701691ed-949f8bdcb1.zip new file mode 100644 index 000000000000..a59b3fea782f Binary files /dev/null and b/.yarn/cache/@emnapi-wasi-threads-npm-1.0.1-a3701691ed-949f8bdcb1.zip differ diff --git a/.yarn/cache/@emotion-use-insertion-effect-with-fallbacks-npm-1.0.1-730758c66c-7d7ead9ba3.zip b/.yarn/cache/@emotion-use-insertion-effect-with-fallbacks-npm-1.0.1-730758c66c-7d7ead9ba3.zip deleted file mode 100644 index 211dd1415c2a..000000000000 Binary files a/.yarn/cache/@emotion-use-insertion-effect-with-fallbacks-npm-1.0.1-730758c66c-7d7ead9ba3.zip and /dev/null differ diff --git a/.yarn/cache/@emotion-use-insertion-effect-with-fallbacks-npm-1.1.0-cf34827cd6-33a10f44a8.zip b/.yarn/cache/@emotion-use-insertion-effect-with-fallbacks-npm-1.1.0-cf34827cd6-33a10f44a8.zip new file mode 100644 index 000000000000..e8453ca18f72 Binary files /dev/null and b/.yarn/cache/@emotion-use-insertion-effect-with-fallbacks-npm-1.1.0-cf34827cd6-33a10f44a8.zip differ diff --git a/.yarn/cache/@esbuild-darwin-arm64-npm-0.17.19-64d69299ed-10.zip b/.yarn/cache/@esbuild-darwin-arm64-npm-0.17.19-64d69299ed-10.zip deleted file mode 100644 index a8f1e57ef1c9..000000000000 Binary files a/.yarn/cache/@esbuild-darwin-arm64-npm-0.17.19-64d69299ed-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-darwin-arm64-npm-0.18.20-00b3504077-10.zip b/.yarn/cache/@esbuild-darwin-arm64-npm-0.18.20-00b3504077-10.zip new file mode 100644 index 000000000000..fe099945524f Binary files /dev/null and b/.yarn/cache/@esbuild-darwin-arm64-npm-0.18.20-00b3504077-10.zip differ diff --git a/.yarn/cache/@esbuild-darwin-arm64-npm-0.23.0-c07423ec26-10.zip b/.yarn/cache/@esbuild-darwin-arm64-npm-0.23.0-c07423ec26-10.zip deleted file mode 100644 index f791e4051363..000000000000 Binary files a/.yarn/cache/@esbuild-darwin-arm64-npm-0.23.0-c07423ec26-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-darwin-arm64-npm-0.23.1-1d26281f3d-10.zip b/.yarn/cache/@esbuild-darwin-arm64-npm-0.23.1-1d26281f3d-10.zip new file mode 100644 index 000000000000..3b3418b7ef9f Binary files /dev/null and b/.yarn/cache/@esbuild-darwin-arm64-npm-0.23.1-1d26281f3d-10.zip differ diff --git a/.yarn/cache/@esbuild-darwin-x64-npm-0.17.19-30afb0190b-10.zip b/.yarn/cache/@esbuild-darwin-x64-npm-0.17.19-30afb0190b-10.zip deleted file mode 100644 index 888c7cacc49a..000000000000 Binary files a/.yarn/cache/@esbuild-darwin-x64-npm-0.17.19-30afb0190b-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-darwin-x64-npm-0.18.20-767fe27d1b-10.zip b/.yarn/cache/@esbuild-darwin-x64-npm-0.18.20-767fe27d1b-10.zip new file mode 100644 index 000000000000..e9c872798a76 Binary files /dev/null and b/.yarn/cache/@esbuild-darwin-x64-npm-0.18.20-767fe27d1b-10.zip differ diff --git a/.yarn/cache/@esbuild-darwin-x64-npm-0.23.0-38ebeac8f3-10.zip b/.yarn/cache/@esbuild-darwin-x64-npm-0.23.0-38ebeac8f3-10.zip deleted file mode 100644 index 34b0c8e8a772..000000000000 Binary files a/.yarn/cache/@esbuild-darwin-x64-npm-0.23.0-38ebeac8f3-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-darwin-x64-npm-0.23.1-2ea8826480-10.zip b/.yarn/cache/@esbuild-darwin-x64-npm-0.23.1-2ea8826480-10.zip new file mode 100644 index 000000000000..4b864db78e7d Binary files /dev/null and b/.yarn/cache/@esbuild-darwin-x64-npm-0.23.1-2ea8826480-10.zip differ diff --git a/.yarn/cache/@esbuild-linux-arm64-npm-0.17.19-6f31af48bb-10.zip b/.yarn/cache/@esbuild-linux-arm64-npm-0.17.19-6f31af48bb-10.zip deleted file mode 100644 index f12994b9dd01..000000000000 Binary files a/.yarn/cache/@esbuild-linux-arm64-npm-0.17.19-6f31af48bb-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-linux-arm64-npm-0.18.20-7b48b328fe-10.zip b/.yarn/cache/@esbuild-linux-arm64-npm-0.18.20-7b48b328fe-10.zip new file mode 100644 index 000000000000..728cccd6c7c0 Binary files /dev/null and b/.yarn/cache/@esbuild-linux-arm64-npm-0.18.20-7b48b328fe-10.zip differ diff --git a/.yarn/cache/@esbuild-linux-arm64-npm-0.23.0-9639e2cb7c-10.zip b/.yarn/cache/@esbuild-linux-arm64-npm-0.23.0-9639e2cb7c-10.zip deleted file mode 100644 index 17cc7e593550..000000000000 Binary files a/.yarn/cache/@esbuild-linux-arm64-npm-0.23.0-9639e2cb7c-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-linux-arm64-npm-0.23.1-9b07bf2e0f-10.zip b/.yarn/cache/@esbuild-linux-arm64-npm-0.23.1-9b07bf2e0f-10.zip new file mode 100644 index 000000000000..42680e31532a Binary files /dev/null and b/.yarn/cache/@esbuild-linux-arm64-npm-0.23.1-9b07bf2e0f-10.zip differ diff --git a/.yarn/cache/@esbuild-linux-x64-npm-0.17.19-08a7136aa6-10.zip b/.yarn/cache/@esbuild-linux-x64-npm-0.17.19-08a7136aa6-10.zip deleted file mode 100644 index ee6c567a81ce..000000000000 Binary files a/.yarn/cache/@esbuild-linux-x64-npm-0.17.19-08a7136aa6-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-linux-x64-npm-0.18.20-de8e99b449-10.zip b/.yarn/cache/@esbuild-linux-x64-npm-0.18.20-de8e99b449-10.zip new file mode 100644 index 000000000000..67ac3efedd79 Binary files /dev/null and b/.yarn/cache/@esbuild-linux-x64-npm-0.18.20-de8e99b449-10.zip differ diff --git a/.yarn/cache/@esbuild-linux-x64-npm-0.23.0-4cf21ebea7-10.zip b/.yarn/cache/@esbuild-linux-x64-npm-0.23.0-4cf21ebea7-10.zip deleted file mode 100644 index 3d02725c4a08..000000000000 Binary files a/.yarn/cache/@esbuild-linux-x64-npm-0.23.0-4cf21ebea7-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-linux-x64-npm-0.23.1-e5d2d8764d-10.zip b/.yarn/cache/@esbuild-linux-x64-npm-0.23.1-e5d2d8764d-10.zip new file mode 100644 index 000000000000..01cb658ce506 Binary files /dev/null and b/.yarn/cache/@esbuild-linux-x64-npm-0.23.1-e5d2d8764d-10.zip differ diff --git a/.yarn/cache/@esbuild-win32-arm64-npm-0.17.19-8006d17388-10.zip b/.yarn/cache/@esbuild-win32-arm64-npm-0.17.19-8006d17388-10.zip deleted file mode 100644 index 9061a501006d..000000000000 Binary files a/.yarn/cache/@esbuild-win32-arm64-npm-0.17.19-8006d17388-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-win32-arm64-npm-0.18.20-a58fe6c6a3-10.zip b/.yarn/cache/@esbuild-win32-arm64-npm-0.18.20-a58fe6c6a3-10.zip new file mode 100644 index 000000000000..6a6837498422 Binary files /dev/null and b/.yarn/cache/@esbuild-win32-arm64-npm-0.18.20-a58fe6c6a3-10.zip differ diff --git a/.yarn/cache/@esbuild-win32-arm64-npm-0.23.0-15ef919f07-10.zip b/.yarn/cache/@esbuild-win32-arm64-npm-0.23.0-15ef919f07-10.zip deleted file mode 100644 index 4fd8b0f7f97c..000000000000 Binary files a/.yarn/cache/@esbuild-win32-arm64-npm-0.23.0-15ef919f07-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-win32-arm64-npm-0.23.1-d957320ec4-10.zip b/.yarn/cache/@esbuild-win32-arm64-npm-0.23.1-d957320ec4-10.zip new file mode 100644 index 000000000000..f835a2669df3 Binary files /dev/null and b/.yarn/cache/@esbuild-win32-arm64-npm-0.23.1-d957320ec4-10.zip differ diff --git a/.yarn/cache/@esbuild-win32-x64-npm-0.17.19-619fae7839-10.zip b/.yarn/cache/@esbuild-win32-x64-npm-0.17.19-619fae7839-10.zip deleted file mode 100644 index ae117af73f48..000000000000 Binary files a/.yarn/cache/@esbuild-win32-x64-npm-0.17.19-619fae7839-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-win32-x64-npm-0.18.20-37a9ab2bda-10.zip b/.yarn/cache/@esbuild-win32-x64-npm-0.18.20-37a9ab2bda-10.zip new file mode 100644 index 000000000000..df11d939b0e3 Binary files /dev/null and b/.yarn/cache/@esbuild-win32-x64-npm-0.18.20-37a9ab2bda-10.zip differ diff --git a/.yarn/cache/@esbuild-win32-x64-npm-0.23.0-8cf70e4f2b-10.zip b/.yarn/cache/@esbuild-win32-x64-npm-0.23.0-8cf70e4f2b-10.zip deleted file mode 100644 index 551a610b9406..000000000000 Binary files a/.yarn/cache/@esbuild-win32-x64-npm-0.23.0-8cf70e4f2b-10.zip and /dev/null differ diff --git a/.yarn/cache/@esbuild-win32-x64-npm-0.23.1-41fdbc02b5-10.zip b/.yarn/cache/@esbuild-win32-x64-npm-0.23.1-41fdbc02b5-10.zip new file mode 100644 index 000000000000..0ad03cbb5956 Binary files /dev/null and b/.yarn/cache/@esbuild-win32-x64-npm-0.23.1-41fdbc02b5-10.zip differ diff --git a/.yarn/cache/@eslint-community-regexpp-npm-4.10.1-785b16afd9-54f13817ca.zip b/.yarn/cache/@eslint-community-regexpp-npm-4.10.1-785b16afd9-54f13817ca.zip deleted file mode 100644 index 10a4f8e626b8..000000000000 Binary files a/.yarn/cache/@eslint-community-regexpp-npm-4.10.1-785b16afd9-54f13817ca.zip and /dev/null differ diff --git a/.yarn/cache/@eslint-community-regexpp-npm-4.11.0-dd7ae18a6d-f053f371c2.zip b/.yarn/cache/@eslint-community-regexpp-npm-4.11.0-dd7ae18a6d-f053f371c2.zip new file mode 100644 index 000000000000..39687a8802f4 Binary files /dev/null and b/.yarn/cache/@eslint-community-regexpp-npm-4.11.0-dd7ae18a6d-f053f371c2.zip differ diff --git a/.yarn/cache/@eslint-config-array-npm-0.16.0-3d9e707ee8-6c1716f896.zip b/.yarn/cache/@eslint-config-array-npm-0.16.0-3d9e707ee8-6c1716f896.zip deleted file mode 100644 index fa97e48e5116..000000000000 Binary files a/.yarn/cache/@eslint-config-array-npm-0.16.0-3d9e707ee8-6c1716f896.zip and /dev/null differ diff --git a/.yarn/cache/@eslint-config-array-npm-0.17.1-a6cb4d2ce2-d837852445.zip b/.yarn/cache/@eslint-config-array-npm-0.17.1-a6cb4d2ce2-d837852445.zip new file mode 100644 index 000000000000..c2f142b8be43 Binary files /dev/null and b/.yarn/cache/@eslint-config-array-npm-0.17.1-a6cb4d2ce2-d837852445.zip differ diff --git a/.yarn/cache/@eslint-eslintrc-npm-2.0.3-531b6e79f7-3508a9eb1a.zip b/.yarn/cache/@eslint-eslintrc-npm-2.0.3-531b6e79f7-3508a9eb1a.zip deleted file mode 100644 index 6df8dab83d89..000000000000 Binary files a/.yarn/cache/@eslint-eslintrc-npm-2.0.3-531b6e79f7-3508a9eb1a.zip and /dev/null differ diff --git a/.yarn/cache/@eslint-eslintrc-npm-2.1.4-1ff4b5f908-7a3b14f4b4.zip b/.yarn/cache/@eslint-eslintrc-npm-2.1.4-1ff4b5f908-7a3b14f4b4.zip new file mode 100644 index 000000000000..b00a29818a35 Binary files /dev/null and b/.yarn/cache/@eslint-eslintrc-npm-2.1.4-1ff4b5f908-7a3b14f4b4.zip differ diff --git a/.yarn/cache/@eslint-js-npm-9.5.0-23a7c544a7-206364e3a0.zip b/.yarn/cache/@eslint-js-npm-9.5.0-23a7c544a7-206364e3a0.zip deleted file mode 100644 index 5b3a703ded5b..000000000000 Binary files a/.yarn/cache/@eslint-js-npm-9.5.0-23a7c544a7-206364e3a0.zip and /dev/null differ diff --git a/.yarn/cache/@eslint-js-npm-9.8.0-3434a17242-1c6ddbcc9f.zip b/.yarn/cache/@eslint-js-npm-9.8.0-3434a17242-1c6ddbcc9f.zip new file mode 100644 index 000000000000..81af4bef77ea Binary files /dev/null and b/.yarn/cache/@eslint-js-npm-9.8.0-3434a17242-1c6ddbcc9f.zip differ diff --git a/.yarn/cache/@fastify-busboy-npm-2.0.0-c6baf48382-6a2366d06b.zip b/.yarn/cache/@fastify-busboy-npm-2.0.0-c6baf48382-6a2366d06b.zip deleted file mode 100644 index be0b24488ff8..000000000000 Binary files a/.yarn/cache/@fastify-busboy-npm-2.0.0-c6baf48382-6a2366d06b.zip and /dev/null differ diff --git a/.yarn/cache/@fastify-busboy-npm-2.1.1-455d8b6bf5-2bb8a7eca8.zip b/.yarn/cache/@fastify-busboy-npm-2.1.1-455d8b6bf5-2bb8a7eca8.zip new file mode 100644 index 000000000000..58a33e6186d4 Binary files /dev/null and b/.yarn/cache/@fastify-busboy-npm-2.1.1-455d8b6bf5-2bb8a7eca8.zip differ diff --git a/.yarn/cache/@figma-code-connect-npm-1.0.6-db319a49b3-952cf06f6a.zip b/.yarn/cache/@figma-code-connect-npm-1.0.6-db319a49b3-952cf06f6a.zip deleted file mode 100644 index 7cf41857ddcc..000000000000 Binary files a/.yarn/cache/@figma-code-connect-npm-1.0.6-db319a49b3-952cf06f6a.zip and /dev/null differ diff --git a/.yarn/cache/@figma-code-connect-npm-1.1.3-98aead698b-f6a8eb17e7.zip b/.yarn/cache/@figma-code-connect-npm-1.1.3-98aead698b-f6a8eb17e7.zip new file mode 100644 index 000000000000..ad872941459a Binary files /dev/null and b/.yarn/cache/@figma-code-connect-npm-1.1.3-98aead698b-f6a8eb17e7.zip differ diff --git a/.yarn/cache/@floating-ui-core-npm-1.4.2-81f30e7a48-b0673b9fe5.zip b/.yarn/cache/@floating-ui-core-npm-1.4.2-81f30e7a48-b0673b9fe5.zip deleted file mode 100644 index f80e7a6a5379..000000000000 Binary files a/.yarn/cache/@floating-ui-core-npm-1.4.2-81f30e7a48-b0673b9fe5.zip and /dev/null differ diff --git a/.yarn/cache/@floating-ui-core-npm-1.6.5-49791f3325-946eccfc16.zip b/.yarn/cache/@floating-ui-core-npm-1.6.5-49791f3325-946eccfc16.zip new file mode 100644 index 000000000000..7105e6a72a12 Binary files /dev/null and b/.yarn/cache/@floating-ui-core-npm-1.6.5-49791f3325-946eccfc16.zip differ diff --git a/.yarn/cache/@floating-ui-dom-npm-1.5.3-ac36b589ae-d2d5ae7a09.zip b/.yarn/cache/@floating-ui-dom-npm-1.5.3-ac36b589ae-d2d5ae7a09.zip deleted file mode 100644 index 565f321d15af..000000000000 Binary files a/.yarn/cache/@floating-ui-dom-npm-1.5.3-ac36b589ae-d2d5ae7a09.zip and /dev/null differ diff --git a/.yarn/cache/@floating-ui-dom-npm-1.6.8-ea98a5783a-ebfc92b7a0.zip b/.yarn/cache/@floating-ui-dom-npm-1.6.8-ea98a5783a-ebfc92b7a0.zip new file mode 100644 index 000000000000..a721eb424205 Binary files /dev/null and b/.yarn/cache/@floating-ui-dom-npm-1.6.8-ea98a5783a-ebfc92b7a0.zip differ diff --git a/.yarn/cache/@floating-ui-react-dom-npm-2.0.2-6bf24b7b13-63a26f3c36.zip b/.yarn/cache/@floating-ui-react-dom-npm-2.0.2-6bf24b7b13-63a26f3c36.zip deleted file mode 100644 index 56e45efc51f8..000000000000 Binary files a/.yarn/cache/@floating-ui-react-dom-npm-2.0.2-6bf24b7b13-63a26f3c36.zip and /dev/null differ diff --git a/.yarn/cache/@floating-ui-react-dom-npm-2.1.1-d717a99d8f-cafabfb5dd.zip b/.yarn/cache/@floating-ui-react-dom-npm-2.1.1-d717a99d8f-cafabfb5dd.zip new file mode 100644 index 000000000000..6f2834a708d7 Binary files /dev/null and b/.yarn/cache/@floating-ui-react-dom-npm-2.1.1-d717a99d8f-cafabfb5dd.zip differ diff --git a/.yarn/cache/@floating-ui-react-npm-0.26.11-099643f337-182e65bc0b.zip b/.yarn/cache/@floating-ui-react-npm-0.26.11-099643f337-182e65bc0b.zip deleted file mode 100644 index d346f8e6b916..000000000000 Binary files a/.yarn/cache/@floating-ui-react-npm-0.26.11-099643f337-182e65bc0b.zip and /dev/null differ diff --git a/.yarn/cache/@floating-ui-react-npm-0.26.20-7328f1ae35-daa2122076.zip b/.yarn/cache/@floating-ui-react-npm-0.26.20-7328f1ae35-daa2122076.zip new file mode 100644 index 000000000000..7bfb8cf9b9ae Binary files /dev/null and b/.yarn/cache/@floating-ui-react-npm-0.26.20-7328f1ae35-daa2122076.zip differ diff --git a/.yarn/cache/@floating-ui-utils-npm-0.1.6-ae508f7272-450ec4ecc1.zip b/.yarn/cache/@floating-ui-utils-npm-0.1.6-ae508f7272-450ec4ecc1.zip deleted file mode 100644 index 551ea055d723..000000000000 Binary files a/.yarn/cache/@floating-ui-utils-npm-0.1.6-ae508f7272-450ec4ecc1.zip and /dev/null differ diff --git a/.yarn/cache/@floating-ui-utils-npm-0.2.1-5ad70234fc-33c9ab346e.zip b/.yarn/cache/@floating-ui-utils-npm-0.2.1-5ad70234fc-33c9ab346e.zip deleted file mode 100644 index aa055522c26f..000000000000 Binary files a/.yarn/cache/@floating-ui-utils-npm-0.2.1-5ad70234fc-33c9ab346e.zip and /dev/null differ diff --git a/.yarn/cache/@floating-ui-utils-npm-0.2.5-9de23726fb-08df715c2a.zip b/.yarn/cache/@floating-ui-utils-npm-0.2.5-9de23726fb-08df715c2a.zip new file mode 100644 index 000000000000..eae2cf7b7fec Binary files /dev/null and b/.yarn/cache/@floating-ui-utils-npm-0.2.5-9de23726fb-08df715c2a.zip differ diff --git a/.yarn/cache/@gar-promisify-npm-1.1.3-ac1a325862-052dd23214.zip b/.yarn/cache/@gar-promisify-npm-1.1.3-ac1a325862-052dd23214.zip deleted file mode 100644 index 349462febf33..000000000000 Binary files a/.yarn/cache/@gar-promisify-npm-1.1.3-ac1a325862-052dd23214.zip and /dev/null differ diff --git a/.yarn/cache/@humanwhocodes-config-array-npm-0.11.14-94a02fcc87-3ffb24ecdf.zip b/.yarn/cache/@humanwhocodes-config-array-npm-0.11.14-94a02fcc87-3ffb24ecdf.zip new file mode 100644 index 000000000000..503a1d53aaf1 Binary files /dev/null and b/.yarn/cache/@humanwhocodes-config-array-npm-0.11.14-94a02fcc87-3ffb24ecdf.zip differ diff --git a/.yarn/cache/@humanwhocodes-config-array-npm-0.11.8-7955bfecc2-2ec8619c75.zip b/.yarn/cache/@humanwhocodes-config-array-npm-0.11.8-7955bfecc2-2ec8619c75.zip deleted file mode 100644 index c10e8059436c..000000000000 Binary files a/.yarn/cache/@humanwhocodes-config-array-npm-0.11.8-7955bfecc2-2ec8619c75.zip and /dev/null differ diff --git a/.yarn/cache/@humanwhocodes-object-schema-npm-1.2.1-eb622b5d0e-b48a8f87fc.zip b/.yarn/cache/@humanwhocodes-object-schema-npm-1.2.1-eb622b5d0e-b48a8f87fc.zip deleted file mode 100644 index 434a25416d2c..000000000000 Binary files a/.yarn/cache/@humanwhocodes-object-schema-npm-1.2.1-eb622b5d0e-b48a8f87fc.zip and /dev/null differ diff --git a/.yarn/cache/@humanwhocodes-object-schema-npm-2.0.3-4f0e508cd9-05bb99ed06.zip b/.yarn/cache/@humanwhocodes-object-schema-npm-2.0.3-4f0e508cd9-05bb99ed06.zip new file mode 100644 index 000000000000..52ae4fad0cc8 Binary files /dev/null and b/.yarn/cache/@humanwhocodes-object-schema-npm-2.0.3-4f0e508cd9-05bb99ed06.zip differ diff --git a/.yarn/cache/@ibm-telemetry-js-npm-1.5.0-da3bb2b1b8-063e1e4a49.zip b/.yarn/cache/@ibm-telemetry-js-npm-1.5.0-da3bb2b1b8-063e1e4a49.zip deleted file mode 100644 index 14ec435ccaa8..000000000000 Binary files a/.yarn/cache/@ibm-telemetry-js-npm-1.5.0-da3bb2b1b8-063e1e4a49.zip and /dev/null differ diff --git a/.yarn/cache/@ibm-telemetry-js-npm-1.6.0-4dc5a09584-09132a2c10.zip b/.yarn/cache/@ibm-telemetry-js-npm-1.6.0-4dc5a09584-09132a2c10.zip new file mode 100644 index 000000000000..00d28b0108d9 Binary files /dev/null and b/.yarn/cache/@ibm-telemetry-js-npm-1.6.0-4dc5a09584-09132a2c10.zip differ diff --git a/.yarn/cache/@isaacs-string-locale-compare-npm-1.1.0-3911094464-85682b1460.zip b/.yarn/cache/@isaacs-string-locale-compare-npm-1.1.0-3911094464-85682b1460.zip new file mode 100644 index 000000000000..7c4cec2938e6 Binary files /dev/null and b/.yarn/cache/@isaacs-string-locale-compare-npm-1.1.0-3911094464-85682b1460.zip differ diff --git a/.yarn/cache/@istanbuljs-load-nyc-config-npm-1.0.0-b3fc180ee9-2f5f58b6e9.zip b/.yarn/cache/@istanbuljs-load-nyc-config-npm-1.0.0-b3fc180ee9-2f5f58b6e9.zip deleted file mode 100644 index fd287fc1c097..000000000000 Binary files a/.yarn/cache/@istanbuljs-load-nyc-config-npm-1.0.0-b3fc180ee9-2f5f58b6e9.zip and /dev/null differ diff --git a/.yarn/cache/@istanbuljs-load-nyc-config-npm-1.1.0-42d17c9cb1-b000a5acd8.zip b/.yarn/cache/@istanbuljs-load-nyc-config-npm-1.1.0-42d17c9cb1-b000a5acd8.zip new file mode 100644 index 000000000000..3683321d7f7a Binary files /dev/null and b/.yarn/cache/@istanbuljs-load-nyc-config-npm-1.1.0-42d17c9cb1-b000a5acd8.zip differ diff --git a/.yarn/cache/@jest-console-npm-28.1.0-071bcc4be0-3d3cb5f976.zip b/.yarn/cache/@jest-console-npm-28.1.0-071bcc4be0-3d3cb5f976.zip deleted file mode 100644 index ecdb462fc096..000000000000 Binary files a/.yarn/cache/@jest-console-npm-28.1.0-071bcc4be0-3d3cb5f976.zip and /dev/null differ diff --git a/.yarn/cache/@jest-console-npm-28.1.3-8b24613279-82153eb24e.zip b/.yarn/cache/@jest-console-npm-28.1.3-8b24613279-82153eb24e.zip new file mode 100644 index 000000000000..5138dbd4bf6f Binary files /dev/null and b/.yarn/cache/@jest-console-npm-28.1.3-8b24613279-82153eb24e.zip differ diff --git a/.yarn/cache/@jest-console-npm-29.6.2-4db58c0edb-8a11314aef.zip b/.yarn/cache/@jest-console-npm-29.6.2-4db58c0edb-8a11314aef.zip deleted file mode 100644 index 70c89f801250..000000000000 Binary files a/.yarn/cache/@jest-console-npm-29.6.2-4db58c0edb-8a11314aef.zip and /dev/null differ diff --git a/.yarn/cache/@jest-console-npm-29.7.0-77689f186f-4a80c750e8.zip b/.yarn/cache/@jest-console-npm-29.7.0-77689f186f-4a80c750e8.zip new file mode 100644 index 000000000000..c0a43827cea5 Binary files /dev/null and b/.yarn/cache/@jest-console-npm-29.7.0-77689f186f-4a80c750e8.zip differ diff --git a/.yarn/cache/@jest-core-npm-28.1.0-c79b488e0b-a78c12ffd0.zip b/.yarn/cache/@jest-core-npm-28.1.0-c79b488e0b-a78c12ffd0.zip deleted file mode 100644 index eff59b13f4bc..000000000000 Binary files a/.yarn/cache/@jest-core-npm-28.1.0-c79b488e0b-a78c12ffd0.zip and /dev/null differ diff --git a/.yarn/cache/@jest-core-npm-28.1.3-4b9647f71c-72b56c7591.zip b/.yarn/cache/@jest-core-npm-28.1.3-4b9647f71c-72b56c7591.zip new file mode 100644 index 000000000000..1c75d81ded4b Binary files /dev/null and b/.yarn/cache/@jest-core-npm-28.1.3-4b9647f71c-72b56c7591.zip differ diff --git a/.yarn/cache/@jest-environment-npm-28.1.0-270850375d-0c694d90ab.zip b/.yarn/cache/@jest-environment-npm-28.1.0-270850375d-0c694d90ab.zip deleted file mode 100644 index feb53e5341df..000000000000 Binary files a/.yarn/cache/@jest-environment-npm-28.1.0-270850375d-0c694d90ab.zip and /dev/null differ diff --git a/.yarn/cache/@jest-environment-npm-28.1.3-506a81a227-63a8efd099.zip b/.yarn/cache/@jest-environment-npm-28.1.3-506a81a227-63a8efd099.zip new file mode 100644 index 000000000000..80bd390627ae Binary files /dev/null and b/.yarn/cache/@jest-environment-npm-28.1.3-506a81a227-63a8efd099.zip differ diff --git a/.yarn/cache/@jest-expect-npm-28.1.0-dbd759f9f2-0ed7b7a45b.zip b/.yarn/cache/@jest-expect-npm-28.1.0-dbd759f9f2-0ed7b7a45b.zip deleted file mode 100644 index 84331cd806e5..000000000000 Binary files a/.yarn/cache/@jest-expect-npm-28.1.0-dbd759f9f2-0ed7b7a45b.zip and /dev/null differ diff --git a/.yarn/cache/@jest-expect-npm-28.1.3-3794e8420c-31ea089e83.zip b/.yarn/cache/@jest-expect-npm-28.1.3-3794e8420c-31ea089e83.zip new file mode 100644 index 000000000000..fc79d62f1209 Binary files /dev/null and b/.yarn/cache/@jest-expect-npm-28.1.3-3794e8420c-31ea089e83.zip differ diff --git a/.yarn/cache/@jest-expect-utils-npm-28.1.0-eb29f26291-fa439c4d15.zip b/.yarn/cache/@jest-expect-utils-npm-28.1.0-eb29f26291-fa439c4d15.zip deleted file mode 100644 index 9da470b7fee7..000000000000 Binary files a/.yarn/cache/@jest-expect-utils-npm-28.1.0-eb29f26291-fa439c4d15.zip and /dev/null differ diff --git a/.yarn/cache/@jest-expect-utils-npm-28.1.3-d83dfb8847-f48e4c5b26.zip b/.yarn/cache/@jest-expect-utils-npm-28.1.3-d83dfb8847-f48e4c5b26.zip new file mode 100644 index 000000000000..1db0df05f683 Binary files /dev/null and b/.yarn/cache/@jest-expect-utils-npm-28.1.3-d83dfb8847-f48e4c5b26.zip differ diff --git a/.yarn/cache/@jest-expect-utils-npm-29.7.0-14740cc487-ef8d379778.zip b/.yarn/cache/@jest-expect-utils-npm-29.7.0-14740cc487-ef8d379778.zip new file mode 100644 index 000000000000..ef177749b9d7 Binary files /dev/null and b/.yarn/cache/@jest-expect-utils-npm-29.7.0-14740cc487-ef8d379778.zip differ diff --git a/.yarn/cache/@jest-fake-timers-npm-28.1.0-99fa6230ca-0276cce59a.zip b/.yarn/cache/@jest-fake-timers-npm-28.1.0-99fa6230ca-0276cce59a.zip deleted file mode 100644 index 741e4dc15c53..000000000000 Binary files a/.yarn/cache/@jest-fake-timers-npm-28.1.0-99fa6230ca-0276cce59a.zip and /dev/null differ diff --git a/.yarn/cache/@jest-fake-timers-npm-28.1.3-593b0acb9a-4002208f66.zip b/.yarn/cache/@jest-fake-timers-npm-28.1.3-593b0acb9a-4002208f66.zip new file mode 100644 index 000000000000..4bb1e1fe8bcb Binary files /dev/null and b/.yarn/cache/@jest-fake-timers-npm-28.1.3-593b0acb9a-4002208f66.zip differ diff --git a/.yarn/cache/@jest-globals-npm-28.1.0-6e373647d7-dce822edd1.zip b/.yarn/cache/@jest-globals-npm-28.1.0-6e373647d7-dce822edd1.zip deleted file mode 100644 index e10988e47a61..000000000000 Binary files a/.yarn/cache/@jest-globals-npm-28.1.0-6e373647d7-dce822edd1.zip and /dev/null differ diff --git a/.yarn/cache/@jest-globals-npm-28.1.3-fee1b2ab3f-3504bb23de.zip b/.yarn/cache/@jest-globals-npm-28.1.3-fee1b2ab3f-3504bb23de.zip new file mode 100644 index 000000000000..6cd127f33bba Binary files /dev/null and b/.yarn/cache/@jest-globals-npm-28.1.3-fee1b2ab3f-3504bb23de.zip differ diff --git a/.yarn/cache/@jest-reporters-npm-28.1.0-f78375e65c-7eb2ff019d.zip b/.yarn/cache/@jest-reporters-npm-28.1.0-f78375e65c-7eb2ff019d.zip deleted file mode 100644 index 0739a0f0b09d..000000000000 Binary files a/.yarn/cache/@jest-reporters-npm-28.1.0-f78375e65c-7eb2ff019d.zip and /dev/null differ diff --git a/.yarn/cache/@jest-reporters-npm-28.1.3-548703b241-bdce58bf1c.zip b/.yarn/cache/@jest-reporters-npm-28.1.3-548703b241-bdce58bf1c.zip new file mode 100644 index 000000000000..681f58073ec2 Binary files /dev/null and b/.yarn/cache/@jest-reporters-npm-28.1.3-548703b241-bdce58bf1c.zip differ diff --git a/.yarn/cache/@jest-schemas-npm-28.0.2-482c1c45c3-6a177e97b1.zip b/.yarn/cache/@jest-schemas-npm-28.0.2-482c1c45c3-6a177e97b1.zip deleted file mode 100644 index 6c022e2624e9..000000000000 Binary files a/.yarn/cache/@jest-schemas-npm-28.0.2-482c1c45c3-6a177e97b1.zip and /dev/null differ diff --git a/.yarn/cache/@jest-schemas-npm-28.1.3-231835b296-3cf1d4b66c.zip b/.yarn/cache/@jest-schemas-npm-28.1.3-231835b296-3cf1d4b66c.zip new file mode 100644 index 000000000000..543567200525 Binary files /dev/null and b/.yarn/cache/@jest-schemas-npm-28.1.3-231835b296-3cf1d4b66c.zip differ diff --git a/.yarn/cache/@jest-source-map-npm-28.0.2-f9db611cdd-427195be85.zip b/.yarn/cache/@jest-source-map-npm-28.0.2-f9db611cdd-427195be85.zip deleted file mode 100644 index 7b6b5276729a..000000000000 Binary files a/.yarn/cache/@jest-source-map-npm-28.0.2-f9db611cdd-427195be85.zip and /dev/null differ diff --git a/.yarn/cache/@jest-source-map-npm-28.1.2-c3d608514f-b82a5c2e93.zip b/.yarn/cache/@jest-source-map-npm-28.1.2-c3d608514f-b82a5c2e93.zip new file mode 100644 index 000000000000..991b89e34d56 Binary files /dev/null and b/.yarn/cache/@jest-source-map-npm-28.1.2-c3d608514f-b82a5c2e93.zip differ diff --git a/.yarn/cache/@jest-test-result-npm-28.1.0-8a4006941b-8cdf3e4d42.zip b/.yarn/cache/@jest-test-result-npm-28.1.0-8a4006941b-8cdf3e4d42.zip deleted file mode 100644 index 24946a8f9607..000000000000 Binary files a/.yarn/cache/@jest-test-result-npm-28.1.0-8a4006941b-8cdf3e4d42.zip and /dev/null differ diff --git a/.yarn/cache/@jest-test-result-npm-28.1.3-678ecd0b36-d343f08e6e.zip b/.yarn/cache/@jest-test-result-npm-28.1.3-678ecd0b36-d343f08e6e.zip new file mode 100644 index 000000000000..029b534fea75 Binary files /dev/null and b/.yarn/cache/@jest-test-result-npm-28.1.3-678ecd0b36-d343f08e6e.zip differ diff --git a/.yarn/cache/@jest-test-result-npm-29.6.2-066177b4eb-68e9f639c7.zip b/.yarn/cache/@jest-test-result-npm-29.6.2-066177b4eb-68e9f639c7.zip deleted file mode 100644 index 308bc86f635e..000000000000 Binary files a/.yarn/cache/@jest-test-result-npm-29.6.2-066177b4eb-68e9f639c7.zip and /dev/null differ diff --git a/.yarn/cache/@jest-test-result-npm-29.7.0-4bb532101b-c073ab7dfe.zip b/.yarn/cache/@jest-test-result-npm-29.7.0-4bb532101b-c073ab7dfe.zip new file mode 100644 index 000000000000..ffaeeba3f173 Binary files /dev/null and b/.yarn/cache/@jest-test-result-npm-29.7.0-4bb532101b-c073ab7dfe.zip differ diff --git a/.yarn/cache/@jest-test-sequencer-npm-28.1.0-7d6ec498c0-22371aea24.zip b/.yarn/cache/@jest-test-sequencer-npm-28.1.0-7d6ec498c0-22371aea24.zip deleted file mode 100644 index 694714729447..000000000000 Binary files a/.yarn/cache/@jest-test-sequencer-npm-28.1.0-7d6ec498c0-22371aea24.zip and /dev/null differ diff --git a/.yarn/cache/@jest-test-sequencer-npm-28.1.3-456bc6e2ff-a2f05475c3.zip b/.yarn/cache/@jest-test-sequencer-npm-28.1.3-456bc6e2ff-a2f05475c3.zip new file mode 100644 index 000000000000..b89adef2baf2 Binary files /dev/null and b/.yarn/cache/@jest-test-sequencer-npm-28.1.3-456bc6e2ff-a2f05475c3.zip differ diff --git a/.yarn/cache/@jest-transform-npm-28.1.0-861eb81744-915e882641.zip b/.yarn/cache/@jest-transform-npm-28.1.0-861eb81744-915e882641.zip deleted file mode 100644 index 0ed7368e3137..000000000000 Binary files a/.yarn/cache/@jest-transform-npm-28.1.0-861eb81744-915e882641.zip and /dev/null differ diff --git a/.yarn/cache/@jest-transform-npm-28.1.3-c63694eb02-89bc17ca22.zip b/.yarn/cache/@jest-transform-npm-28.1.3-c63694eb02-89bc17ca22.zip new file mode 100644 index 000000000000..75e792efd2e3 Binary files /dev/null and b/.yarn/cache/@jest-transform-npm-28.1.3-c63694eb02-89bc17ca22.zip differ diff --git a/.yarn/cache/@jest-types-npm-28.1.0-a5f31b5c52-34f75a3f45.zip b/.yarn/cache/@jest-types-npm-28.1.0-a5f31b5c52-34f75a3f45.zip deleted file mode 100644 index b34c36a3282f..000000000000 Binary files a/.yarn/cache/@jest-types-npm-28.1.0-a5f31b5c52-34f75a3f45.zip and /dev/null differ diff --git a/.yarn/cache/@jest-types-npm-28.1.3-422ad1bd71-a90e636df7.zip b/.yarn/cache/@jest-types-npm-28.1.3-422ad1bd71-a90e636df7.zip new file mode 100644 index 000000000000..388ac2ee20da Binary files /dev/null and b/.yarn/cache/@jest-types-npm-28.1.3-422ad1bd71-a90e636df7.zip differ diff --git a/.yarn/cache/@jest-types-npm-29.6.1-b7c765fadd-f6264fb0fc.zip b/.yarn/cache/@jest-types-npm-29.6.1-b7c765fadd-f6264fb0fc.zip deleted file mode 100644 index bf442954c885..000000000000 Binary files a/.yarn/cache/@jest-types-npm-29.6.1-b7c765fadd-f6264fb0fc.zip and /dev/null differ diff --git a/.yarn/cache/@jest-types-npm-29.6.3-a584ca999d-f74bf512fd.zip b/.yarn/cache/@jest-types-npm-29.6.3-a584ca999d-f74bf512fd.zip new file mode 100644 index 000000000000..2ac5bed3c651 Binary files /dev/null and b/.yarn/cache/@jest-types-npm-29.6.3-a584ca999d-f74bf512fd.zip differ diff --git a/.yarn/cache/@jsonjoy.com-json-pack-npm-1.0.4-52a7eae8bc-dd749e7c46.zip b/.yarn/cache/@jsonjoy.com-json-pack-npm-1.0.4-52a7eae8bc-dd749e7c46.zip new file mode 100644 index 000000000000..56db386f3588 Binary files /dev/null and b/.yarn/cache/@jsonjoy.com-json-pack-npm-1.0.4-52a7eae8bc-dd749e7c46.zip differ diff --git a/.yarn/cache/@jsonjoy.com-json-pack-npm-1.1.0-14d39591c6-cd2776085a.zip b/.yarn/cache/@jsonjoy.com-json-pack-npm-1.1.0-14d39591c6-cd2776085a.zip deleted file mode 100644 index f26bb55f5010..000000000000 Binary files a/.yarn/cache/@jsonjoy.com-json-pack-npm-1.1.0-14d39591c6-cd2776085a.zip and /dev/null differ diff --git a/.yarn/cache/@lerna-create-npm-8.0.0-350095aba5-047f966705.zip b/.yarn/cache/@lerna-create-npm-8.0.0-350095aba5-047f966705.zip deleted file mode 100644 index d577d66c314f..000000000000 Binary files a/.yarn/cache/@lerna-create-npm-8.0.0-350095aba5-047f966705.zip and /dev/null differ diff --git a/.yarn/cache/@lerna-create-npm-8.1.7-cfa1c0c10c-81e6054f39.zip b/.yarn/cache/@lerna-create-npm-8.1.7-cfa1c0c10c-81e6054f39.zip new file mode 100644 index 000000000000..b35e3efc09eb Binary files /dev/null and b/.yarn/cache/@lerna-create-npm-8.1.7-cfa1c0c10c-81e6054f39.zip differ diff --git a/.yarn/cache/@lit-labs-ssr-dom-shim-npm-1.2.0-6bda8c35cb-33679defe0.zip b/.yarn/cache/@lit-labs-ssr-dom-shim-npm-1.2.0-6bda8c35cb-33679defe0.zip new file mode 100644 index 000000000000..fc4afe019d0f Binary files /dev/null and b/.yarn/cache/@lit-labs-ssr-dom-shim-npm-1.2.0-6bda8c35cb-33679defe0.zip differ diff --git a/.yarn/cache/@lit-reactive-element-npm-2.0.4-4836436301-16aa5a8d91.zip b/.yarn/cache/@lit-reactive-element-npm-2.0.4-4836436301-16aa5a8d91.zip new file mode 100644 index 000000000000..e921bebb5645 Binary files /dev/null and b/.yarn/cache/@lit-reactive-element-npm-2.0.4-4836436301-16aa5a8d91.zip differ diff --git a/.yarn/cache/@mordech-vite-lit-loader-npm-0.31.3-b75ba0b159-a83c0b5e22.zip b/.yarn/cache/@mordech-vite-lit-loader-npm-0.31.3-b75ba0b159-a83c0b5e22.zip new file mode 100644 index 000000000000..2213817ec07e Binary files /dev/null and b/.yarn/cache/@mordech-vite-lit-loader-npm-0.31.3-b75ba0b159-a83c0b5e22.zip differ diff --git a/.yarn/cache/@napi-rs-wasm-runtime-npm-0.2.4-bc75480c68-af335867ec.zip b/.yarn/cache/@napi-rs-wasm-runtime-npm-0.2.4-bc75480c68-af335867ec.zip new file mode 100644 index 000000000000..13749f70e7d3 Binary files /dev/null and b/.yarn/cache/@napi-rs-wasm-runtime-npm-0.2.4-bc75480c68-af335867ec.zip differ diff --git a/.yarn/cache/@next-env-npm-14.2.5-49076f5af2-0462db6a82.zip b/.yarn/cache/@next-env-npm-14.2.5-49076f5af2-0462db6a82.zip new file mode 100644 index 000000000000..05a230c0c62e Binary files /dev/null and b/.yarn/cache/@next-env-npm-14.2.5-49076f5af2-0462db6a82.zip differ diff --git a/.yarn/cache/@next-swc-darwin-arm64-npm-14.2.5-30baab3764-10.zip b/.yarn/cache/@next-swc-darwin-arm64-npm-14.2.5-30baab3764-10.zip new file mode 100644 index 000000000000..1e2aeb83ced3 Binary files /dev/null and b/.yarn/cache/@next-swc-darwin-arm64-npm-14.2.5-30baab3764-10.zip differ diff --git a/.yarn/cache/@next-swc-darwin-x64-npm-14.2.5-01db35822e-10.zip b/.yarn/cache/@next-swc-darwin-x64-npm-14.2.5-01db35822e-10.zip new file mode 100644 index 000000000000..8aaaf8113964 Binary files /dev/null and b/.yarn/cache/@next-swc-darwin-x64-npm-14.2.5-01db35822e-10.zip differ diff --git a/.yarn/cache/@next-swc-linux-arm64-gnu-npm-14.2.5-c0be37ef87-10.zip b/.yarn/cache/@next-swc-linux-arm64-gnu-npm-14.2.5-c0be37ef87-10.zip new file mode 100644 index 000000000000..706d499bc331 Binary files /dev/null and b/.yarn/cache/@next-swc-linux-arm64-gnu-npm-14.2.5-c0be37ef87-10.zip differ diff --git a/.yarn/cache/@next-swc-linux-x64-gnu-npm-14.2.5-cc62fe9948-10.zip b/.yarn/cache/@next-swc-linux-x64-gnu-npm-14.2.5-cc62fe9948-10.zip new file mode 100644 index 000000000000..b550578c1fb8 Binary files /dev/null and b/.yarn/cache/@next-swc-linux-x64-gnu-npm-14.2.5-cc62fe9948-10.zip differ diff --git a/.yarn/cache/@next-swc-win32-arm64-msvc-npm-14.2.5-28a30fb16b-10.zip b/.yarn/cache/@next-swc-win32-arm64-msvc-npm-14.2.5-28a30fb16b-10.zip new file mode 100644 index 000000000000..c0a2a23998d5 Binary files /dev/null and b/.yarn/cache/@next-swc-win32-arm64-msvc-npm-14.2.5-28a30fb16b-10.zip differ diff --git a/.yarn/cache/@next-swc-win32-x64-msvc-npm-14.2.5-fd8931986f-10.zip b/.yarn/cache/@next-swc-win32-x64-msvc-npm-14.2.5-fd8931986f-10.zip new file mode 100644 index 000000000000..f95ac8d99573 Binary files /dev/null and b/.yarn/cache/@next-swc-win32-x64-msvc-npm-14.2.5-fd8931986f-10.zip differ diff --git a/.yarn/cache/@nolyfill-is-core-module-npm-1.0.39-9ff248572b-0d6e098b87.zip b/.yarn/cache/@nolyfill-is-core-module-npm-1.0.39-9ff248572b-0d6e098b87.zip new file mode 100644 index 000000000000..ce9a50d79de2 Binary files /dev/null and b/.yarn/cache/@nolyfill-is-core-module-npm-1.0.39-9ff248572b-0d6e098b87.zip differ diff --git a/.yarn/cache/@npmcli-agent-npm-2.2.2-e2f559d6c0-96fc0036b1.zip b/.yarn/cache/@npmcli-agent-npm-2.2.2-e2f559d6c0-96fc0036b1.zip new file mode 100644 index 000000000000..ce626b4aad3c Binary files /dev/null and b/.yarn/cache/@npmcli-agent-npm-2.2.2-e2f559d6c0-96fc0036b1.zip differ diff --git a/.yarn/cache/@npmcli-arborist-npm-7.5.3-074a013bcc-e149df712a.zip b/.yarn/cache/@npmcli-arborist-npm-7.5.3-074a013bcc-e149df712a.zip new file mode 100644 index 000000000000..63148dc5997a Binary files /dev/null and b/.yarn/cache/@npmcli-arborist-npm-7.5.3-074a013bcc-e149df712a.zip differ diff --git a/.yarn/cache/@npmcli-fs-npm-2.1.2-08d434e77b-c5d4dfee80.zip b/.yarn/cache/@npmcli-fs-npm-2.1.2-08d434e77b-c5d4dfee80.zip deleted file mode 100644 index 72ef3ec35967..000000000000 Binary files a/.yarn/cache/@npmcli-fs-npm-2.1.2-08d434e77b-c5d4dfee80.zip and /dev/null differ diff --git a/.yarn/cache/@npmcli-fs-npm-3.1.0-0844a57978-f3a7ab3a31.zip b/.yarn/cache/@npmcli-fs-npm-3.1.0-0844a57978-f3a7ab3a31.zip deleted file mode 100644 index 79245108f2cf..000000000000 Binary files a/.yarn/cache/@npmcli-fs-npm-3.1.0-0844a57978-f3a7ab3a31.zip and /dev/null differ diff --git a/.yarn/cache/@npmcli-fs-npm-3.1.1-c19bd09f3c-1e0e040870.zip b/.yarn/cache/@npmcli-fs-npm-3.1.1-c19bd09f3c-1e0e040870.zip new file mode 100644 index 000000000000..107e37bbe666 Binary files /dev/null and b/.yarn/cache/@npmcli-fs-npm-3.1.1-c19bd09f3c-1e0e040870.zip differ diff --git a/.yarn/cache/@npmcli-git-npm-4.1.0-f7322fced9-33512ce127.zip b/.yarn/cache/@npmcli-git-npm-4.1.0-f7322fced9-33512ce127.zip deleted file mode 100644 index 6c05c2a11d54..000000000000 Binary files a/.yarn/cache/@npmcli-git-npm-4.1.0-f7322fced9-33512ce127.zip and /dev/null differ diff --git a/.yarn/cache/@npmcli-git-npm-5.0.8-f327e06825-e6f94175fb.zip b/.yarn/cache/@npmcli-git-npm-5.0.8-f327e06825-e6f94175fb.zip new file mode 100644 index 000000000000..f088d964c65d Binary files /dev/null and b/.yarn/cache/@npmcli-git-npm-5.0.8-f327e06825-e6f94175fb.zip differ diff --git a/.yarn/cache/@npmcli-installed-package-contents-npm-2.0.2-99564e3824-4598a97e3d.zip b/.yarn/cache/@npmcli-installed-package-contents-npm-2.0.2-99564e3824-4598a97e3d.zip deleted file mode 100644 index 8503e33f0507..000000000000 Binary files a/.yarn/cache/@npmcli-installed-package-contents-npm-2.0.2-99564e3824-4598a97e3d.zip and /dev/null differ diff --git a/.yarn/cache/@npmcli-installed-package-contents-npm-2.1.0-82f7020627-68ab3ea299.zip b/.yarn/cache/@npmcli-installed-package-contents-npm-2.1.0-82f7020627-68ab3ea299.zip new file mode 100644 index 000000000000..9a1cd30d4c7a Binary files /dev/null and b/.yarn/cache/@npmcli-installed-package-contents-npm-2.1.0-82f7020627-68ab3ea299.zip differ diff --git a/.yarn/cache/@npmcli-map-workspaces-npm-3.0.6-dcaa328de8-b364b15599.zip b/.yarn/cache/@npmcli-map-workspaces-npm-3.0.6-dcaa328de8-b364b15599.zip new file mode 100644 index 000000000000..85ae72e23afd Binary files /dev/null and b/.yarn/cache/@npmcli-map-workspaces-npm-3.0.6-dcaa328de8-b364b15599.zip differ diff --git a/.yarn/cache/@npmcli-metavuln-calculator-npm-7.1.1-392e62877e-57163b4bde.zip b/.yarn/cache/@npmcli-metavuln-calculator-npm-7.1.1-392e62877e-57163b4bde.zip new file mode 100644 index 000000000000..5f8cff419449 Binary files /dev/null and b/.yarn/cache/@npmcli-metavuln-calculator-npm-7.1.1-392e62877e-57163b4bde.zip differ diff --git a/.yarn/cache/@npmcli-move-file-npm-2.0.1-b593d8f741-52dc02259d.zip b/.yarn/cache/@npmcli-move-file-npm-2.0.1-b593d8f741-52dc02259d.zip deleted file mode 100644 index f6a649e34f82..000000000000 Binary files a/.yarn/cache/@npmcli-move-file-npm-2.0.1-b593d8f741-52dc02259d.zip and /dev/null differ diff --git a/.yarn/cache/@npmcli-name-from-folder-npm-2.0.0-18e2dba870-75beb40373.zip b/.yarn/cache/@npmcli-name-from-folder-npm-2.0.0-18e2dba870-75beb40373.zip new file mode 100644 index 000000000000..348c5b0ffa06 Binary files /dev/null and b/.yarn/cache/@npmcli-name-from-folder-npm-2.0.0-18e2dba870-75beb40373.zip differ diff --git a/.yarn/cache/@npmcli-package-json-npm-5.2.0-6ff383122c-c3d2218877.zip b/.yarn/cache/@npmcli-package-json-npm-5.2.0-6ff383122c-c3d2218877.zip new file mode 100644 index 000000000000..28f22ef2dfc0 Binary files /dev/null and b/.yarn/cache/@npmcli-package-json-npm-5.2.0-6ff383122c-c3d2218877.zip differ diff --git a/.yarn/cache/@npmcli-promise-spawn-npm-6.0.2-c9941b207c-cc94a83ff1.zip b/.yarn/cache/@npmcli-promise-spawn-npm-6.0.2-c9941b207c-cc94a83ff1.zip deleted file mode 100644 index 6164b8adc70d..000000000000 Binary files a/.yarn/cache/@npmcli-promise-spawn-npm-6.0.2-c9941b207c-cc94a83ff1.zip and /dev/null differ diff --git a/.yarn/cache/@npmcli-promise-spawn-npm-7.0.2-643915b5c0-94cbbbeeb2.zip b/.yarn/cache/@npmcli-promise-spawn-npm-7.0.2-643915b5c0-94cbbbeeb2.zip new file mode 100644 index 000000000000..7f0438f0c434 Binary files /dev/null and b/.yarn/cache/@npmcli-promise-spawn-npm-7.0.2-643915b5c0-94cbbbeeb2.zip differ diff --git a/.yarn/cache/@npmcli-query-npm-3.1.0-88f6486c5b-fa79ae3179.zip b/.yarn/cache/@npmcli-query-npm-3.1.0-88f6486c5b-fa79ae3179.zip new file mode 100644 index 000000000000..5bcc68125531 Binary files /dev/null and b/.yarn/cache/@npmcli-query-npm-3.1.0-88f6486c5b-fa79ae3179.zip differ diff --git a/.yarn/cache/@npmcli-redact-npm-2.0.1-aabc2eefef-f19a521fa7.zip b/.yarn/cache/@npmcli-redact-npm-2.0.1-aabc2eefef-f19a521fa7.zip new file mode 100644 index 000000000000..e7f4cc1df1ff Binary files /dev/null and b/.yarn/cache/@npmcli-redact-npm-2.0.1-aabc2eefef-f19a521fa7.zip differ diff --git a/.yarn/cache/@npmcli-run-script-npm-6.0.2-6a98dec431-9b22c4c53d.zip b/.yarn/cache/@npmcli-run-script-npm-6.0.2-6a98dec431-9b22c4c53d.zip deleted file mode 100644 index 6b6acfe1ca15..000000000000 Binary files a/.yarn/cache/@npmcli-run-script-npm-6.0.2-6a98dec431-9b22c4c53d.zip and /dev/null differ diff --git a/.yarn/cache/@npmcli-run-script-npm-8.1.0-e82d9acd40-256bd580f8.zip b/.yarn/cache/@npmcli-run-script-npm-8.1.0-e82d9acd40-256bd580f8.zip new file mode 100644 index 000000000000..19e678265d47 Binary files /dev/null and b/.yarn/cache/@npmcli-run-script-npm-8.1.0-e82d9acd40-256bd580f8.zip differ diff --git a/.yarn/cache/@nrwl-devkit-npm-17.1.3-39974a32d4-a70d95b980.zip b/.yarn/cache/@nrwl-devkit-npm-17.1.3-39974a32d4-a70d95b980.zip deleted file mode 100644 index 8f3abdefc260..000000000000 Binary files a/.yarn/cache/@nrwl-devkit-npm-17.1.3-39974a32d4-a70d95b980.zip and /dev/null differ diff --git a/.yarn/cache/@nrwl-devkit-npm-19.5.3-6720587cd9-ac32e2d4f3.zip b/.yarn/cache/@nrwl-devkit-npm-19.5.3-6720587cd9-ac32e2d4f3.zip new file mode 100644 index 000000000000..9e48e4b354ad Binary files /dev/null and b/.yarn/cache/@nrwl-devkit-npm-19.5.3-6720587cd9-ac32e2d4f3.zip differ diff --git a/.yarn/cache/@nrwl-tao-npm-17.1.3-0911d20225-2f51db66bb.zip b/.yarn/cache/@nrwl-tao-npm-17.1.3-0911d20225-2f51db66bb.zip deleted file mode 100644 index 36c5c45a7fb2..000000000000 Binary files a/.yarn/cache/@nrwl-tao-npm-17.1.3-0911d20225-2f51db66bb.zip and /dev/null differ diff --git a/.yarn/cache/@nrwl-tao-npm-19.5.3-e167ba7143-669405a362.zip b/.yarn/cache/@nrwl-tao-npm-19.5.3-e167ba7143-669405a362.zip new file mode 100644 index 000000000000..009667da1954 Binary files /dev/null and b/.yarn/cache/@nrwl-tao-npm-19.5.3-e167ba7143-669405a362.zip differ diff --git a/.yarn/cache/@nx-devkit-npm-17.1.3-67d2a6f11e-77363232e0.zip b/.yarn/cache/@nx-devkit-npm-17.1.3-67d2a6f11e-77363232e0.zip deleted file mode 100644 index 1fea6851d0bb..000000000000 Binary files a/.yarn/cache/@nx-devkit-npm-17.1.3-67d2a6f11e-77363232e0.zip and /dev/null differ diff --git a/.yarn/cache/@nx-devkit-npm-19.5.3-46aab62e21-f1aa574713.zip b/.yarn/cache/@nx-devkit-npm-19.5.3-46aab62e21-f1aa574713.zip new file mode 100644 index 000000000000..a07b830088c7 Binary files /dev/null and b/.yarn/cache/@nx-devkit-npm-19.5.3-46aab62e21-f1aa574713.zip differ diff --git a/.yarn/cache/@nx-nx-darwin-arm64-npm-17.1.3-970ddd1445-10.zip b/.yarn/cache/@nx-nx-darwin-arm64-npm-17.1.3-970ddd1445-10.zip deleted file mode 100644 index cfea596a786d..000000000000 Binary files a/.yarn/cache/@nx-nx-darwin-arm64-npm-17.1.3-970ddd1445-10.zip and /dev/null differ diff --git a/.yarn/cache/@nx-nx-darwin-arm64-npm-19.5.3-1f6fff9001-10.zip b/.yarn/cache/@nx-nx-darwin-arm64-npm-19.5.3-1f6fff9001-10.zip new file mode 100644 index 000000000000..06eb7ec7c916 Binary files /dev/null and b/.yarn/cache/@nx-nx-darwin-arm64-npm-19.5.3-1f6fff9001-10.zip differ diff --git a/.yarn/cache/@nx-nx-darwin-x64-npm-17.1.3-5eacc66132-10.zip b/.yarn/cache/@nx-nx-darwin-x64-npm-17.1.3-5eacc66132-10.zip deleted file mode 100644 index 2ca646aa4e74..000000000000 Binary files a/.yarn/cache/@nx-nx-darwin-x64-npm-17.1.3-5eacc66132-10.zip and /dev/null differ diff --git a/.yarn/cache/@nx-nx-darwin-x64-npm-19.5.3-b826de7ef6-10.zip b/.yarn/cache/@nx-nx-darwin-x64-npm-19.5.3-b826de7ef6-10.zip new file mode 100644 index 000000000000..cbb1a2c1a512 Binary files /dev/null and b/.yarn/cache/@nx-nx-darwin-x64-npm-19.5.3-b826de7ef6-10.zip differ diff --git a/.yarn/cache/@nx-nx-linux-arm64-gnu-npm-17.1.3-78fca323a7-10.zip b/.yarn/cache/@nx-nx-linux-arm64-gnu-npm-17.1.3-78fca323a7-10.zip deleted file mode 100644 index f4310f4a7942..000000000000 Binary files a/.yarn/cache/@nx-nx-linux-arm64-gnu-npm-17.1.3-78fca323a7-10.zip and /dev/null differ diff --git a/.yarn/cache/@nx-nx-linux-arm64-gnu-npm-19.5.3-b54834ed9d-10.zip b/.yarn/cache/@nx-nx-linux-arm64-gnu-npm-19.5.3-b54834ed9d-10.zip new file mode 100644 index 000000000000..2d36e940a8b5 Binary files /dev/null and b/.yarn/cache/@nx-nx-linux-arm64-gnu-npm-19.5.3-b54834ed9d-10.zip differ diff --git a/.yarn/cache/@nx-nx-linux-x64-gnu-npm-17.1.3-3fb051827e-10.zip b/.yarn/cache/@nx-nx-linux-x64-gnu-npm-17.1.3-3fb051827e-10.zip deleted file mode 100644 index 8985b62f6c7b..000000000000 Binary files a/.yarn/cache/@nx-nx-linux-x64-gnu-npm-17.1.3-3fb051827e-10.zip and /dev/null differ diff --git a/.yarn/cache/@nx-nx-linux-x64-gnu-npm-19.5.3-3cb61d63f8-10.zip b/.yarn/cache/@nx-nx-linux-x64-gnu-npm-19.5.3-3cb61d63f8-10.zip new file mode 100644 index 000000000000..a4ee76408b99 Binary files /dev/null and b/.yarn/cache/@nx-nx-linux-x64-gnu-npm-19.5.3-3cb61d63f8-10.zip differ diff --git a/.yarn/cache/@nx-nx-win32-arm64-msvc-npm-17.1.3-a761f7e1b9-10.zip b/.yarn/cache/@nx-nx-win32-arm64-msvc-npm-17.1.3-a761f7e1b9-10.zip deleted file mode 100644 index 63257570f283..000000000000 Binary files a/.yarn/cache/@nx-nx-win32-arm64-msvc-npm-17.1.3-a761f7e1b9-10.zip and /dev/null differ diff --git a/.yarn/cache/@nx-nx-win32-arm64-msvc-npm-19.5.3-dfd4761174-10.zip b/.yarn/cache/@nx-nx-win32-arm64-msvc-npm-19.5.3-dfd4761174-10.zip new file mode 100644 index 000000000000..405b0b242e7c Binary files /dev/null and b/.yarn/cache/@nx-nx-win32-arm64-msvc-npm-19.5.3-dfd4761174-10.zip differ diff --git a/.yarn/cache/@nx-nx-win32-x64-msvc-npm-17.1.3-307bde7704-10.zip b/.yarn/cache/@nx-nx-win32-x64-msvc-npm-17.1.3-307bde7704-10.zip deleted file mode 100644 index 72369e770d5e..000000000000 Binary files a/.yarn/cache/@nx-nx-win32-x64-msvc-npm-17.1.3-307bde7704-10.zip and /dev/null differ diff --git a/.yarn/cache/@nx-nx-win32-x64-msvc-npm-19.5.3-4304b78ca1-10.zip b/.yarn/cache/@nx-nx-win32-x64-msvc-npm-19.5.3-4304b78ca1-10.zip new file mode 100644 index 000000000000..6a6eee8e9515 Binary files /dev/null and b/.yarn/cache/@nx-nx-win32-x64-msvc-npm-19.5.3-4304b78ca1-10.zip differ diff --git a/.yarn/cache/@octokit-auth-action-npm-2.0.2-853b9a3fba-0b55635ea2.zip b/.yarn/cache/@octokit-auth-action-npm-2.0.2-853b9a3fba-0b55635ea2.zip deleted file mode 100644 index 55f54827616b..000000000000 Binary files a/.yarn/cache/@octokit-auth-action-npm-2.0.2-853b9a3fba-0b55635ea2.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-auth-action-npm-2.1.1-76846322ea-2192cfad98.zip b/.yarn/cache/@octokit-auth-action-npm-2.1.1-76846322ea-2192cfad98.zip new file mode 100644 index 000000000000..10acd20339f7 Binary files /dev/null and b/.yarn/cache/@octokit-auth-action-npm-2.1.1-76846322ea-2192cfad98.zip differ diff --git a/.yarn/cache/@octokit-auth-token-npm-3.0.0-a49dbe877e-cd6d3b0039.zip b/.yarn/cache/@octokit-auth-token-npm-3.0.0-a49dbe877e-cd6d3b0039.zip deleted file mode 100644 index 60c215d92875..000000000000 Binary files a/.yarn/cache/@octokit-auth-token-npm-3.0.0-a49dbe877e-cd6d3b0039.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-auth-token-npm-3.0.4-2b669244cb-8e21e567e3.zip b/.yarn/cache/@octokit-auth-token-npm-3.0.4-2b669244cb-8e21e567e3.zip new file mode 100644 index 000000000000..95af6565a1bf Binary files /dev/null and b/.yarn/cache/@octokit-auth-token-npm-3.0.4-2b669244cb-8e21e567e3.zip differ diff --git a/.yarn/cache/@octokit-core-npm-4.2.1-ed461a1d34-028045edeb.zip b/.yarn/cache/@octokit-core-npm-4.2.1-ed461a1d34-028045edeb.zip deleted file mode 100644 index d3e114de1fd5..000000000000 Binary files a/.yarn/cache/@octokit-core-npm-4.2.1-ed461a1d34-028045edeb.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-core-npm-4.2.4-25aeed316b-53ba8f990c.zip b/.yarn/cache/@octokit-core-npm-4.2.4-25aeed316b-53ba8f990c.zip new file mode 100644 index 000000000000..e10e17dbf21a Binary files /dev/null and b/.yarn/cache/@octokit-core-npm-4.2.4-25aeed316b-53ba8f990c.zip differ diff --git a/.yarn/cache/@octokit-core-npm-5.0.1-58208565b9-e0f6398e59.zip b/.yarn/cache/@octokit-core-npm-5.0.1-58208565b9-e0f6398e59.zip deleted file mode 100644 index b67bed2e5262..000000000000 Binary files a/.yarn/cache/@octokit-core-npm-5.0.1-58208565b9-e0f6398e59.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-core-npm-5.2.0-d30dcc079c-2e40baf0b5.zip b/.yarn/cache/@octokit-core-npm-5.2.0-d30dcc079c-2e40baf0b5.zip new file mode 100644 index 000000000000..d7083ca56f4c Binary files /dev/null and b/.yarn/cache/@octokit-core-npm-5.2.0-d30dcc079c-2e40baf0b5.zip differ diff --git a/.yarn/cache/@octokit-endpoint-npm-7.0.0-db1160698c-ec433d3ac7.zip b/.yarn/cache/@octokit-endpoint-npm-7.0.0-db1160698c-ec433d3ac7.zip deleted file mode 100644 index 72bd007846fb..000000000000 Binary files a/.yarn/cache/@octokit-endpoint-npm-7.0.0-db1160698c-ec433d3ac7.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-endpoint-npm-7.0.6-ff8dba936f-e8b9cc09aa.zip b/.yarn/cache/@octokit-endpoint-npm-7.0.6-ff8dba936f-e8b9cc09aa.zip new file mode 100644 index 000000000000..6dea76ea387e Binary files /dev/null and b/.yarn/cache/@octokit-endpoint-npm-7.0.6-ff8dba936f-e8b9cc09aa.zip differ diff --git a/.yarn/cache/@octokit-endpoint-npm-9.0.1-19bac4870b-8d1e6540ca.zip b/.yarn/cache/@octokit-endpoint-npm-9.0.1-19bac4870b-8d1e6540ca.zip deleted file mode 100644 index 552669df35b0..000000000000 Binary files a/.yarn/cache/@octokit-endpoint-npm-9.0.1-19bac4870b-8d1e6540ca.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-endpoint-npm-9.0.5-9f96e75a5d-212122f653.zip b/.yarn/cache/@octokit-endpoint-npm-9.0.5-9f96e75a5d-212122f653.zip new file mode 100644 index 000000000000..30215efcdb2c Binary files /dev/null and b/.yarn/cache/@octokit-endpoint-npm-9.0.5-9f96e75a5d-212122f653.zip differ diff --git a/.yarn/cache/@octokit-graphql-npm-5.0.0-316da27aea-d492d0ac55.zip b/.yarn/cache/@octokit-graphql-npm-5.0.0-316da27aea-d492d0ac55.zip deleted file mode 100644 index 0a6926398ca9..000000000000 Binary files a/.yarn/cache/@octokit-graphql-npm-5.0.0-316da27aea-d492d0ac55.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-graphql-npm-5.0.6-26fb5b6074-6014690d18.zip b/.yarn/cache/@octokit-graphql-npm-5.0.6-26fb5b6074-6014690d18.zip new file mode 100644 index 000000000000..733513e1ef89 Binary files /dev/null and b/.yarn/cache/@octokit-graphql-npm-5.0.6-26fb5b6074-6014690d18.zip differ diff --git a/.yarn/cache/@octokit-graphql-npm-7.0.2-b5522f5b29-f5dcc51fed.zip b/.yarn/cache/@octokit-graphql-npm-7.0.2-b5522f5b29-f5dcc51fed.zip deleted file mode 100644 index e39733f93a7a..000000000000 Binary files a/.yarn/cache/@octokit-graphql-npm-7.0.2-b5522f5b29-f5dcc51fed.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-graphql-npm-7.1.0-9956e50359-da6857a69d.zip b/.yarn/cache/@octokit-graphql-npm-7.1.0-9956e50359-da6857a69d.zip new file mode 100644 index 000000000000..84a6f9562a75 Binary files /dev/null and b/.yarn/cache/@octokit-graphql-npm-7.1.0-9956e50359-da6857a69d.zip differ diff --git a/.yarn/cache/@octokit-openapi-types-npm-13.13.1-6b9bdd4c9f-6dcfd1fbcc.zip b/.yarn/cache/@octokit-openapi-types-npm-13.13.1-6b9bdd4c9f-6dcfd1fbcc.zip deleted file mode 100644 index be8b6a492419..000000000000 Binary files a/.yarn/cache/@octokit-openapi-types-npm-13.13.1-6b9bdd4c9f-6dcfd1fbcc.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-openapi-types-npm-18.0.0-1586e405d6-5d4aa6abab.zip b/.yarn/cache/@octokit-openapi-types-npm-18.0.0-1586e405d6-5d4aa6abab.zip deleted file mode 100644 index adf5bda9df0e..000000000000 Binary files a/.yarn/cache/@octokit-openapi-types-npm-18.0.0-1586e405d6-5d4aa6abab.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-openapi-types-npm-18.1.1-18b6c70735-bd2920a238.zip b/.yarn/cache/@octokit-openapi-types-npm-18.1.1-18b6c70735-bd2920a238.zip new file mode 100644 index 000000000000..ba6deeda8a4d Binary files /dev/null and b/.yarn/cache/@octokit-openapi-types-npm-18.1.1-18b6c70735-bd2920a238.zip differ diff --git a/.yarn/cache/@octokit-openapi-types-npm-19.0.0-064193076f-87962fee2e.zip b/.yarn/cache/@octokit-openapi-types-npm-19.0.0-064193076f-87962fee2e.zip deleted file mode 100644 index e40b56222214..000000000000 Binary files a/.yarn/cache/@octokit-openapi-types-npm-19.0.0-064193076f-87962fee2e.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-openapi-types-npm-20.0.0-1aac079689-9f60572af1.zip b/.yarn/cache/@octokit-openapi-types-npm-20.0.0-1aac079689-9f60572af1.zip new file mode 100644 index 000000000000..5610914af11f Binary files /dev/null and b/.yarn/cache/@octokit-openapi-types-npm-20.0.0-1aac079689-9f60572af1.zip differ diff --git a/.yarn/cache/@octokit-openapi-types-npm-22.2.0-ce9f704019-0471b0c789.zip b/.yarn/cache/@octokit-openapi-types-npm-22.2.0-ce9f704019-0471b0c789.zip new file mode 100644 index 000000000000..49d5ff53a5ee Binary files /dev/null and b/.yarn/cache/@octokit-openapi-types-npm-22.2.0-ce9f704019-0471b0c789.zip differ diff --git a/.yarn/cache/@octokit-plugin-paginate-rest-npm-9.0.0-fb07663301-1fcf2358d2.zip b/.yarn/cache/@octokit-plugin-paginate-rest-npm-9.0.0-fb07663301-1fcf2358d2.zip deleted file mode 100644 index 69598b27ae0e..000000000000 Binary files a/.yarn/cache/@octokit-plugin-paginate-rest-npm-9.0.0-fb07663301-1fcf2358d2.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-plugin-paginate-rest-npm-9.2.1-9310cd3549-1528ab17ee.zip b/.yarn/cache/@octokit-plugin-paginate-rest-npm-9.2.1-9310cd3549-1528ab17ee.zip new file mode 100644 index 000000000000..60a859a9460e Binary files /dev/null and b/.yarn/cache/@octokit-plugin-paginate-rest-npm-9.2.1-9310cd3549-1528ab17ee.zip differ diff --git a/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-10.0.1-28cbf3f633-8953424d85.zip b/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-10.0.1-28cbf3f633-8953424d85.zip deleted file mode 100644 index 87fa73f09b9e..000000000000 Binary files a/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-10.0.1-28cbf3f633-8953424d85.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-10.4.1-3fc380dbdf-1090fc5a1b.zip b/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-10.4.1-3fc380dbdf-1090fc5a1b.zip new file mode 100644 index 000000000000..a0f41c006e3e Binary files /dev/null and b/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-10.4.1-3fc380dbdf-1090fc5a1b.zip differ diff --git a/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-7.2.1-fce6442c19-fcf90a8b26.zip b/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-7.2.1-fce6442c19-fcf90a8b26.zip deleted file mode 100644 index 79ef715bbd9f..000000000000 Binary files a/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-7.2.1-fce6442c19-fcf90a8b26.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-7.2.3-c54ecf5d8d-59fb4e786a.zip b/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-7.2.3-c54ecf5d8d-59fb4e786a.zip new file mode 100644 index 000000000000..9545ce7565a6 Binary files /dev/null and b/.yarn/cache/@octokit-plugin-rest-endpoint-methods-npm-7.2.3-c54ecf5d8d-59fb4e786a.zip differ diff --git a/.yarn/cache/@octokit-plugin-throttling-npm-4.3.0-41aeb7464b-498baab4c5.zip b/.yarn/cache/@octokit-plugin-throttling-npm-4.3.0-41aeb7464b-498baab4c5.zip deleted file mode 100644 index 39c17ade23d7..000000000000 Binary files a/.yarn/cache/@octokit-plugin-throttling-npm-4.3.0-41aeb7464b-498baab4c5.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-plugin-throttling-npm-4.3.2-63cc75e7c4-f46394b90c.zip b/.yarn/cache/@octokit-plugin-throttling-npm-4.3.2-63cc75e7c4-f46394b90c.zip new file mode 100644 index 000000000000..67f0d85164ee Binary files /dev/null and b/.yarn/cache/@octokit-plugin-throttling-npm-4.3.2-63cc75e7c4-f46394b90c.zip differ diff --git a/.yarn/cache/@octokit-request-error-npm-3.0.0-a69f5de938-5778904ed5.zip b/.yarn/cache/@octokit-request-error-npm-3.0.0-a69f5de938-5778904ed5.zip deleted file mode 100644 index 698f14450284..000000000000 Binary files a/.yarn/cache/@octokit-request-error-npm-3.0.0-a69f5de938-5778904ed5.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-request-error-npm-3.0.3-cbba4d6220-5db0b51473.zip b/.yarn/cache/@octokit-request-error-npm-3.0.3-cbba4d6220-5db0b51473.zip new file mode 100644 index 000000000000..a8ffdc9c0a4d Binary files /dev/null and b/.yarn/cache/@octokit-request-error-npm-3.0.3-cbba4d6220-5db0b51473.zip differ diff --git a/.yarn/cache/@octokit-request-error-npm-5.0.1-eda589102d-a21a4614c4.zip b/.yarn/cache/@octokit-request-error-npm-5.0.1-eda589102d-a21a4614c4.zip deleted file mode 100644 index b96644295688..000000000000 Binary files a/.yarn/cache/@octokit-request-error-npm-5.0.1-eda589102d-a21a4614c4.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-request-error-npm-5.1.0-f7282c5282-d03f9f7a40.zip b/.yarn/cache/@octokit-request-error-npm-5.1.0-f7282c5282-d03f9f7a40.zip new file mode 100644 index 000000000000..933c831e2c84 Binary files /dev/null and b/.yarn/cache/@octokit-request-error-npm-5.1.0-f7282c5282-d03f9f7a40.zip differ diff --git a/.yarn/cache/@octokit-request-npm-6.2.1-240d2f8d84-471ad71eb7.zip b/.yarn/cache/@octokit-request-npm-6.2.1-240d2f8d84-471ad71eb7.zip deleted file mode 100644 index 48d23ac8c8b5..000000000000 Binary files a/.yarn/cache/@octokit-request-npm-6.2.1-240d2f8d84-471ad71eb7.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-request-npm-6.2.8-fbcbb43713-47188fa08d.zip b/.yarn/cache/@octokit-request-npm-6.2.8-fbcbb43713-47188fa08d.zip new file mode 100644 index 000000000000..807d94b6de3f Binary files /dev/null and b/.yarn/cache/@octokit-request-npm-6.2.8-fbcbb43713-47188fa08d.zip differ diff --git a/.yarn/cache/@octokit-request-npm-8.1.4-e871d5ebf1-a51470f470.zip b/.yarn/cache/@octokit-request-npm-8.1.4-e871d5ebf1-a51470f470.zip deleted file mode 100644 index 643bd6bfa27a..000000000000 Binary files a/.yarn/cache/@octokit-request-npm-8.1.4-e871d5ebf1-a51470f470.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-request-npm-8.4.0-75489e49cf-176cd83c68.zip b/.yarn/cache/@octokit-request-npm-8.4.0-75489e49cf-176cd83c68.zip new file mode 100644 index 000000000000..972575f0b192 Binary files /dev/null and b/.yarn/cache/@octokit-request-npm-8.4.0-75489e49cf-176cd83c68.zip differ diff --git a/.yarn/cache/@octokit-rest-npm-19.0.13-3bdada05df-7fbee09a2f.zip b/.yarn/cache/@octokit-rest-npm-19.0.13-3bdada05df-7fbee09a2f.zip new file mode 100644 index 000000000000..e26439e35ab2 Binary files /dev/null and b/.yarn/cache/@octokit-rest-npm-19.0.13-3bdada05df-7fbee09a2f.zip differ diff --git a/.yarn/cache/@octokit-types-npm-10.0.0-8ea850424d-6345e605d3.zip b/.yarn/cache/@octokit-types-npm-10.0.0-8ea850424d-6345e605d3.zip new file mode 100644 index 000000000000..374cc3c9c4f2 Binary files /dev/null and b/.yarn/cache/@octokit-types-npm-10.0.0-8ea850424d-6345e605d3.zip differ diff --git a/.yarn/cache/@octokit-types-npm-12.0.0-b74b3121ec-68faa94efa.zip b/.yarn/cache/@octokit-types-npm-12.0.0-b74b3121ec-68faa94efa.zip deleted file mode 100644 index 8215461fea41..000000000000 Binary files a/.yarn/cache/@octokit-types-npm-12.0.0-b74b3121ec-68faa94efa.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-types-npm-12.6.0-3f6eea3eb3-19b77a8d25.zip b/.yarn/cache/@octokit-types-npm-12.6.0-3f6eea3eb3-19b77a8d25.zip new file mode 100644 index 000000000000..54d728387841 Binary files /dev/null and b/.yarn/cache/@octokit-types-npm-12.6.0-3f6eea3eb3-19b77a8d25.zip differ diff --git a/.yarn/cache/@octokit-types-npm-13.5.0-9d89476548-d2aeebc1d8.zip b/.yarn/cache/@octokit-types-npm-13.5.0-9d89476548-d2aeebc1d8.zip new file mode 100644 index 000000000000..434598c30c7f Binary files /dev/null and b/.yarn/cache/@octokit-types-npm-13.5.0-9d89476548-d2aeebc1d8.zip differ diff --git a/.yarn/cache/@octokit-types-npm-7.5.1-1a7540339f-53e43f423b.zip b/.yarn/cache/@octokit-types-npm-7.5.1-1a7540339f-53e43f423b.zip deleted file mode 100644 index 9a8cd9570805..000000000000 Binary files a/.yarn/cache/@octokit-types-npm-7.5.1-1a7540339f-53e43f423b.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-types-npm-8.0.0-8cee8f31e4-6ef663f9f5.zip b/.yarn/cache/@octokit-types-npm-8.0.0-8cee8f31e4-6ef663f9f5.zip deleted file mode 100644 index 34660a059083..000000000000 Binary files a/.yarn/cache/@octokit-types-npm-8.0.0-8cee8f31e4-6ef663f9f5.zip and /dev/null differ diff --git a/.yarn/cache/@octokit-types-npm-8.2.1-4c7415624d-8b52753b00.zip b/.yarn/cache/@octokit-types-npm-8.2.1-4c7415624d-8b52753b00.zip new file mode 100644 index 000000000000..244d9eb5964f Binary files /dev/null and b/.yarn/cache/@octokit-types-npm-8.2.1-4c7415624d-8b52753b00.zip differ diff --git a/.yarn/cache/@pkgr-utils-npm-2.4.1-982147648e-76d6c364da.zip b/.yarn/cache/@pkgr-utils-npm-2.4.1-982147648e-76d6c364da.zip deleted file mode 100644 index 0a0e952a76cd..000000000000 Binary files a/.yarn/cache/@pkgr-utils-npm-2.4.1-982147648e-76d6c364da.zip and /dev/null differ diff --git a/.yarn/cache/@radix-ui-primitive-npm-1.1.0-9aa14acf6b-7cbf70bfd4.zip b/.yarn/cache/@radix-ui-primitive-npm-1.1.0-9aa14acf6b-7cbf70bfd4.zip new file mode 100644 index 000000000000..d14d44bb54b2 Binary files /dev/null and b/.yarn/cache/@radix-ui-primitive-npm-1.1.0-9aa14acf6b-7cbf70bfd4.zip differ diff --git a/.yarn/cache/@radix-ui-react-collection-npm-1.1.0-8fec2d3db8-d3e6567617.zip b/.yarn/cache/@radix-ui-react-collection-npm-1.1.0-8fec2d3db8-d3e6567617.zip new file mode 100644 index 000000000000..a67e8327f847 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-collection-npm-1.1.0-8fec2d3db8-d3e6567617.zip differ diff --git a/.yarn/cache/@radix-ui-react-compose-refs-npm-1.1.0-98156c7f82-047a4ed5f8.zip b/.yarn/cache/@radix-ui-react-compose-refs-npm-1.1.0-98156c7f82-047a4ed5f8.zip new file mode 100644 index 000000000000..7b2c83e26063 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-compose-refs-npm-1.1.0-98156c7f82-047a4ed5f8.zip differ diff --git a/.yarn/cache/@radix-ui-react-context-npm-1.1.0-91ec9af4c8-755aea1966.zip b/.yarn/cache/@radix-ui-react-context-npm-1.1.0-91ec9af4c8-755aea1966.zip new file mode 100644 index 000000000000..053d19f27b28 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-context-npm-1.1.0-91ec9af4c8-755aea1966.zip differ diff --git a/.yarn/cache/@radix-ui-react-direction-npm-1.1.0-5fb6b21578-25ad0d1d65.zip b/.yarn/cache/@radix-ui-react-direction-npm-1.1.0-5fb6b21578-25ad0d1d65.zip new file mode 100644 index 000000000000..e5ec1a5c9674 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-direction-npm-1.1.0-5fb6b21578-25ad0d1d65.zip differ diff --git a/.yarn/cache/@radix-ui-react-id-npm-1.1.0-520751ed60-6fbc9d1739.zip b/.yarn/cache/@radix-ui-react-id-npm-1.1.0-520751ed60-6fbc9d1739.zip new file mode 100644 index 000000000000..dbe26d34e968 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-id-npm-1.1.0-520751ed60-6fbc9d1739.zip differ diff --git a/.yarn/cache/@radix-ui-react-primitive-npm-2.0.0-ab3a5426b6-f3dc683f5b.zip b/.yarn/cache/@radix-ui-react-primitive-npm-2.0.0-ab3a5426b6-f3dc683f5b.zip new file mode 100644 index 000000000000..11a48c80091b Binary files /dev/null and b/.yarn/cache/@radix-ui-react-primitive-npm-2.0.0-ab3a5426b6-f3dc683f5b.zip differ diff --git a/.yarn/cache/@radix-ui-react-roving-focus-npm-1.0.4-7106f3083a-a23ffb1e3e.zip b/.yarn/cache/@radix-ui-react-roving-focus-npm-1.0.4-7106f3083a-a23ffb1e3e.zip deleted file mode 100644 index 634ce5c9ca2c..000000000000 Binary files a/.yarn/cache/@radix-ui-react-roving-focus-npm-1.0.4-7106f3083a-a23ffb1e3e.zip and /dev/null differ diff --git a/.yarn/cache/@radix-ui-react-roving-focus-npm-1.1.0-6061ae7a81-f7c3d9b6d9.zip b/.yarn/cache/@radix-ui-react-roving-focus-npm-1.1.0-6061ae7a81-f7c3d9b6d9.zip new file mode 100644 index 000000000000..8536d183ba0c Binary files /dev/null and b/.yarn/cache/@radix-ui-react-roving-focus-npm-1.1.0-6061ae7a81-f7c3d9b6d9.zip differ diff --git a/.yarn/cache/@radix-ui-react-separator-npm-1.0.3-a8fd4c57de-b5ea8f1996.zip b/.yarn/cache/@radix-ui-react-separator-npm-1.0.3-a8fd4c57de-b5ea8f1996.zip deleted file mode 100644 index 6a2ddf6921ed..000000000000 Binary files a/.yarn/cache/@radix-ui-react-separator-npm-1.0.3-a8fd4c57de-b5ea8f1996.zip and /dev/null differ diff --git a/.yarn/cache/@radix-ui-react-separator-npm-1.1.0-5ebebe6272-a7c3445603.zip b/.yarn/cache/@radix-ui-react-separator-npm-1.1.0-5ebebe6272-a7c3445603.zip new file mode 100644 index 000000000000..56a76e4726f6 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-separator-npm-1.1.0-5ebebe6272-a7c3445603.zip differ diff --git a/.yarn/cache/@radix-ui-react-slot-npm-1.1.0-f9e1623e18-95e1908684.zip b/.yarn/cache/@radix-ui-react-slot-npm-1.1.0-f9e1623e18-95e1908684.zip new file mode 100644 index 000000000000..ee6c1267a5ea Binary files /dev/null and b/.yarn/cache/@radix-ui-react-slot-npm-1.1.0-f9e1623e18-95e1908684.zip differ diff --git a/.yarn/cache/@radix-ui-react-toggle-group-npm-1.0.4-8ed5373168-96ea35f0e9.zip b/.yarn/cache/@radix-ui-react-toggle-group-npm-1.0.4-8ed5373168-96ea35f0e9.zip deleted file mode 100644 index 42bbaf98d3d7..000000000000 Binary files a/.yarn/cache/@radix-ui-react-toggle-group-npm-1.0.4-8ed5373168-96ea35f0e9.zip and /dev/null differ diff --git a/.yarn/cache/@radix-ui-react-toggle-group-npm-1.1.0-b1b7eb0aef-0d9102e2e3.zip b/.yarn/cache/@radix-ui-react-toggle-group-npm-1.1.0-b1b7eb0aef-0d9102e2e3.zip new file mode 100644 index 000000000000..9b9483b2117f Binary files /dev/null and b/.yarn/cache/@radix-ui-react-toggle-group-npm-1.1.0-b1b7eb0aef-0d9102e2e3.zip differ diff --git a/.yarn/cache/@radix-ui-react-toggle-npm-1.0.3-815cae4672-ed5407f482.zip b/.yarn/cache/@radix-ui-react-toggle-npm-1.0.3-815cae4672-ed5407f482.zip deleted file mode 100644 index 65abcf1e0e4a..000000000000 Binary files a/.yarn/cache/@radix-ui-react-toggle-npm-1.0.3-815cae4672-ed5407f482.zip and /dev/null differ diff --git a/.yarn/cache/@radix-ui-react-toggle-npm-1.1.0-771796dc34-556818c9d5.zip b/.yarn/cache/@radix-ui-react-toggle-npm-1.1.0-771796dc34-556818c9d5.zip new file mode 100644 index 000000000000..f2909bfb8a91 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-toggle-npm-1.1.0-771796dc34-556818c9d5.zip differ diff --git a/.yarn/cache/@radix-ui-react-toolbar-npm-1.0.4-0625e3aacc-57f75b6617.zip b/.yarn/cache/@radix-ui-react-toolbar-npm-1.0.4-0625e3aacc-57f75b6617.zip deleted file mode 100644 index 81f817c32246..000000000000 Binary files a/.yarn/cache/@radix-ui-react-toolbar-npm-1.0.4-0625e3aacc-57f75b6617.zip and /dev/null differ diff --git a/.yarn/cache/@radix-ui-react-toolbar-npm-1.1.0-2bf55e96db-dd5a727de1.zip b/.yarn/cache/@radix-ui-react-toolbar-npm-1.1.0-2bf55e96db-dd5a727de1.zip new file mode 100644 index 000000000000..8c7ffddca2c2 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-toolbar-npm-1.1.0-2bf55e96db-dd5a727de1.zip differ diff --git a/.yarn/cache/@radix-ui-react-use-callback-ref-npm-1.1.0-1727bf35c9-2ec7903c67.zip b/.yarn/cache/@radix-ui-react-use-callback-ref-npm-1.1.0-1727bf35c9-2ec7903c67.zip new file mode 100644 index 000000000000..59c042e22737 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-use-callback-ref-npm-1.1.0-1727bf35c9-2ec7903c67.zip differ diff --git a/.yarn/cache/@radix-ui-react-use-controllable-state-npm-1.1.0-53300dd6f2-9583679150.zip b/.yarn/cache/@radix-ui-react-use-controllable-state-npm-1.1.0-53300dd6f2-9583679150.zip new file mode 100644 index 000000000000..6672bb8f1ee4 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-use-controllable-state-npm-1.1.0-53300dd6f2-9583679150.zip differ diff --git a/.yarn/cache/@radix-ui-react-use-layout-effect-npm-1.1.0-710cee2d09-271ea0bf1c.zip b/.yarn/cache/@radix-ui-react-use-layout-effect-npm-1.1.0-710cee2d09-271ea0bf1c.zip new file mode 100644 index 000000000000..e436f491b3e6 Binary files /dev/null and b/.yarn/cache/@radix-ui-react-use-layout-effect-npm-1.1.0-710cee2d09-271ea0bf1c.zip differ diff --git a/.yarn/cache/@rollup-plugin-alias-npm-5.1.0-5f8a6a898f-2749f9563d.zip b/.yarn/cache/@rollup-plugin-alias-npm-5.1.0-5f8a6a898f-2749f9563d.zip new file mode 100644 index 000000000000..127c1744bff5 Binary files /dev/null and b/.yarn/cache/@rollup-plugin-alias-npm-5.1.0-5f8a6a898f-2749f9563d.zip differ diff --git a/.yarn/cache/@rollup-plugin-babel-npm-6.0.2-a0e15f1f97-fcfcce12d2.zip b/.yarn/cache/@rollup-plugin-babel-npm-6.0.2-a0e15f1f97-fcfcce12d2.zip deleted file mode 100644 index f9290e45e73b..000000000000 Binary files a/.yarn/cache/@rollup-plugin-babel-npm-6.0.2-a0e15f1f97-fcfcce12d2.zip and /dev/null differ diff --git a/.yarn/cache/@rollup-plugin-babel-npm-6.0.4-117a8c516b-89210c8c59.zip b/.yarn/cache/@rollup-plugin-babel-npm-6.0.4-117a8c516b-89210c8c59.zip new file mode 100644 index 000000000000..59696f1fdbc9 Binary files /dev/null and b/.yarn/cache/@rollup-plugin-babel-npm-6.0.4-117a8c516b-89210c8c59.zip differ diff --git a/.yarn/cache/@rollup-plugin-node-resolve-npm-15.0.1-3c00b5782e-3620cad07c.zip b/.yarn/cache/@rollup-plugin-node-resolve-npm-15.0.1-3c00b5782e-3620cad07c.zip deleted file mode 100644 index 76ff8408ab3d..000000000000 Binary files a/.yarn/cache/@rollup-plugin-node-resolve-npm-15.0.1-3c00b5782e-3620cad07c.zip and /dev/null differ diff --git a/.yarn/cache/@rollup-plugin-node-resolve-npm-15.2.3-f49fe9c656-d36a6792fb.zip b/.yarn/cache/@rollup-plugin-node-resolve-npm-15.2.3-f49fe9c656-d36a6792fb.zip new file mode 100644 index 000000000000..1dbb9cab7ca8 Binary files /dev/null and b/.yarn/cache/@rollup-plugin-node-resolve-npm-15.2.3-f49fe9c656-d36a6792fb.zip differ diff --git a/.yarn/cache/@rollup-plugin-replace-npm-5.0.1-681fe3a569-97d308ab6c.zip b/.yarn/cache/@rollup-plugin-replace-npm-5.0.1-681fe3a569-97d308ab6c.zip deleted file mode 100644 index 91341d764c3f..000000000000 Binary files a/.yarn/cache/@rollup-plugin-replace-npm-5.0.1-681fe3a569-97d308ab6c.zip and /dev/null differ diff --git a/.yarn/cache/@rollup-plugin-replace-npm-5.0.7-def496da76-1f0a26fe13.zip b/.yarn/cache/@rollup-plugin-replace-npm-5.0.7-def496da76-1f0a26fe13.zip new file mode 100644 index 000000000000..f5badb5e50dc Binary files /dev/null and b/.yarn/cache/@rollup-plugin-replace-npm-5.0.7-def496da76-1f0a26fe13.zip differ diff --git a/.yarn/cache/@rollup-plugin-terser-npm-0.4.4-c6896dd264-a5e066ddea.zip b/.yarn/cache/@rollup-plugin-terser-npm-0.4.4-c6896dd264-a5e066ddea.zip new file mode 100644 index 000000000000..4330a00fd8e9 Binary files /dev/null and b/.yarn/cache/@rollup-plugin-terser-npm-0.4.4-c6896dd264-a5e066ddea.zip differ diff --git a/.yarn/cache/@rollup-plugin-typescript-npm-11.0.0-867f35a277-ea240f1fd6.zip b/.yarn/cache/@rollup-plugin-typescript-npm-11.0.0-867f35a277-ea240f1fd6.zip deleted file mode 100644 index c8ac89316028..000000000000 Binary files a/.yarn/cache/@rollup-plugin-typescript-npm-11.0.0-867f35a277-ea240f1fd6.zip and /dev/null differ diff --git a/.yarn/cache/@rollup-plugin-typescript-npm-11.1.6-aeaa3525fc-4ae4d6cfc9.zip b/.yarn/cache/@rollup-plugin-typescript-npm-11.1.6-aeaa3525fc-4ae4d6cfc9.zip new file mode 100644 index 000000000000..2a406b7b187c Binary files /dev/null and b/.yarn/cache/@rollup-plugin-typescript-npm-11.1.6-aeaa3525fc-4ae4d6cfc9.zip differ diff --git a/.yarn/cache/@rollup-pluginutils-npm-4.2.1-0f52a5eba2-503a6f0a44.zip b/.yarn/cache/@rollup-pluginutils-npm-4.2.1-0f52a5eba2-503a6f0a44.zip new file mode 100644 index 000000000000..4d313180e598 Binary files /dev/null and b/.yarn/cache/@rollup-pluginutils-npm-4.2.1-0f52a5eba2-503a6f0a44.zip differ diff --git a/.yarn/cache/@rollup-pluginutils-npm-5.0.2-6aa9d0ddd4-7aebf04d5d.zip b/.yarn/cache/@rollup-pluginutils-npm-5.0.2-6aa9d0ddd4-7aebf04d5d.zip deleted file mode 100644 index 9ab700d26889..000000000000 Binary files a/.yarn/cache/@rollup-pluginutils-npm-5.0.2-6aa9d0ddd4-7aebf04d5d.zip and /dev/null differ diff --git a/.yarn/cache/@rollup-pluginutils-npm-5.0.5-cfa8fafc53-7c07bdb6bc.zip b/.yarn/cache/@rollup-pluginutils-npm-5.0.5-cfa8fafc53-7c07bdb6bc.zip new file mode 100644 index 000000000000..dc6f31b2471d Binary files /dev/null and b/.yarn/cache/@rollup-pluginutils-npm-5.0.5-cfa8fafc53-7c07bdb6bc.zip differ diff --git a/.yarn/cache/@rollup-pluginutils-npm-5.1.0-6939820ef8-abb15eaec5.zip b/.yarn/cache/@rollup-pluginutils-npm-5.1.0-6939820ef8-abb15eaec5.zip new file mode 100644 index 000000000000..6daf5a90ba9c Binary files /dev/null and b/.yarn/cache/@rollup-pluginutils-npm-5.1.0-6939820ef8-abb15eaec5.zip differ diff --git a/.yarn/cache/@rollup-rollup-darwin-arm64-npm-4.19.1-883ee0328a-10.zip b/.yarn/cache/@rollup-rollup-darwin-arm64-npm-4.19.1-883ee0328a-10.zip new file mode 100644 index 000000000000..5eee17efaf6c Binary files /dev/null and b/.yarn/cache/@rollup-rollup-darwin-arm64-npm-4.19.1-883ee0328a-10.zip differ diff --git a/.yarn/cache/@rollup-rollup-darwin-x64-npm-4.19.1-9f61249c6c-10.zip b/.yarn/cache/@rollup-rollup-darwin-x64-npm-4.19.1-9f61249c6c-10.zip new file mode 100644 index 000000000000..1072d9297024 Binary files /dev/null and b/.yarn/cache/@rollup-rollup-darwin-x64-npm-4.19.1-9f61249c6c-10.zip differ diff --git a/.yarn/cache/@rollup-rollup-linux-arm64-gnu-npm-4.19.1-aeb5ea0864-10.zip b/.yarn/cache/@rollup-rollup-linux-arm64-gnu-npm-4.19.1-aeb5ea0864-10.zip new file mode 100644 index 000000000000..c4356cc21cb3 Binary files /dev/null and b/.yarn/cache/@rollup-rollup-linux-arm64-gnu-npm-4.19.1-aeb5ea0864-10.zip differ diff --git a/.yarn/cache/@rollup-rollup-linux-x64-gnu-npm-4.19.1-1c3201fe62-10.zip b/.yarn/cache/@rollup-rollup-linux-x64-gnu-npm-4.19.1-1c3201fe62-10.zip new file mode 100644 index 000000000000..c168e3042896 Binary files /dev/null and b/.yarn/cache/@rollup-rollup-linux-x64-gnu-npm-4.19.1-1c3201fe62-10.zip differ diff --git a/.yarn/cache/@rollup-rollup-win32-arm64-msvc-npm-4.19.1-98928a5404-10.zip b/.yarn/cache/@rollup-rollup-win32-arm64-msvc-npm-4.19.1-98928a5404-10.zip new file mode 100644 index 000000000000..a27c7975d66a Binary files /dev/null and b/.yarn/cache/@rollup-rollup-win32-arm64-msvc-npm-4.19.1-98928a5404-10.zip differ diff --git a/.yarn/cache/@rollup-rollup-win32-x64-msvc-npm-4.19.1-1f7a68ddfa-10.zip b/.yarn/cache/@rollup-rollup-win32-x64-msvc-npm-4.19.1-1f7a68ddfa-10.zip new file mode 100644 index 000000000000..b242e49dd676 Binary files /dev/null and b/.yarn/cache/@rollup-rollup-win32-x64-msvc-npm-4.19.1-1f7a68ddfa-10.zip differ diff --git a/.yarn/cache/@rushstack-eslint-patch-npm-1.10.4-a760e177e3-fa14a091cc.zip b/.yarn/cache/@rushstack-eslint-patch-npm-1.10.4-a760e177e3-fa14a091cc.zip new file mode 100644 index 000000000000..e95f8be66ce3 Binary files /dev/null and b/.yarn/cache/@rushstack-eslint-patch-npm-1.10.4-a760e177e3-fa14a091cc.zip differ diff --git a/.yarn/cache/@rushstack-eslint-patch-npm-1.3.2-0939a1615d-e4060163f7.zip b/.yarn/cache/@rushstack-eslint-patch-npm-1.3.2-0939a1615d-e4060163f7.zip deleted file mode 100644 index 1c261de9ec6f..000000000000 Binary files a/.yarn/cache/@rushstack-eslint-patch-npm-1.3.2-0939a1615d-e4060163f7.zip and /dev/null differ diff --git a/.yarn/cache/@sec-ant-readable-stream-npm-0.4.1-12d52145e0-aac8958165.zip b/.yarn/cache/@sec-ant-readable-stream-npm-0.4.1-12d52145e0-aac8958165.zip new file mode 100644 index 000000000000..0701c95bf7e3 Binary files /dev/null and b/.yarn/cache/@sec-ant-readable-stream-npm-0.4.1-12d52145e0-aac8958165.zip differ diff --git a/.yarn/cache/@sigstore-bundle-npm-2.3.2-ce9028d56c-16c2dd6246.zip b/.yarn/cache/@sigstore-bundle-npm-2.3.2-ce9028d56c-16c2dd6246.zip new file mode 100644 index 000000000000..d21ffdaefc91 Binary files /dev/null and b/.yarn/cache/@sigstore-bundle-npm-2.3.2-ce9028d56c-16c2dd6246.zip differ diff --git a/.yarn/cache/@sigstore-core-npm-1.1.0-44b420f972-4149572091.zip b/.yarn/cache/@sigstore-core-npm-1.1.0-44b420f972-4149572091.zip new file mode 100644 index 000000000000..a0a3707fc9c1 Binary files /dev/null and b/.yarn/cache/@sigstore-core-npm-1.1.0-44b420f972-4149572091.zip differ diff --git a/.yarn/cache/@sigstore-protobuf-specs-npm-0.1.0-0b5d821c3c-751d402f7f.zip b/.yarn/cache/@sigstore-protobuf-specs-npm-0.1.0-0b5d821c3c-751d402f7f.zip deleted file mode 100644 index bc51c77005ee..000000000000 Binary files a/.yarn/cache/@sigstore-protobuf-specs-npm-0.1.0-0b5d821c3c-751d402f7f.zip and /dev/null differ diff --git a/.yarn/cache/@sigstore-protobuf-specs-npm-0.3.2-ff6825392f-350a6eb834.zip b/.yarn/cache/@sigstore-protobuf-specs-npm-0.3.2-ff6825392f-350a6eb834.zip new file mode 100644 index 000000000000..2054bc7ac026 Binary files /dev/null and b/.yarn/cache/@sigstore-protobuf-specs-npm-0.3.2-ff6825392f-350a6eb834.zip differ diff --git a/.yarn/cache/@sigstore-sign-npm-2.3.2-2c1302c9b4-3b0198fb8f.zip b/.yarn/cache/@sigstore-sign-npm-2.3.2-2c1302c9b4-3b0198fb8f.zip new file mode 100644 index 000000000000..3bcc5fa0ddf9 Binary files /dev/null and b/.yarn/cache/@sigstore-sign-npm-2.3.2-2c1302c9b4-3b0198fb8f.zip differ diff --git a/.yarn/cache/@sigstore-tuf-npm-1.0.0-28c9866802-b54f6e19e3.zip b/.yarn/cache/@sigstore-tuf-npm-1.0.0-28c9866802-b54f6e19e3.zip deleted file mode 100644 index d66576195438..000000000000 Binary files a/.yarn/cache/@sigstore-tuf-npm-1.0.0-28c9866802-b54f6e19e3.zip and /dev/null differ diff --git a/.yarn/cache/@sigstore-tuf-npm-2.3.4-a77c728ae9-4ef978a0b2.zip b/.yarn/cache/@sigstore-tuf-npm-2.3.4-a77c728ae9-4ef978a0b2.zip new file mode 100644 index 000000000000..9b917d279ca4 Binary files /dev/null and b/.yarn/cache/@sigstore-tuf-npm-2.3.4-a77c728ae9-4ef978a0b2.zip differ diff --git a/.yarn/cache/@sigstore-verify-npm-1.2.1-f2cb932ce3-68a1bb341e.zip b/.yarn/cache/@sigstore-verify-npm-1.2.1-f2cb932ce3-68a1bb341e.zip new file mode 100644 index 000000000000..5fad056db07b Binary files /dev/null and b/.yarn/cache/@sigstore-verify-npm-1.2.1-f2cb932ce3-68a1bb341e.zip differ diff --git a/.yarn/cache/@sinclair-typebox-npm-0.23.5-10c003c068-2d0a9573f9.zip b/.yarn/cache/@sinclair-typebox-npm-0.23.5-10c003c068-2d0a9573f9.zip deleted file mode 100644 index 17ffa81b1994..000000000000 Binary files a/.yarn/cache/@sinclair-typebox-npm-0.23.5-10c003c068-2d0a9573f9.zip and /dev/null differ diff --git a/.yarn/cache/@sinclair-typebox-npm-0.24.51-cdde4a266f-7886847b9d.zip b/.yarn/cache/@sinclair-typebox-npm-0.24.51-cdde4a266f-7886847b9d.zip new file mode 100644 index 000000000000..1db7fe2112aa Binary files /dev/null and b/.yarn/cache/@sinclair-typebox-npm-0.24.51-cdde4a266f-7886847b9d.zip differ diff --git a/.yarn/cache/@sindresorhus-is-npm-6.1.0-d56260a06d-e15c4abdca.zip b/.yarn/cache/@sindresorhus-is-npm-6.1.0-d56260a06d-e15c4abdca.zip deleted file mode 100644 index 19f748c865f5..000000000000 Binary files a/.yarn/cache/@sindresorhus-is-npm-6.1.0-d56260a06d-e15c4abdca.zip and /dev/null differ diff --git a/.yarn/cache/@sindresorhus-is-npm-7.0.0-d5455300d7-768f9155db.zip b/.yarn/cache/@sindresorhus-is-npm-7.0.0-d5455300d7-768f9155db.zip new file mode 100644 index 000000000000..fe184fee0635 Binary files /dev/null and b/.yarn/cache/@sindresorhus-is-npm-7.0.0-d5455300d7-768f9155db.zip differ diff --git a/.yarn/cache/@sinonjs-commons-npm-1.7.0-1df9026921-56bbc0c2d3.zip b/.yarn/cache/@sinonjs-commons-npm-1.7.0-1df9026921-56bbc0c2d3.zip deleted file mode 100644 index 471012ad226e..000000000000 Binary files a/.yarn/cache/@sinonjs-commons-npm-1.7.0-1df9026921-56bbc0c2d3.zip and /dev/null differ diff --git a/.yarn/cache/@sinonjs-commons-npm-1.8.6-e3593ed6d6-51987338fd.zip b/.yarn/cache/@sinonjs-commons-npm-1.8.6-e3593ed6d6-51987338fd.zip new file mode 100644 index 000000000000..91236cd79fa0 Binary files /dev/null and b/.yarn/cache/@sinonjs-commons-npm-1.8.6-e3593ed6d6-51987338fd.zip differ diff --git a/.yarn/cache/@storybook-builder-vite-npm-8.2.9-e33ad290c2-ed8e28b694.zip b/.yarn/cache/@storybook-builder-vite-npm-8.2.9-e33ad290c2-ed8e28b694.zip new file mode 100644 index 000000000000..8cbb58ec88c2 Binary files /dev/null and b/.yarn/cache/@storybook-builder-vite-npm-8.2.9-e33ad290c2-ed8e28b694.zip differ diff --git a/.yarn/cache/@storybook-web-components-npm-8.2.9-f1691d0e15-9bac46a5d7.zip b/.yarn/cache/@storybook-web-components-npm-8.2.9-f1691d0e15-9bac46a5d7.zip new file mode 100644 index 000000000000..de40a38a2a74 Binary files /dev/null and b/.yarn/cache/@storybook-web-components-npm-8.2.9-f1691d0e15-9bac46a5d7.zip differ diff --git a/.yarn/cache/@storybook-web-components-vite-npm-8.2.9-3bd41c0e59-7382d9d2d7.zip b/.yarn/cache/@storybook-web-components-vite-npm-8.2.9-3bd41c0e59-7382d9d2d7.zip new file mode 100644 index 000000000000..bfd49d7af875 Binary files /dev/null and b/.yarn/cache/@storybook-web-components-vite-npm-8.2.9-3bd41c0e59-7382d9d2d7.zip differ diff --git a/.yarn/cache/@swc-counter-npm-0.1.3-ce42b0e3f5-df8f9cfba9.zip b/.yarn/cache/@swc-counter-npm-0.1.3-ce42b0e3f5-df8f9cfba9.zip new file mode 100644 index 000000000000..3b53020e9431 Binary files /dev/null and b/.yarn/cache/@swc-counter-npm-0.1.3-ce42b0e3f5-df8f9cfba9.zip differ diff --git a/.yarn/cache/@swc-helpers-npm-0.5.5-a0698e6ac9-1c5ef04f64.zip b/.yarn/cache/@swc-helpers-npm-0.5.5-a0698e6ac9-1c5ef04f64.zip new file mode 100644 index 000000000000..4f91b0075c62 Binary files /dev/null and b/.yarn/cache/@swc-helpers-npm-0.5.5-a0698e6ac9-1c5ef04f64.zip differ diff --git a/.yarn/cache/@testim-chrome-version-npm-1.0.7-258fb7c7ce-e9d88791f2.zip b/.yarn/cache/@testim-chrome-version-npm-1.0.7-258fb7c7ce-e9d88791f2.zip deleted file mode 100644 index c8c4b21921dd..000000000000 Binary files a/.yarn/cache/@testim-chrome-version-npm-1.0.7-258fb7c7ce-e9d88791f2.zip and /dev/null differ diff --git a/.yarn/cache/@testim-chrome-version-npm-1.1.4-11fe243748-faaed16b6b.zip b/.yarn/cache/@testim-chrome-version-npm-1.1.4-11fe243748-faaed16b6b.zip new file mode 100644 index 000000000000..78c11bf25728 Binary files /dev/null and b/.yarn/cache/@testim-chrome-version-npm-1.1.4-11fe243748-faaed16b6b.zip differ diff --git a/.yarn/cache/@testing-library-dom-npm-10.1.0-720175996f-6d6ef942de.zip b/.yarn/cache/@testing-library-dom-npm-10.1.0-720175996f-6d6ef942de.zip deleted file mode 100644 index 39a10c264b06..000000000000 Binary files a/.yarn/cache/@testing-library-dom-npm-10.1.0-720175996f-6d6ef942de.zip and /dev/null differ diff --git a/.yarn/cache/@testing-library-dom-npm-10.4.0-a0d2ca848e-05825ee9a1.zip b/.yarn/cache/@testing-library-dom-npm-10.4.0-a0d2ca848e-05825ee9a1.zip new file mode 100644 index 000000000000..e7a43a3f6a79 Binary files /dev/null and b/.yarn/cache/@testing-library-dom-npm-10.4.0-a0d2ca848e-05825ee9a1.zip differ diff --git a/.yarn/cache/@testing-library-jest-dom-npm-6.0.1-90ebbcfb58-ad7fbe0441.zip b/.yarn/cache/@testing-library-jest-dom-npm-6.0.1-90ebbcfb58-ad7fbe0441.zip deleted file mode 100644 index f4f61d39ef87..000000000000 Binary files a/.yarn/cache/@testing-library-jest-dom-npm-6.0.1-90ebbcfb58-ad7fbe0441.zip and /dev/null differ diff --git a/.yarn/cache/@testing-library-jest-dom-npm-6.4.8-490ab7a359-011e5a309e.zip b/.yarn/cache/@testing-library-jest-dom-npm-6.4.8-490ab7a359-011e5a309e.zip new file mode 100644 index 000000000000..6fba92505d64 Binary files /dev/null and b/.yarn/cache/@testing-library-jest-dom-npm-6.4.8-490ab7a359-011e5a309e.zip differ diff --git a/.yarn/cache/@testing-library-user-event-npm-14.4.3-2d1a75355f-0c7c1ee6ba.zip b/.yarn/cache/@testing-library-user-event-npm-14.4.3-2d1a75355f-0c7c1ee6ba.zip deleted file mode 100644 index 13fe0c1d4835..000000000000 Binary files a/.yarn/cache/@testing-library-user-event-npm-14.4.3-2d1a75355f-0c7c1ee6ba.zip and /dev/null differ diff --git a/.yarn/cache/@testing-library-user-event-npm-14.5.2-ec9587901c-49821459d8.zip b/.yarn/cache/@testing-library-user-event-npm-14.5.2-ec9587901c-49821459d8.zip new file mode 100644 index 000000000000..fcff3506508a Binary files /dev/null and b/.yarn/cache/@testing-library-user-event-npm-14.5.2-ec9587901c-49821459d8.zip differ diff --git a/.yarn/cache/@textlint-ast-node-types-npm-12.6.1-c306cc2320-a0a5d82fe4.zip b/.yarn/cache/@textlint-ast-node-types-npm-12.6.1-c306cc2320-a0a5d82fe4.zip new file mode 100644 index 000000000000..995ae7b1d1f5 Binary files /dev/null and b/.yarn/cache/@textlint-ast-node-types-npm-12.6.1-c306cc2320-a0a5d82fe4.zip differ diff --git a/.yarn/cache/@textlint-ast-node-types-npm-4.4.3-23d45d4c41-e71ba2e029.zip b/.yarn/cache/@textlint-ast-node-types-npm-4.4.3-23d45d4c41-e71ba2e029.zip deleted file mode 100644 index a11c0835652f..000000000000 Binary files a/.yarn/cache/@textlint-ast-node-types-npm-4.4.3-23d45d4c41-e71ba2e029.zip and /dev/null differ diff --git a/.yarn/cache/@textlint-markdown-to-ast-npm-12.6.1-c6a8402e2c-48d1954f0f.zip b/.yarn/cache/@textlint-markdown-to-ast-npm-12.6.1-c6a8402e2c-48d1954f0f.zip new file mode 100644 index 000000000000..d92348b9237c Binary files /dev/null and b/.yarn/cache/@textlint-markdown-to-ast-npm-12.6.1-c6a8402e2c-48d1954f0f.zip differ diff --git a/.yarn/cache/@textlint-markdown-to-ast-npm-6.1.7-594f11b5df-77fc91c963.zip b/.yarn/cache/@textlint-markdown-to-ast-npm-6.1.7-594f11b5df-77fc91c963.zip deleted file mode 100644 index 1b143d93385f..000000000000 Binary files a/.yarn/cache/@textlint-markdown-to-ast-npm-6.1.7-594f11b5df-77fc91c963.zip and /dev/null differ diff --git a/.yarn/cache/@tootallnate-quickjs-emscripten-npm-0.23.0-a889ea7aeb-95cbad451d.zip b/.yarn/cache/@tootallnate-quickjs-emscripten-npm-0.23.0-a889ea7aeb-95cbad451d.zip new file mode 100644 index 000000000000..c6ee758d5afa Binary files /dev/null and b/.yarn/cache/@tootallnate-quickjs-emscripten-npm-0.23.0-a889ea7aeb-95cbad451d.zip differ diff --git a/.yarn/cache/@tufjs-canonical-json-npm-1.0.0-66d27d850f-9ff3bcd129.zip b/.yarn/cache/@tufjs-canonical-json-npm-1.0.0-66d27d850f-9ff3bcd129.zip deleted file mode 100644 index 980393d7774b..000000000000 Binary files a/.yarn/cache/@tufjs-canonical-json-npm-1.0.0-66d27d850f-9ff3bcd129.zip and /dev/null differ diff --git a/.yarn/cache/@tufjs-canonical-json-npm-2.0.0-46a22aa444-cc719a1d0d.zip b/.yarn/cache/@tufjs-canonical-json-npm-2.0.0-46a22aa444-cc719a1d0d.zip new file mode 100644 index 000000000000..213475a1fd6e Binary files /dev/null and b/.yarn/cache/@tufjs-canonical-json-npm-2.0.0-46a22aa444-cc719a1d0d.zip differ diff --git a/.yarn/cache/@tufjs-models-npm-1.0.4-a1dddaf561-2c63e9cfc0.zip b/.yarn/cache/@tufjs-models-npm-1.0.4-a1dddaf561-2c63e9cfc0.zip deleted file mode 100644 index 50d948d6a4c9..000000000000 Binary files a/.yarn/cache/@tufjs-models-npm-1.0.4-a1dddaf561-2c63e9cfc0.zip and /dev/null differ diff --git a/.yarn/cache/@tufjs-models-npm-2.0.1-39153b9fec-7c5d2b8194.zip b/.yarn/cache/@tufjs-models-npm-2.0.1-39153b9fec-7c5d2b8194.zip new file mode 100644 index 000000000000..5fb1105b36c9 Binary files /dev/null and b/.yarn/cache/@tufjs-models-npm-2.0.1-39153b9fec-7c5d2b8194.zip differ diff --git a/.yarn/cache/@tybys-wasm-util-npm-0.9.0-5f9b6b37b1-aa58e64753.zip b/.yarn/cache/@tybys-wasm-util-npm-0.9.0-5f9b6b37b1-aa58e64753.zip new file mode 100644 index 000000000000..60d4d683800d Binary files /dev/null and b/.yarn/cache/@tybys-wasm-util-npm-0.9.0-5f9b6b37b1-aa58e64753.zip differ diff --git a/.yarn/cache/@types-babel__generator-npm-7.6.1-1afd3e1fa9-af2e4a2a16.zip b/.yarn/cache/@types-babel__generator-npm-7.6.1-1afd3e1fa9-af2e4a2a16.zip deleted file mode 100644 index 6a4f404fbeb0..000000000000 Binary files a/.yarn/cache/@types-babel__generator-npm-7.6.1-1afd3e1fa9-af2e4a2a16.zip and /dev/null differ diff --git a/.yarn/cache/@types-babel__generator-npm-7.6.8-61be1197d9-b53c215e90.zip b/.yarn/cache/@types-babel__generator-npm-7.6.8-61be1197d9-b53c215e90.zip new file mode 100644 index 000000000000..1064ba015fbc Binary files /dev/null and b/.yarn/cache/@types-babel__generator-npm-7.6.8-61be1197d9-b53c215e90.zip differ diff --git a/.yarn/cache/@types-babel__template-npm-7.0.2-32d369837a-e1bbf80509.zip b/.yarn/cache/@types-babel__template-npm-7.0.2-32d369837a-e1bbf80509.zip deleted file mode 100644 index 781466051f0d..000000000000 Binary files a/.yarn/cache/@types-babel__template-npm-7.0.2-32d369837a-e1bbf80509.zip and /dev/null differ diff --git a/.yarn/cache/@types-babel__template-npm-7.4.4-f34eba762c-d7a02d2a9b.zip b/.yarn/cache/@types-babel__template-npm-7.4.4-f34eba762c-d7a02d2a9b.zip new file mode 100644 index 000000000000..c421f0574b6f Binary files /dev/null and b/.yarn/cache/@types-babel__template-npm-7.4.4-f34eba762c-d7a02d2a9b.zip differ diff --git a/.yarn/cache/@types-bluebird-npm-3.5.42-15f353048c-09ad60b083.zip b/.yarn/cache/@types-bluebird-npm-3.5.42-15f353048c-09ad60b083.zip new file mode 100644 index 000000000000..c63d1433dbf9 Binary files /dev/null and b/.yarn/cache/@types-bluebird-npm-3.5.42-15f353048c-09ad60b083.zip differ diff --git a/.yarn/cache/@types-body-parser-npm-1.19.2-f845b7b538-e17840c7d7.zip b/.yarn/cache/@types-body-parser-npm-1.19.2-f845b7b538-e17840c7d7.zip deleted file mode 100644 index 37c532e75bc1..000000000000 Binary files a/.yarn/cache/@types-body-parser-npm-1.19.2-f845b7b538-e17840c7d7.zip and /dev/null differ diff --git a/.yarn/cache/@types-body-parser-npm-1.19.5-97fb106976-1e251118c4.zip b/.yarn/cache/@types-body-parser-npm-1.19.5-97fb106976-1e251118c4.zip new file mode 100644 index 000000000000..507341171d76 Binary files /dev/null and b/.yarn/cache/@types-body-parser-npm-1.19.5-97fb106976-1e251118c4.zip differ diff --git a/.yarn/cache/@types-connect-npm-3.4.35-7337eee0a3-fe81351470.zip b/.yarn/cache/@types-connect-npm-3.4.35-7337eee0a3-fe81351470.zip deleted file mode 100644 index ae5f3a0f182d..000000000000 Binary files a/.yarn/cache/@types-connect-npm-3.4.35-7337eee0a3-fe81351470.zip and /dev/null differ diff --git a/.yarn/cache/@types-connect-npm-3.4.38-a8a4c38337-7eb1bc5342.zip b/.yarn/cache/@types-connect-npm-3.4.38-a8a4c38337-7eb1bc5342.zip new file mode 100644 index 000000000000..f943dcaa9bb5 Binary files /dev/null and b/.yarn/cache/@types-connect-npm-3.4.38-a8a4c38337-7eb1bc5342.zip differ diff --git a/.yarn/cache/@types-cross-spawn-npm-6.0.2-f5d63b3325-fa9edd3217.zip b/.yarn/cache/@types-cross-spawn-npm-6.0.2-f5d63b3325-fa9edd3217.zip deleted file mode 100644 index 66dc87d1904a..000000000000 Binary files a/.yarn/cache/@types-cross-spawn-npm-6.0.2-f5d63b3325-fa9edd3217.zip and /dev/null differ diff --git a/.yarn/cache/@types-cross-spawn-npm-6.0.6-fbe5fe9243-b4172927cd.zip b/.yarn/cache/@types-cross-spawn-npm-6.0.6-fbe5fe9243-b4172927cd.zip new file mode 100644 index 000000000000..2cddf3213816 Binary files /dev/null and b/.yarn/cache/@types-cross-spawn-npm-6.0.6-fbe5fe9243-b4172927cd.zip differ diff --git a/.yarn/cache/@types-debug-npm-4.1.12-82a3fc4905-47876a852d.zip b/.yarn/cache/@types-debug-npm-4.1.12-82a3fc4905-47876a852d.zip new file mode 100644 index 000000000000..521af2cb5eba Binary files /dev/null and b/.yarn/cache/@types-debug-npm-4.1.12-82a3fc4905-47876a852d.zip differ diff --git a/.yarn/cache/@types-debug-npm-4.1.8-a04e2ca136-a9a9bb40a1.zip b/.yarn/cache/@types-debug-npm-4.1.8-a04e2ca136-a9a9bb40a1.zip deleted file mode 100644 index 62cdd38f27f4..000000000000 Binary files a/.yarn/cache/@types-debug-npm-4.1.8-a04e2ca136-a9a9bb40a1.zip and /dev/null differ diff --git a/.yarn/cache/@types-emscripten-npm-1.39.13-baf7427522-02c0446150.zip b/.yarn/cache/@types-emscripten-npm-1.39.13-baf7427522-02c0446150.zip new file mode 100644 index 000000000000..9d7e31ed4310 Binary files /dev/null and b/.yarn/cache/@types-emscripten-npm-1.39.13-baf7427522-02c0446150.zip differ diff --git a/.yarn/cache/@types-emscripten-npm-1.39.6-c9c4021365-1f5dcf1dbc.zip b/.yarn/cache/@types-emscripten-npm-1.39.6-c9c4021365-1f5dcf1dbc.zip deleted file mode 100644 index 4eccdfc44c8d..000000000000 Binary files a/.yarn/cache/@types-emscripten-npm-1.39.6-c9c4021365-1f5dcf1dbc.zip and /dev/null differ diff --git a/.yarn/cache/@types-express-serve-static-core-npm-4.17.35-c86e5f6e4a-9f08212ac1.zip b/.yarn/cache/@types-express-serve-static-core-npm-4.17.35-c86e5f6e4a-9f08212ac1.zip deleted file mode 100644 index c885909f912a..000000000000 Binary files a/.yarn/cache/@types-express-serve-static-core-npm-4.17.35-c86e5f6e4a-9f08212ac1.zip and /dev/null differ diff --git a/.yarn/cache/@types-express-serve-static-core-npm-4.19.5-6a71bb1fe8-49350c6315.zip b/.yarn/cache/@types-express-serve-static-core-npm-4.19.5-6a71bb1fe8-49350c6315.zip new file mode 100644 index 000000000000..2b40f7a95adf Binary files /dev/null and b/.yarn/cache/@types-express-serve-static-core-npm-4.19.5-6a71bb1fe8-49350c6315.zip differ diff --git a/.yarn/cache/@types-find-cache-dir-npm-3.2.1-07fd2b6e78-bf5c4e96da.zip b/.yarn/cache/@types-find-cache-dir-npm-3.2.1-07fd2b6e78-bf5c4e96da.zip new file mode 100644 index 000000000000..107a9901c5a3 Binary files /dev/null and b/.yarn/cache/@types-find-cache-dir-npm-3.2.1-07fd2b6e78-bf5c4e96da.zip differ diff --git a/.yarn/cache/@types-fs-extra-npm-8.1.5-77d3a95112-565d9e55cd.zip b/.yarn/cache/@types-fs-extra-npm-8.1.5-77d3a95112-565d9e55cd.zip new file mode 100644 index 000000000000..6a65899354e3 Binary files /dev/null and b/.yarn/cache/@types-fs-extra-npm-8.1.5-77d3a95112-565d9e55cd.zip differ diff --git a/.yarn/cache/@types-glob-npm-7.2.0-772334bf9a-6ae717fedf.zip b/.yarn/cache/@types-glob-npm-7.2.0-772334bf9a-6ae717fedf.zip new file mode 100644 index 000000000000..f3ad9aedc27d Binary files /dev/null and b/.yarn/cache/@types-glob-npm-7.2.0-772334bf9a-6ae717fedf.zip differ diff --git a/.yarn/cache/@types-graceful-fs-npm-4.1.5-91d62e1050-d076bb61f4.zip b/.yarn/cache/@types-graceful-fs-npm-4.1.5-91d62e1050-d076bb61f4.zip deleted file mode 100644 index 7e5f7a5f32e5..000000000000 Binary files a/.yarn/cache/@types-graceful-fs-npm-4.1.5-91d62e1050-d076bb61f4.zip and /dev/null differ diff --git a/.yarn/cache/@types-graceful-fs-npm-4.1.9-ebd697fe83-79d746a8f0.zip b/.yarn/cache/@types-graceful-fs-npm-4.1.9-ebd697fe83-79d746a8f0.zip new file mode 100644 index 000000000000..8af594bc6aa0 Binary files /dev/null and b/.yarn/cache/@types-graceful-fs-npm-4.1.9-ebd697fe83-79d746a8f0.zip differ diff --git a/.yarn/cache/@types-http-proxy-npm-1.17.14-170e4e32fb-aa1a3e66cd.zip b/.yarn/cache/@types-http-proxy-npm-1.17.14-170e4e32fb-aa1a3e66cd.zip new file mode 100644 index 000000000000..3ff35190a599 Binary files /dev/null and b/.yarn/cache/@types-http-proxy-npm-1.17.14-170e4e32fb-aa1a3e66cd.zip differ diff --git a/.yarn/cache/@types-http-proxy-npm-1.17.8-0e73b3e3eb-426c910286.zip b/.yarn/cache/@types-http-proxy-npm-1.17.8-0e73b3e3eb-426c910286.zip deleted file mode 100644 index 90171e74aeca..000000000000 Binary files a/.yarn/cache/@types-http-proxy-npm-1.17.8-0e73b3e3eb-426c910286.zip and /dev/null differ diff --git a/.yarn/cache/@types-istanbul-lib-coverage-npm-2.0.1-c8b87e4b03-7de11cd954.zip b/.yarn/cache/@types-istanbul-lib-coverage-npm-2.0.1-c8b87e4b03-7de11cd954.zip deleted file mode 100644 index d63249eab582..000000000000 Binary files a/.yarn/cache/@types-istanbul-lib-coverage-npm-2.0.1-c8b87e4b03-7de11cd954.zip and /dev/null differ diff --git a/.yarn/cache/@types-istanbul-lib-coverage-npm-2.0.6-2ea31fda9c-3feac423fd.zip b/.yarn/cache/@types-istanbul-lib-coverage-npm-2.0.6-2ea31fda9c-3feac423fd.zip new file mode 100644 index 000000000000..c09edec14c31 Binary files /dev/null and b/.yarn/cache/@types-istanbul-lib-coverage-npm-2.0.6-2ea31fda9c-3feac423fd.zip differ diff --git a/.yarn/cache/@types-istanbul-lib-report-npm-3.0.0-50de3e6b3b-f121dcac8a.zip b/.yarn/cache/@types-istanbul-lib-report-npm-3.0.0-50de3e6b3b-f121dcac8a.zip deleted file mode 100644 index 7f0ebaf27820..000000000000 Binary files a/.yarn/cache/@types-istanbul-lib-report-npm-3.0.0-50de3e6b3b-f121dcac8a.zip and /dev/null differ diff --git a/.yarn/cache/@types-istanbul-lib-report-npm-3.0.3-a5c0ef4b88-b91e9b60f8.zip b/.yarn/cache/@types-istanbul-lib-report-npm-3.0.3-a5c0ef4b88-b91e9b60f8.zip new file mode 100644 index 000000000000..b9934ced9579 Binary files /dev/null and b/.yarn/cache/@types-istanbul-lib-report-npm-3.0.3-a5c0ef4b88-b91e9b60f8.zip differ diff --git a/.yarn/cache/@types-istanbul-reports-npm-3.0.0-e6fb7a309c-286a18cff1.zip b/.yarn/cache/@types-istanbul-reports-npm-3.0.0-e6fb7a309c-286a18cff1.zip deleted file mode 100644 index 8f12c1a48e33..000000000000 Binary files a/.yarn/cache/@types-istanbul-reports-npm-3.0.0-e6fb7a309c-286a18cff1.zip and /dev/null differ diff --git a/.yarn/cache/@types-istanbul-reports-npm-3.0.4-1afa69db29-93eb188357.zip b/.yarn/cache/@types-istanbul-reports-npm-3.0.4-1afa69db29-93eb188357.zip new file mode 100644 index 000000000000..47eedca9480b Binary files /dev/null and b/.yarn/cache/@types-istanbul-reports-npm-3.0.4-1afa69db29-93eb188357.zip differ diff --git a/.yarn/cache/@types-jasmine-npm-3.10.18-0ee1412708-25ae5b329c.zip b/.yarn/cache/@types-jasmine-npm-3.10.18-0ee1412708-25ae5b329c.zip new file mode 100644 index 000000000000..33b00eae3b7d Binary files /dev/null and b/.yarn/cache/@types-jasmine-npm-3.10.18-0ee1412708-25ae5b329c.zip differ diff --git a/.yarn/cache/@types-jest-npm-29.5.12-6459b9d012-312e8dcf92.zip b/.yarn/cache/@types-jest-npm-29.5.12-6459b9d012-312e8dcf92.zip new file mode 100644 index 000000000000..3b867eeb6c64 Binary files /dev/null and b/.yarn/cache/@types-jest-npm-29.5.12-6459b9d012-312e8dcf92.zip differ diff --git a/.yarn/cache/@types-jsdom-npm-16.2.14-bfbb37071c-d44ac37189.zip b/.yarn/cache/@types-jsdom-npm-16.2.14-bfbb37071c-d44ac37189.zip deleted file mode 100644 index 93ae85079089..000000000000 Binary files a/.yarn/cache/@types-jsdom-npm-16.2.14-bfbb37071c-d44ac37189.zip and /dev/null differ diff --git a/.yarn/cache/@types-jsdom-npm-16.2.15-1241c41fda-16f9f9f7d5.zip b/.yarn/cache/@types-jsdom-npm-16.2.15-1241c41fda-16f9f9f7d5.zip new file mode 100644 index 000000000000..3633895dbd55 Binary files /dev/null and b/.yarn/cache/@types-jsdom-npm-16.2.15-1241c41fda-16f9f9f7d5.zip differ diff --git a/.yarn/cache/@types-json-schema-npm-7.0.15-fd16381786-1a3c3e0623.zip b/.yarn/cache/@types-json-schema-npm-7.0.15-fd16381786-1a3c3e0623.zip new file mode 100644 index 000000000000..681120149963 Binary files /dev/null and b/.yarn/cache/@types-json-schema-npm-7.0.15-fd16381786-1a3c3e0623.zip differ diff --git a/.yarn/cache/@types-json-schema-npm-7.0.9-361918cff3-7ceb41e396.zip b/.yarn/cache/@types-json-schema-npm-7.0.9-361918cff3-7ceb41e396.zip deleted file mode 100644 index 10fe6311b73a..000000000000 Binary files a/.yarn/cache/@types-json-schema-npm-7.0.9-361918cff3-7ceb41e396.zip and /dev/null differ diff --git a/.yarn/cache/@types-lodash-es-npm-4.17.12-87dce3f795-56b9a43334.zip b/.yarn/cache/@types-lodash-es-npm-4.17.12-87dce3f795-56b9a43334.zip new file mode 100644 index 000000000000..1b7b880a469a Binary files /dev/null and b/.yarn/cache/@types-lodash-es-npm-4.17.12-87dce3f795-56b9a43334.zip differ diff --git a/.yarn/cache/@types-lodash-npm-4.14.182-1073aac722-6c0d3fa682.zip b/.yarn/cache/@types-lodash-npm-4.14.182-1073aac722-6c0d3fa682.zip deleted file mode 100644 index edcb3269688f..000000000000 Binary files a/.yarn/cache/@types-lodash-npm-4.14.182-1073aac722-6c0d3fa682.zip and /dev/null differ diff --git a/.yarn/cache/@types-lodash-npm-4.17.7-2077805efb-b8177f19cf.zip b/.yarn/cache/@types-lodash-npm-4.17.7-2077805efb-b8177f19cf.zip new file mode 100644 index 000000000000..4dceac21308e Binary files /dev/null and b/.yarn/cache/@types-lodash-npm-4.17.7-2077805efb-b8177f19cf.zip differ diff --git a/.yarn/cache/@types-mdast-npm-3.0.15-66e5bbbc2b-050a5c1383.zip b/.yarn/cache/@types-mdast-npm-3.0.15-66e5bbbc2b-050a5c1383.zip new file mode 100644 index 000000000000..cdbe0fd094fa Binary files /dev/null and b/.yarn/cache/@types-mdast-npm-3.0.15-66e5bbbc2b-050a5c1383.zip differ diff --git a/.yarn/cache/@types-mdx-npm-2.0.13-52981f86f6-b73ed5f081.zip b/.yarn/cache/@types-mdx-npm-2.0.13-52981f86f6-b73ed5f081.zip new file mode 100644 index 000000000000..7ab69cb33bd6 Binary files /dev/null and b/.yarn/cache/@types-mdx-npm-2.0.13-52981f86f6-b73ed5f081.zip differ diff --git a/.yarn/cache/@types-mdx-npm-2.0.5-3b264b4530-1069baff0b.zip b/.yarn/cache/@types-mdx-npm-2.0.5-3b264b4530-1069baff0b.zip deleted file mode 100644 index 647f338d61eb..000000000000 Binary files a/.yarn/cache/@types-mdx-npm-2.0.5-3b264b4530-1069baff0b.zip and /dev/null differ diff --git a/.yarn/cache/@types-mime-npm-1.3.2-ea71878ab3-0493368244.zip b/.yarn/cache/@types-mime-npm-1.3.2-ea71878ab3-0493368244.zip deleted file mode 100644 index e363cbe58cbb..000000000000 Binary files a/.yarn/cache/@types-mime-npm-1.3.2-ea71878ab3-0493368244.zip and /dev/null differ diff --git a/.yarn/cache/@types-mime-npm-1.3.5-48d28990db-e29a5f9c47.zip b/.yarn/cache/@types-mime-npm-1.3.5-48d28990db-e29a5f9c47.zip new file mode 100644 index 000000000000..c39cba3f0479 Binary files /dev/null and b/.yarn/cache/@types-mime-npm-1.3.5-48d28990db-e29a5f9c47.zip differ diff --git a/.yarn/cache/@types-minimatch-npm-3.0.4-f1932169cb-583a174116.zip b/.yarn/cache/@types-minimatch-npm-3.0.4-f1932169cb-583a174116.zip deleted file mode 100644 index 471388042bf9..000000000000 Binary files a/.yarn/cache/@types-minimatch-npm-3.0.4-f1932169cb-583a174116.zip and /dev/null differ diff --git a/.yarn/cache/@types-minimatch-npm-3.0.5-802bb0797f-c41d136f67.zip b/.yarn/cache/@types-minimatch-npm-3.0.5-802bb0797f-c41d136f67.zip new file mode 100644 index 000000000000..11730d3c38d3 Binary files /dev/null and b/.yarn/cache/@types-minimatch-npm-3.0.5-802bb0797f-c41d136f67.zip differ diff --git a/.yarn/cache/@types-minimatch-npm-5.1.2-aab9c394d3-94db5060d2.zip b/.yarn/cache/@types-minimatch-npm-5.1.2-aab9c394d3-94db5060d2.zip new file mode 100644 index 000000000000..2a03433ab8f4 Binary files /dev/null and b/.yarn/cache/@types-minimatch-npm-5.1.2-aab9c394d3-94db5060d2.zip differ diff --git a/.yarn/cache/@types-minimist-npm-1.2.2-a445de65da-b8da83c66e.zip b/.yarn/cache/@types-minimist-npm-1.2.2-a445de65da-b8da83c66e.zip deleted file mode 100644 index 42814291074f..000000000000 Binary files a/.yarn/cache/@types-minimist-npm-1.2.2-a445de65da-b8da83c66e.zip and /dev/null differ diff --git a/.yarn/cache/@types-minimist-npm-1.2.5-c85664a9d8-477047b606.zip b/.yarn/cache/@types-minimist-npm-1.2.5-c85664a9d8-477047b606.zip new file mode 100644 index 000000000000..21b2adc583da Binary files /dev/null and b/.yarn/cache/@types-minimist-npm-1.2.5-c85664a9d8-477047b606.zip differ diff --git a/.yarn/cache/@types-ms-npm-0.7.31-ea3b89342b-6647b295fb.zip b/.yarn/cache/@types-ms-npm-0.7.31-ea3b89342b-6647b295fb.zip deleted file mode 100644 index bda4e3b646a2..000000000000 Binary files a/.yarn/cache/@types-ms-npm-0.7.31-ea3b89342b-6647b295fb.zip and /dev/null differ diff --git a/.yarn/cache/@types-ms-npm-0.7.34-46f5141bfd-f38d36e7b6.zip b/.yarn/cache/@types-ms-npm-0.7.34-46f5141bfd-f38d36e7b6.zip new file mode 100644 index 000000000000..5f29610c32ad Binary files /dev/null and b/.yarn/cache/@types-ms-npm-0.7.34-46f5141bfd-f38d36e7b6.zip differ diff --git a/.yarn/cache/@types-node-npm-14.18.47-d4b030205d-ff293a46d6.zip b/.yarn/cache/@types-node-npm-14.18.47-d4b030205d-ff293a46d6.zip deleted file mode 100644 index 72f1350174e2..000000000000 Binary files a/.yarn/cache/@types-node-npm-14.18.47-d4b030205d-ff293a46d6.zip and /dev/null differ diff --git a/.yarn/cache/@types-node-npm-14.18.63-a411f0ee60-82a7775898.zip b/.yarn/cache/@types-node-npm-14.18.63-a411f0ee60-82a7775898.zip new file mode 100644 index 000000000000..1554a12aada0 Binary files /dev/null and b/.yarn/cache/@types-node-npm-14.18.63-a411f0ee60-82a7775898.zip differ diff --git a/.yarn/cache/@types-normalize-package-data-npm-2.4.0-ed928aaaa8-f98b30d59e.zip b/.yarn/cache/@types-normalize-package-data-npm-2.4.0-ed928aaaa8-f98b30d59e.zip deleted file mode 100644 index e93bf7b3c545..000000000000 Binary files a/.yarn/cache/@types-normalize-package-data-npm-2.4.0-ed928aaaa8-f98b30d59e.zip and /dev/null differ diff --git a/.yarn/cache/@types-normalize-package-data-npm-2.4.4-676a8ba353-65dff72b54.zip b/.yarn/cache/@types-normalize-package-data-npm-2.4.4-676a8ba353-65dff72b54.zip new file mode 100644 index 000000000000..58fbb00485b3 Binary files /dev/null and b/.yarn/cache/@types-normalize-package-data-npm-2.4.4-676a8ba353-65dff72b54.zip differ diff --git a/.yarn/cache/@types-parse-json-npm-4.0.0-298522afa6-4df9de9815.zip b/.yarn/cache/@types-parse-json-npm-4.0.0-298522afa6-4df9de9815.zip deleted file mode 100644 index 66498d8d0422..000000000000 Binary files a/.yarn/cache/@types-parse-json-npm-4.0.0-298522afa6-4df9de9815.zip and /dev/null differ diff --git a/.yarn/cache/@types-parse-json-npm-4.0.2-f87f65692e-5bf62eec37.zip b/.yarn/cache/@types-parse-json-npm-4.0.2-f87f65692e-5bf62eec37.zip new file mode 100644 index 000000000000..2b86e9102fe3 Binary files /dev/null and b/.yarn/cache/@types-parse-json-npm-4.0.2-f87f65692e-5bf62eec37.zip differ diff --git a/.yarn/cache/@types-prettier-npm-2.3.0-b1be4bd841-86fd0b6285.zip b/.yarn/cache/@types-prettier-npm-2.3.0-b1be4bd841-86fd0b6285.zip deleted file mode 100644 index 066b53443df1..000000000000 Binary files a/.yarn/cache/@types-prettier-npm-2.3.0-b1be4bd841-86fd0b6285.zip and /dev/null differ diff --git a/.yarn/cache/@types-prettier-npm-2.7.3-497316f37c-cda84c19ac.zip b/.yarn/cache/@types-prettier-npm-2.7.3-497316f37c-cda84c19ac.zip new file mode 100644 index 000000000000..ab9f7b00263c Binary files /dev/null and b/.yarn/cache/@types-prettier-npm-2.7.3-497316f37c-cda84c19ac.zip differ diff --git a/.yarn/cache/@types-q-npm-1.5.2-a077e9d454-f1594d5daf.zip b/.yarn/cache/@types-q-npm-1.5.2-a077e9d454-f1594d5daf.zip deleted file mode 100644 index 5fcc70a8b088..000000000000 Binary files a/.yarn/cache/@types-q-npm-1.5.2-a077e9d454-f1594d5daf.zip and /dev/null differ diff --git a/.yarn/cache/@types-q-npm-1.5.8-a29ca59dc8-eaa21cd2cf.zip b/.yarn/cache/@types-q-npm-1.5.8-a29ca59dc8-eaa21cd2cf.zip new file mode 100644 index 000000000000..b0622614da9b Binary files /dev/null and b/.yarn/cache/@types-q-npm-1.5.8-a29ca59dc8-eaa21cd2cf.zip differ diff --git a/.yarn/cache/@types-qs-npm-6.9.15-aae1b1e2f7-97d8208c2b.zip b/.yarn/cache/@types-qs-npm-6.9.15-aae1b1e2f7-97d8208c2b.zip new file mode 100644 index 000000000000..d5e81fa1ea7b Binary files /dev/null and b/.yarn/cache/@types-qs-npm-6.9.15-aae1b1e2f7-97d8208c2b.zip differ diff --git a/.yarn/cache/@types-qs-npm-6.9.7-4a3e6ca0d0-7fd6f9c250.zip b/.yarn/cache/@types-qs-npm-6.9.7-4a3e6ca0d0-7fd6f9c250.zip deleted file mode 100644 index 9137540a9993..000000000000 Binary files a/.yarn/cache/@types-qs-npm-6.9.7-4a3e6ca0d0-7fd6f9c250.zip and /dev/null differ diff --git a/.yarn/cache/@types-range-parser-npm-1.2.4-23d797fbde-b7c0dfd508.zip b/.yarn/cache/@types-range-parser-npm-1.2.4-23d797fbde-b7c0dfd508.zip deleted file mode 100644 index 951f3f1062d1..000000000000 Binary files a/.yarn/cache/@types-range-parser-npm-1.2.4-23d797fbde-b7c0dfd508.zip and /dev/null differ diff --git a/.yarn/cache/@types-range-parser-npm-1.2.7-a83c0b6429-95640233b6.zip b/.yarn/cache/@types-range-parser-npm-1.2.7-a83c0b6429-95640233b6.zip new file mode 100644 index 000000000000..a2c7ae4c00e1 Binary files /dev/null and b/.yarn/cache/@types-range-parser-npm-1.2.7-a83c0b6429-95640233b6.zip differ diff --git a/.yarn/cache/@types-react-npm-18.3.1-5744cb1fe5-baa6b8a75c.zip b/.yarn/cache/@types-react-npm-18.3.1-5744cb1fe5-baa6b8a75c.zip deleted file mode 100644 index c5daf109e0b5..000000000000 Binary files a/.yarn/cache/@types-react-npm-18.3.1-5744cb1fe5-baa6b8a75c.zip and /dev/null differ diff --git a/.yarn/cache/@types-react-npm-18.3.3-07e68e178e-68e203b7f1.zip b/.yarn/cache/@types-react-npm-18.3.3-07e68e178e-68e203b7f1.zip new file mode 100644 index 000000000000..f220e739465a Binary files /dev/null and b/.yarn/cache/@types-react-npm-18.3.3-07e68e178e-68e203b7f1.zip differ diff --git a/.yarn/cache/@types-responselike-npm-1.0.0-85dd08af42-e497238945.zip b/.yarn/cache/@types-responselike-npm-1.0.0-85dd08af42-e497238945.zip deleted file mode 100644 index 26cd4029d3ec..000000000000 Binary files a/.yarn/cache/@types-responselike-npm-1.0.0-85dd08af42-e497238945.zip and /dev/null differ diff --git a/.yarn/cache/@types-responselike-npm-1.0.3-de0150f03d-6ac4b35723.zip b/.yarn/cache/@types-responselike-npm-1.0.3-de0150f03d-6ac4b35723.zip new file mode 100644 index 000000000000..1e5c0cb6eab8 Binary files /dev/null and b/.yarn/cache/@types-responselike-npm-1.0.3-de0150f03d-6ac4b35723.zip differ diff --git a/.yarn/cache/@types-semver-npm-7.5.0-4823ff34be-8fbfbf79e9.zip b/.yarn/cache/@types-semver-npm-7.5.0-4823ff34be-8fbfbf79e9.zip deleted file mode 100644 index 40e1b5e0146a..000000000000 Binary files a/.yarn/cache/@types-semver-npm-7.5.0-4823ff34be-8fbfbf79e9.zip and /dev/null differ diff --git a/.yarn/cache/@types-semver-npm-7.5.8-26073743d7-3496808818.zip b/.yarn/cache/@types-semver-npm-7.5.8-26073743d7-3496808818.zip new file mode 100644 index 000000000000..159fae7cde56 Binary files /dev/null and b/.yarn/cache/@types-semver-npm-7.5.8-26073743d7-3496808818.zip differ diff --git a/.yarn/cache/@types-send-npm-0.17.1-5f715ca966-6420837887.zip b/.yarn/cache/@types-send-npm-0.17.1-5f715ca966-6420837887.zip deleted file mode 100644 index 0de34ba37bf4..000000000000 Binary files a/.yarn/cache/@types-send-npm-0.17.1-5f715ca966-6420837887.zip and /dev/null differ diff --git a/.yarn/cache/@types-send-npm-0.17.4-9d7c55577f-28320a2aa1.zip b/.yarn/cache/@types-send-npm-0.17.4-9d7c55577f-28320a2aa1.zip new file mode 100644 index 000000000000..b3fb472c55a2 Binary files /dev/null and b/.yarn/cache/@types-send-npm-0.17.4-9d7c55577f-28320a2aa1.zip differ diff --git a/.yarn/cache/@types-stack-utils-npm-2.0.0-8ded8461bc-b3fbae25b0.zip b/.yarn/cache/@types-stack-utils-npm-2.0.0-8ded8461bc-b3fbae25b0.zip deleted file mode 100644 index 7b51292f18ee..000000000000 Binary files a/.yarn/cache/@types-stack-utils-npm-2.0.0-8ded8461bc-b3fbae25b0.zip and /dev/null differ diff --git a/.yarn/cache/@types-stack-utils-npm-2.0.3-48a0a03262-72576cc152.zip b/.yarn/cache/@types-stack-utils-npm-2.0.3-48a0a03262-72576cc152.zip new file mode 100644 index 000000000000..875101af5e6c Binary files /dev/null and b/.yarn/cache/@types-stack-utils-npm-2.0.3-48a0a03262-72576cc152.zip differ diff --git a/.yarn/cache/@types-tough-cookie-npm-4.0.2-9e61f877e6-8682b40629.zip b/.yarn/cache/@types-tough-cookie-npm-4.0.2-9e61f877e6-8682b40629.zip deleted file mode 100644 index 65a6a3c46649..000000000000 Binary files a/.yarn/cache/@types-tough-cookie-npm-4.0.2-9e61f877e6-8682b40629.zip and /dev/null differ diff --git a/.yarn/cache/@types-tough-cookie-npm-4.0.5-8c5e2162e1-01fd82efc8.zip b/.yarn/cache/@types-tough-cookie-npm-4.0.5-8c5e2162e1-01fd82efc8.zip new file mode 100644 index 000000000000..14551125ae91 Binary files /dev/null and b/.yarn/cache/@types-tough-cookie-npm-4.0.5-8c5e2162e1-01fd82efc8.zip differ diff --git a/.yarn/cache/@types-trusted-types-npm-2.0.7-a07fc44f59-8e4202766a.zip b/.yarn/cache/@types-trusted-types-npm-2.0.7-a07fc44f59-8e4202766a.zip new file mode 100644 index 000000000000..3d2f216ed3bc Binary files /dev/null and b/.yarn/cache/@types-trusted-types-npm-2.0.7-a07fc44f59-8e4202766a.zip differ diff --git a/.yarn/cache/@types-unist-npm-2.0.10-f9b9ac478e-e2924e18de.zip b/.yarn/cache/@types-unist-npm-2.0.10-f9b9ac478e-e2924e18de.zip new file mode 100644 index 000000000000..3746c358130e Binary files /dev/null and b/.yarn/cache/@types-unist-npm-2.0.10-f9b9ac478e-e2924e18de.zip differ diff --git a/.yarn/cache/@types-unist-npm-2.0.3-4b26dedfde-c13ec9068d.zip b/.yarn/cache/@types-unist-npm-2.0.3-4b26dedfde-c13ec9068d.zip deleted file mode 100644 index df96f09e16fe..000000000000 Binary files a/.yarn/cache/@types-unist-npm-2.0.3-4b26dedfde-c13ec9068d.zip and /dev/null differ diff --git a/.yarn/cache/@types-unist-npm-3.0.2-3bce72a913-3d04d0be69.zip b/.yarn/cache/@types-unist-npm-3.0.2-3bce72a913-3d04d0be69.zip new file mode 100644 index 000000000000..e76a2f16032a Binary files /dev/null and b/.yarn/cache/@types-unist-npm-3.0.2-3bce72a913-3d04d0be69.zip differ diff --git a/.yarn/cache/@types-unist-npm-3.0.3-1c20461f2e-96e6453da9.zip b/.yarn/cache/@types-unist-npm-3.0.3-1c20461f2e-96e6453da9.zip deleted file mode 100644 index 5f5c08b6f9d7..000000000000 Binary files a/.yarn/cache/@types-unist-npm-3.0.3-1c20461f2e-96e6453da9.zip and /dev/null differ diff --git a/.yarn/cache/@types-vfile-message-npm-1.0.1-94f6b0361a-a5fd80df8d.zip b/.yarn/cache/@types-vfile-message-npm-1.0.1-94f6b0361a-a5fd80df8d.zip new file mode 100644 index 000000000000..bae64eed168b Binary files /dev/null and b/.yarn/cache/@types-vfile-message-npm-1.0.1-94f6b0361a-a5fd80df8d.zip differ diff --git a/.yarn/cache/@types-vfile-message-npm-2.0.0-e0014f470c-3c019a88d6.zip b/.yarn/cache/@types-vfile-message-npm-2.0.0-e0014f470c-3c019a88d6.zip deleted file mode 100644 index cc1502cd57b4..000000000000 Binary files a/.yarn/cache/@types-vfile-message-npm-2.0.0-e0014f470c-3c019a88d6.zip and /dev/null differ diff --git a/.yarn/cache/@types-yargs-npm-17.0.10-04ed5382c7-cfe94e8ba5.zip b/.yarn/cache/@types-yargs-npm-17.0.10-04ed5382c7-cfe94e8ba5.zip deleted file mode 100644 index 54c437a923f4..000000000000 Binary files a/.yarn/cache/@types-yargs-npm-17.0.10-04ed5382c7-cfe94e8ba5.zip and /dev/null differ diff --git a/.yarn/cache/@types-yargs-npm-17.0.32-38712e567a-1e2b267384.zip b/.yarn/cache/@types-yargs-npm-17.0.32-38712e567a-1e2b267384.zip new file mode 100644 index 000000000000..91964222b69f Binary files /dev/null and b/.yarn/cache/@types-yargs-npm-17.0.32-38712e567a-1e2b267384.zip differ diff --git a/.yarn/cache/@types-yargs-parser-npm-15.0.0-db1d59832c-333ab73a1f.zip b/.yarn/cache/@types-yargs-parser-npm-15.0.0-db1d59832c-333ab73a1f.zip deleted file mode 100644 index 79202fcbb055..000000000000 Binary files a/.yarn/cache/@types-yargs-parser-npm-15.0.0-db1d59832c-333ab73a1f.zip and /dev/null differ diff --git a/.yarn/cache/@types-yargs-parser-npm-21.0.3-1d265246a1-a794eb750e.zip b/.yarn/cache/@types-yargs-parser-npm-21.0.3-1d265246a1-a794eb750e.zip new file mode 100644 index 000000000000..4aae8db13d3a Binary files /dev/null and b/.yarn/cache/@types-yargs-parser-npm-21.0.3-1d265246a1-a794eb750e.zip differ diff --git a/.yarn/cache/@types-yauzl-npm-2.10.3-4b633e1ddc-5ee966ea7b.zip b/.yarn/cache/@types-yauzl-npm-2.10.3-4b633e1ddc-5ee966ea7b.zip new file mode 100644 index 000000000000..1530a2be8f40 Binary files /dev/null and b/.yarn/cache/@types-yauzl-npm-2.10.3-4b633e1ddc-5ee966ea7b.zip differ diff --git a/.yarn/cache/@types-yauzl-npm-2.9.1-fc63c94ba6-49534eebab.zip b/.yarn/cache/@types-yauzl-npm-2.9.1-fc63c94ba6-49534eebab.zip deleted file mode 100644 index 2f68fe5997a3..000000000000 Binary files a/.yarn/cache/@types-yauzl-npm-2.9.1-fc63c94ba6-49534eebab.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-eslint-plugin-npm-5.59.6-86575b47ed-a39b0b8c80.zip b/.yarn/cache/@typescript-eslint-eslint-plugin-npm-5.59.6-86575b47ed-a39b0b8c80.zip deleted file mode 100644 index 273ff02ba00b..000000000000 Binary files a/.yarn/cache/@typescript-eslint-eslint-plugin-npm-5.59.6-86575b47ed-a39b0b8c80.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-eslint-plugin-npm-5.62.0-c48b9a5492-9cc8319c6f.zip b/.yarn/cache/@typescript-eslint-eslint-plugin-npm-5.62.0-c48b9a5492-9cc8319c6f.zip new file mode 100644 index 000000000000..eb69a1ef2596 Binary files /dev/null and b/.yarn/cache/@typescript-eslint-eslint-plugin-npm-5.62.0-c48b9a5492-9cc8319c6f.zip differ diff --git a/.yarn/cache/@typescript-eslint-parser-npm-5.60.1-5b4c773190-4117ce76b1.zip b/.yarn/cache/@typescript-eslint-parser-npm-5.60.1-5b4c773190-4117ce76b1.zip deleted file mode 100644 index e7aff45aa162..000000000000 Binary files a/.yarn/cache/@typescript-eslint-parser-npm-5.60.1-5b4c773190-4117ce76b1.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-parser-npm-5.62.0-c6b29fa302-b6ca629d8f.zip b/.yarn/cache/@typescript-eslint-parser-npm-5.62.0-c6b29fa302-b6ca629d8f.zip new file mode 100644 index 000000000000..5a7c153fefff Binary files /dev/null and b/.yarn/cache/@typescript-eslint-parser-npm-5.62.0-c6b29fa302-b6ca629d8f.zip differ diff --git a/.yarn/cache/@typescript-eslint-scope-manager-npm-5.59.6-4dd15100b2-325de282a1.zip b/.yarn/cache/@typescript-eslint-scope-manager-npm-5.59.6-4dd15100b2-325de282a1.zip deleted file mode 100644 index eafd31fa2ccc..000000000000 Binary files a/.yarn/cache/@typescript-eslint-scope-manager-npm-5.59.6-4dd15100b2-325de282a1.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-scope-manager-npm-5.60.1-6fd320c6c3-0fb618d689.zip b/.yarn/cache/@typescript-eslint-scope-manager-npm-5.60.1-6fd320c6c3-0fb618d689.zip deleted file mode 100644 index 1779869ac34f..000000000000 Binary files a/.yarn/cache/@typescript-eslint-scope-manager-npm-5.60.1-6fd320c6c3-0fb618d689.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-type-utils-npm-5.59.6-d65d99a670-25e363d33c.zip b/.yarn/cache/@typescript-eslint-type-utils-npm-5.59.6-d65d99a670-25e363d33c.zip deleted file mode 100644 index 2217932a9a63..000000000000 Binary files a/.yarn/cache/@typescript-eslint-type-utils-npm-5.59.6-d65d99a670-25e363d33c.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-type-utils-npm-5.62.0-220216d668-f9a4398d6d.zip b/.yarn/cache/@typescript-eslint-type-utils-npm-5.62.0-220216d668-f9a4398d6d.zip new file mode 100644 index 000000000000..c75eb860a317 Binary files /dev/null and b/.yarn/cache/@typescript-eslint-type-utils-npm-5.62.0-220216d668-f9a4398d6d.zip differ diff --git a/.yarn/cache/@typescript-eslint-types-npm-5.59.6-1c7e8a61d3-fda210cb81.zip b/.yarn/cache/@typescript-eslint-types-npm-5.59.6-1c7e8a61d3-fda210cb81.zip deleted file mode 100644 index 1c07a135f888..000000000000 Binary files a/.yarn/cache/@typescript-eslint-types-npm-5.59.6-1c7e8a61d3-fda210cb81.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-types-npm-5.60.1-38a0e3f5b9-69c2b31e6f.zip b/.yarn/cache/@typescript-eslint-types-npm-5.60.1-38a0e3f5b9-69c2b31e6f.zip deleted file mode 100644 index 1ce8abe42583..000000000000 Binary files a/.yarn/cache/@typescript-eslint-types-npm-5.60.1-38a0e3f5b9-69c2b31e6f.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-typescript-estree-npm-5.59.6-7337b89070-3798ef5804.zip b/.yarn/cache/@typescript-eslint-typescript-estree-npm-5.59.6-7337b89070-3798ef5804.zip deleted file mode 100644 index 2fc13ab0246b..000000000000 Binary files a/.yarn/cache/@typescript-eslint-typescript-estree-npm-5.59.6-7337b89070-3798ef5804.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-typescript-estree-npm-5.60.1-1fa27ea8d4-f67ad9bc86.zip b/.yarn/cache/@typescript-eslint-typescript-estree-npm-5.60.1-1fa27ea8d4-f67ad9bc86.zip deleted file mode 100644 index 3f3555a11105..000000000000 Binary files a/.yarn/cache/@typescript-eslint-typescript-estree-npm-5.60.1-1fa27ea8d4-f67ad9bc86.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-utils-npm-5.59.6-ac988726e8-6faf350175.zip b/.yarn/cache/@typescript-eslint-utils-npm-5.59.6-ac988726e8-6faf350175.zip deleted file mode 100644 index ec41e15a11cb..000000000000 Binary files a/.yarn/cache/@typescript-eslint-utils-npm-5.59.6-ac988726e8-6faf350175.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-visitor-keys-npm-5.59.6-7e0a261ee1-b52c0b60fa.zip b/.yarn/cache/@typescript-eslint-visitor-keys-npm-5.59.6-7e0a261ee1-b52c0b60fa.zip deleted file mode 100644 index dc57cb9f1c81..000000000000 Binary files a/.yarn/cache/@typescript-eslint-visitor-keys-npm-5.59.6-7e0a261ee1-b52c0b60fa.zip and /dev/null differ diff --git a/.yarn/cache/@typescript-eslint-visitor-keys-npm-5.60.1-78f4352527-15826a8373.zip b/.yarn/cache/@typescript-eslint-visitor-keys-npm-5.60.1-78f4352527-15826a8373.zip deleted file mode 100644 index b51be08a7e52..000000000000 Binary files a/.yarn/cache/@typescript-eslint-visitor-keys-npm-5.60.1-78f4352527-15826a8373.zip and /dev/null differ diff --git a/.yarn/cache/@vue-compiler-sfc-npm-2.7.16-a7ff2cddb3-fd1128fe1b.zip b/.yarn/cache/@vue-compiler-sfc-npm-2.7.16-a7ff2cddb3-fd1128fe1b.zip new file mode 100644 index 000000000000..58a9cfd4caef Binary files /dev/null and b/.yarn/cache/@vue-compiler-sfc-npm-2.7.16-a7ff2cddb3-fd1128fe1b.zip differ diff --git a/.yarn/cache/@webcomponents-webcomponentsjs-npm-2.8.0-36c07db4d2-acba7dce2c.zip b/.yarn/cache/@webcomponents-webcomponentsjs-npm-2.8.0-36c07db4d2-acba7dce2c.zip new file mode 100644 index 000000000000..2002d7a905df Binary files /dev/null and b/.yarn/cache/@webcomponents-webcomponentsjs-npm-2.8.0-36c07db4d2-acba7dce2c.zip differ diff --git a/.yarn/cache/@zkochan-js-yaml-npm-0.0.6-3eced3a388-1a079db8bc.zip b/.yarn/cache/@zkochan-js-yaml-npm-0.0.6-3eced3a388-1a079db8bc.zip deleted file mode 100644 index bc8714e66302..000000000000 Binary files a/.yarn/cache/@zkochan-js-yaml-npm-0.0.6-3eced3a388-1a079db8bc.zip and /dev/null differ diff --git a/.yarn/cache/@zkochan-js-yaml-npm-0.0.7-931c761308-83642debff.zip b/.yarn/cache/@zkochan-js-yaml-npm-0.0.7-931c761308-83642debff.zip new file mode 100644 index 000000000000..51a83267749d Binary files /dev/null and b/.yarn/cache/@zkochan-js-yaml-npm-0.0.7-931c761308-83642debff.zip differ diff --git a/.yarn/cache/abbrev-npm-2.0.0-0eb38a17e5-ca0a54e35b.zip b/.yarn/cache/abbrev-npm-2.0.0-0eb38a17e5-ca0a54e35b.zip new file mode 100644 index 000000000000..4b92f56772a7 Binary files /dev/null and b/.yarn/cache/abbrev-npm-2.0.0-0eb38a17e5-ca0a54e35b.zip differ diff --git a/.yarn/cache/accessibility-checker-engine-npm-3.1.62-338e2a2e3d-ed36a64f84.zip b/.yarn/cache/accessibility-checker-engine-npm-3.1.62-338e2a2e3d-ed36a64f84.zip deleted file mode 100644 index e74b9e85509d..000000000000 Binary files a/.yarn/cache/accessibility-checker-engine-npm-3.1.62-338e2a2e3d-ed36a64f84.zip and /dev/null differ diff --git a/.yarn/cache/accessibility-checker-engine-npm-3.1.73-606575db72-222b44505f.zip b/.yarn/cache/accessibility-checker-engine-npm-3.1.73-606575db72-222b44505f.zip new file mode 100644 index 000000000000..9f46b1c7b7cc Binary files /dev/null and b/.yarn/cache/accessibility-checker-engine-npm-3.1.73-606575db72-222b44505f.zip differ diff --git a/.yarn/cache/agent-base-npm-7.1.1-c9e1a4b59e-c478fec8f7.zip b/.yarn/cache/agent-base-npm-7.1.1-c9e1a4b59e-c478fec8f7.zip new file mode 100644 index 000000000000..4996c95ed611 Binary files /dev/null and b/.yarn/cache/agent-base-npm-7.1.1-c9e1a4b59e-c478fec8f7.zip differ diff --git a/.yarn/cache/agentkeepalive-npm-4.2.1-b86a9fb343-63961cba1a.zip b/.yarn/cache/agentkeepalive-npm-4.2.1-b86a9fb343-63961cba1a.zip deleted file mode 100644 index d543b8e87beb..000000000000 Binary files a/.yarn/cache/agentkeepalive-npm-4.2.1-b86a9fb343-63961cba1a.zip and /dev/null differ diff --git a/.yarn/cache/all-contributors-cli-npm-6.19.0-0cde72da11-eb8cc0549c.zip b/.yarn/cache/all-contributors-cli-npm-6.19.0-0cde72da11-eb8cc0549c.zip deleted file mode 100644 index 87a4576eaad5..000000000000 Binary files a/.yarn/cache/all-contributors-cli-npm-6.19.0-0cde72da11-eb8cc0549c.zip and /dev/null differ diff --git a/.yarn/cache/all-contributors-cli-npm-6.26.1-b196173d57-07878861df.zip b/.yarn/cache/all-contributors-cli-npm-6.26.1-b196173d57-07878861df.zip new file mode 100644 index 000000000000..93361fb55dbb Binary files /dev/null and b/.yarn/cache/all-contributors-cli-npm-6.26.1-b196173d57-07878861df.zip differ diff --git a/.yarn/cache/anchor-markdown-header-npm-0.5.7-59fdd094d5-d504cc03ff.zip b/.yarn/cache/anchor-markdown-header-npm-0.5.7-59fdd094d5-d504cc03ff.zip deleted file mode 100644 index 650989f2678d..000000000000 Binary files a/.yarn/cache/anchor-markdown-header-npm-0.5.7-59fdd094d5-d504cc03ff.zip and /dev/null differ diff --git a/.yarn/cache/anchor-markdown-header-npm-0.6.0-73e0950f01-6e5766ae2c.zip b/.yarn/cache/anchor-markdown-header-npm-0.6.0-73e0950f01-6e5766ae2c.zip new file mode 100644 index 000000000000..b7f6b116d5f0 Binary files /dev/null and b/.yarn/cache/anchor-markdown-header-npm-0.6.0-73e0950f01-6e5766ae2c.zip differ diff --git a/.yarn/cache/ansi-align-npm-3.0.0-2f770647c2-22cebe8d9b.zip b/.yarn/cache/ansi-align-npm-3.0.0-2f770647c2-22cebe8d9b.zip deleted file mode 100644 index 5a7df68d7481..000000000000 Binary files a/.yarn/cache/ansi-align-npm-3.0.0-2f770647c2-22cebe8d9b.zip and /dev/null differ diff --git a/.yarn/cache/ansi-align-npm-3.0.1-8e6288d20a-4c7e8b6a10.zip b/.yarn/cache/ansi-align-npm-3.0.1-8e6288d20a-4c7e8b6a10.zip new file mode 100644 index 000000000000..84afbfdb5cd8 Binary files /dev/null and b/.yarn/cache/ansi-align-npm-3.0.1-8e6288d20a-4c7e8b6a10.zip differ diff --git a/.yarn/cache/ansi-colors-npm-4.1.1-97ad42f223-e862fddd0a.zip b/.yarn/cache/ansi-colors-npm-4.1.1-97ad42f223-e862fddd0a.zip deleted file mode 100644 index f5fd8c0b16b2..000000000000 Binary files a/.yarn/cache/ansi-colors-npm-4.1.1-97ad42f223-e862fddd0a.zip and /dev/null differ diff --git a/.yarn/cache/ansi-colors-npm-4.1.3-8ffd0ae6c7-43d6e2fc7b.zip b/.yarn/cache/ansi-colors-npm-4.1.3-8ffd0ae6c7-43d6e2fc7b.zip new file mode 100644 index 000000000000..c2d78bcf9fdc Binary files /dev/null and b/.yarn/cache/ansi-colors-npm-4.1.3-8ffd0ae6c7-43d6e2fc7b.zip differ diff --git a/.yarn/cache/ansi-escapes-npm-5.0.0-8a26b6a77d-cbfb95f9f6.zip b/.yarn/cache/ansi-escapes-npm-5.0.0-8a26b6a77d-cbfb95f9f6.zip deleted file mode 100644 index 87a143ef754c..000000000000 Binary files a/.yarn/cache/ansi-escapes-npm-5.0.0-8a26b6a77d-cbfb95f9f6.zip and /dev/null differ diff --git a/.yarn/cache/ansi-escapes-npm-6.2.0-acda9c0a5d-442f91b046.zip b/.yarn/cache/ansi-escapes-npm-6.2.0-acda9c0a5d-442f91b046.zip deleted file mode 100644 index 5d99da6ae405..000000000000 Binary files a/.yarn/cache/ansi-escapes-npm-6.2.0-acda9c0a5d-442f91b046.zip and /dev/null differ diff --git a/.yarn/cache/ansi-escapes-npm-6.2.1-fcae4e6cbc-3b064937dc.zip b/.yarn/cache/ansi-escapes-npm-6.2.1-fcae4e6cbc-3b064937dc.zip new file mode 100644 index 000000000000..63e8dd3deaeb Binary files /dev/null and b/.yarn/cache/ansi-escapes-npm-6.2.1-fcae4e6cbc-3b064937dc.zip differ diff --git a/.yarn/cache/ansi-escapes-npm-7.0.0-70628135e5-2d0e234508.zip b/.yarn/cache/ansi-escapes-npm-7.0.0-70628135e5-2d0e234508.zip new file mode 100644 index 000000000000..40a14f6564f2 Binary files /dev/null and b/.yarn/cache/ansi-escapes-npm-7.0.0-70628135e5-2d0e234508.zip differ diff --git a/.yarn/cache/ansi-regex-npm-3.0.0-be0b845911-2ad11c416f.zip b/.yarn/cache/ansi-regex-npm-3.0.0-be0b845911-2ad11c416f.zip deleted file mode 100644 index d0c2902890ff..000000000000 Binary files a/.yarn/cache/ansi-regex-npm-3.0.0-be0b845911-2ad11c416f.zip and /dev/null differ diff --git a/.yarn/cache/ansi-regex-npm-3.0.1-01f44078a3-09daf180c5.zip b/.yarn/cache/ansi-regex-npm-3.0.1-01f44078a3-09daf180c5.zip new file mode 100644 index 000000000000..b7e261d15b0c Binary files /dev/null and b/.yarn/cache/ansi-regex-npm-3.0.1-01f44078a3-09daf180c5.zip differ diff --git a/.yarn/cache/ansi-regex-npm-4.1.0-4a7d8413fe-97aa465953.zip b/.yarn/cache/ansi-regex-npm-4.1.0-4a7d8413fe-97aa465953.zip deleted file mode 100644 index 7ff4a9216a63..000000000000 Binary files a/.yarn/cache/ansi-regex-npm-4.1.0-4a7d8413fe-97aa465953.zip and /dev/null differ diff --git a/.yarn/cache/ansi-regex-npm-4.1.1-af0a582bb9-b1a6ee44cb.zip b/.yarn/cache/ansi-regex-npm-4.1.1-af0a582bb9-b1a6ee44cb.zip new file mode 100644 index 000000000000..e568811030a0 Binary files /dev/null and b/.yarn/cache/ansi-regex-npm-4.1.1-af0a582bb9-b1a6ee44cb.zip differ diff --git a/.yarn/cache/anymatch-npm-3.1.2-1d5471acfa-985163db22.zip b/.yarn/cache/anymatch-npm-3.1.2-1d5471acfa-985163db22.zip deleted file mode 100644 index b71280dc2a75..000000000000 Binary files a/.yarn/cache/anymatch-npm-3.1.2-1d5471acfa-985163db22.zip and /dev/null differ diff --git a/.yarn/cache/anymatch-npm-3.1.3-bc81d103b1-3e044fd6d1.zip b/.yarn/cache/anymatch-npm-3.1.3-bc81d103b1-3e044fd6d1.zip new file mode 100644 index 000000000000..095ff2093348 Binary files /dev/null and b/.yarn/cache/anymatch-npm-3.1.3-bc81d103b1-3e044fd6d1.zip differ diff --git a/.yarn/cache/archiver-npm-5.3.1-db84171f80-f77b575694.zip b/.yarn/cache/archiver-npm-5.3.1-db84171f80-f77b575694.zip deleted file mode 100644 index 008cdaddc0ca..000000000000 Binary files a/.yarn/cache/archiver-npm-5.3.1-db84171f80-f77b575694.zip and /dev/null differ diff --git a/.yarn/cache/archiver-npm-5.3.2-cd50d62eca-9384b3b20d.zip b/.yarn/cache/archiver-npm-5.3.2-cd50d62eca-9384b3b20d.zip new file mode 100644 index 000000000000..1415b7b53869 Binary files /dev/null and b/.yarn/cache/archiver-npm-5.3.2-cd50d62eca-9384b3b20d.zip differ diff --git a/.yarn/cache/archiver-utils-npm-3.0.4-71b8c9e097-a838c325a1.zip b/.yarn/cache/archiver-utils-npm-3.0.4-71b8c9e097-a838c325a1.zip new file mode 100644 index 000000000000..d44366ef40ab Binary files /dev/null and b/.yarn/cache/archiver-utils-npm-3.0.4-71b8c9e097-a838c325a1.zip differ diff --git a/.yarn/cache/are-we-there-yet-npm-3.0.1-3395b1512f-390731720e.zip b/.yarn/cache/are-we-there-yet-npm-3.0.1-3395b1512f-390731720e.zip deleted file mode 100644 index 8c1d9a190189..000000000000 Binary files a/.yarn/cache/are-we-there-yet-npm-3.0.1-3395b1512f-390731720e.zip and /dev/null differ diff --git a/.yarn/cache/aria-hidden-npm-1.2.3-02d72be80c-cd7f8474f1.zip b/.yarn/cache/aria-hidden-npm-1.2.3-02d72be80c-cd7f8474f1.zip deleted file mode 100644 index 69e23890cd50..000000000000 Binary files a/.yarn/cache/aria-hidden-npm-1.2.3-02d72be80c-cd7f8474f1.zip and /dev/null differ diff --git a/.yarn/cache/aria-hidden-npm-1.2.4-9bb601e7c8-df4bc15423.zip b/.yarn/cache/aria-hidden-npm-1.2.4-9bb601e7c8-df4bc15423.zip new file mode 100644 index 000000000000..80a310982743 Binary files /dev/null and b/.yarn/cache/aria-hidden-npm-1.2.4-9bb601e7c8-df4bc15423.zip differ diff --git a/.yarn/cache/aria-query-npm-5.1.3-9632eccdee-e5da608a7c.zip b/.yarn/cache/aria-query-npm-5.1.3-9632eccdee-e5da608a7c.zip new file mode 100644 index 000000000000..af4be143fd03 Binary files /dev/null and b/.yarn/cache/aria-query-npm-5.1.3-9632eccdee-e5da608a7c.zip differ diff --git a/.yarn/cache/array-buffer-byte-length-npm-1.0.1-e7afc30010-53524e08f4.zip b/.yarn/cache/array-buffer-byte-length-npm-1.0.1-e7afc30010-53524e08f4.zip new file mode 100644 index 000000000000..8e5f04a16604 Binary files /dev/null and b/.yarn/cache/array-buffer-byte-length-npm-1.0.1-e7afc30010-53524e08f4.zip differ diff --git a/.yarn/cache/array-includes-npm-3.1.6-d0ff9d248b-a7168bd168.zip b/.yarn/cache/array-includes-npm-3.1.6-d0ff9d248b-a7168bd168.zip deleted file mode 100644 index 62107e5f28c7..000000000000 Binary files a/.yarn/cache/array-includes-npm-3.1.6-d0ff9d248b-a7168bd168.zip and /dev/null differ diff --git a/.yarn/cache/array-includes-npm-3.1.8-62a178e549-290b206c94.zip b/.yarn/cache/array-includes-npm-3.1.8-62a178e549-290b206c94.zip new file mode 100644 index 000000000000..5787b886a387 Binary files /dev/null and b/.yarn/cache/array-includes-npm-3.1.8-62a178e549-290b206c94.zip differ diff --git a/.yarn/cache/array.prototype.findlast-npm-1.2.5-316cb71d39-7dffcc665a.zip b/.yarn/cache/array.prototype.findlast-npm-1.2.5-316cb71d39-7dffcc665a.zip new file mode 100644 index 000000000000..9a7f9692a436 Binary files /dev/null and b/.yarn/cache/array.prototype.findlast-npm-1.2.5-316cb71d39-7dffcc665a.zip differ diff --git a/.yarn/cache/array.prototype.findlastindex-npm-1.2.5-f112a7bfcd-7c5c821f35.zip b/.yarn/cache/array.prototype.findlastindex-npm-1.2.5-f112a7bfcd-7c5c821f35.zip new file mode 100644 index 000000000000..5fc7f4950e37 Binary files /dev/null and b/.yarn/cache/array.prototype.findlastindex-npm-1.2.5-f112a7bfcd-7c5c821f35.zip differ diff --git a/.yarn/cache/array.prototype.flat-npm-1.3.1-e9a9e389c0-787bd3e938.zip b/.yarn/cache/array.prototype.flat-npm-1.3.1-e9a9e389c0-787bd3e938.zip deleted file mode 100644 index adf07593e79d..000000000000 Binary files a/.yarn/cache/array.prototype.flat-npm-1.3.1-e9a9e389c0-787bd3e938.zip and /dev/null differ diff --git a/.yarn/cache/array.prototype.flat-npm-1.3.2-350729f7f4-d9d2f6f275.zip b/.yarn/cache/array.prototype.flat-npm-1.3.2-350729f7f4-d9d2f6f275.zip new file mode 100644 index 000000000000..08000966f713 Binary files /dev/null and b/.yarn/cache/array.prototype.flat-npm-1.3.2-350729f7f4-d9d2f6f275.zip differ diff --git a/.yarn/cache/array.prototype.flatmap-npm-1.3.1-c65186ca34-f1f3d8e061.zip b/.yarn/cache/array.prototype.flatmap-npm-1.3.1-c65186ca34-f1f3d8e061.zip deleted file mode 100644 index 52a485d71d6c..000000000000 Binary files a/.yarn/cache/array.prototype.flatmap-npm-1.3.1-c65186ca34-f1f3d8e061.zip and /dev/null differ diff --git a/.yarn/cache/array.prototype.flatmap-npm-1.3.2-5c6a4af226-33f2000668.zip b/.yarn/cache/array.prototype.flatmap-npm-1.3.2-5c6a4af226-33f2000668.zip new file mode 100644 index 000000000000..974648a14b68 Binary files /dev/null and b/.yarn/cache/array.prototype.flatmap-npm-1.3.2-5c6a4af226-33f2000668.zip differ diff --git a/.yarn/cache/array.prototype.reduce-npm-1.0.7-68b13a3834-3a4fa56cf5.zip b/.yarn/cache/array.prototype.reduce-npm-1.0.7-68b13a3834-3a4fa56cf5.zip new file mode 100644 index 000000000000..c1d837082af5 Binary files /dev/null and b/.yarn/cache/array.prototype.reduce-npm-1.0.7-68b13a3834-3a4fa56cf5.zip differ diff --git a/.yarn/cache/array.prototype.tosorted-npm-1.1.1-1be94ad4a7-23e86074d0.zip b/.yarn/cache/array.prototype.tosorted-npm-1.1.1-1be94ad4a7-23e86074d0.zip deleted file mode 100644 index 3f7dadcde3f1..000000000000 Binary files a/.yarn/cache/array.prototype.tosorted-npm-1.1.1-1be94ad4a7-23e86074d0.zip and /dev/null differ diff --git a/.yarn/cache/array.prototype.tosorted-npm-1.1.4-c1fc919434-874694e5d5.zip b/.yarn/cache/array.prototype.tosorted-npm-1.1.4-c1fc919434-874694e5d5.zip new file mode 100644 index 000000000000..2965bf97448a Binary files /dev/null and b/.yarn/cache/array.prototype.tosorted-npm-1.1.4-c1fc919434-874694e5d5.zip differ diff --git a/.yarn/cache/arraybuffer.prototype.slice-npm-1.0.3-97a993a091-0221f16c1e.zip b/.yarn/cache/arraybuffer.prototype.slice-npm-1.0.3-97a993a091-0221f16c1e.zip new file mode 100644 index 000000000000..1f050cde14c8 Binary files /dev/null and b/.yarn/cache/arraybuffer.prototype.slice-npm-1.0.3-97a993a091-0221f16c1e.zip differ diff --git a/.yarn/cache/ast-types-flow-npm-0.0.7-7d32a3abf5-663b90e99b.zip b/.yarn/cache/ast-types-flow-npm-0.0.7-7d32a3abf5-663b90e99b.zip deleted file mode 100644 index 577160b1eacd..000000000000 Binary files a/.yarn/cache/ast-types-flow-npm-0.0.7-7d32a3abf5-663b90e99b.zip and /dev/null differ diff --git a/.yarn/cache/ast-types-flow-npm-0.0.8-d5c457c18e-85a1c24af4.zip b/.yarn/cache/ast-types-flow-npm-0.0.8-d5c457c18e-85a1c24af4.zip new file mode 100644 index 000000000000..706300b1b6d1 Binary files /dev/null and b/.yarn/cache/ast-types-flow-npm-0.0.8-d5c457c18e-85a1c24af4.zip differ diff --git a/.yarn/cache/async-npm-3.2.4-aba13508f9-bebb5dc225.zip b/.yarn/cache/async-npm-3.2.4-aba13508f9-bebb5dc225.zip deleted file mode 100644 index 0ddad0e7346b..000000000000 Binary files a/.yarn/cache/async-npm-3.2.4-aba13508f9-bebb5dc225.zip and /dev/null differ diff --git a/.yarn/cache/async-npm-3.2.5-f5dbdabdfc-323c3615c3.zip b/.yarn/cache/async-npm-3.2.5-f5dbdabdfc-323c3615c3.zip new file mode 100644 index 000000000000..ed14198e1704 Binary files /dev/null and b/.yarn/cache/async-npm-3.2.5-f5dbdabdfc-323c3615c3.zip differ diff --git a/.yarn/cache/autoprefixer-npm-10.4.19-7c86a73b2f-98378eae37.zip b/.yarn/cache/autoprefixer-npm-10.4.19-7c86a73b2f-98378eae37.zip new file mode 100644 index 000000000000..66df265d251e Binary files /dev/null and b/.yarn/cache/autoprefixer-npm-10.4.19-7c86a73b2f-98378eae37.zip differ diff --git a/.yarn/cache/autoprefixer-npm-10.4.7-463a114196-7261822bdf.zip b/.yarn/cache/autoprefixer-npm-10.4.7-463a114196-7261822bdf.zip deleted file mode 100644 index f1900d79e654..000000000000 Binary files a/.yarn/cache/autoprefixer-npm-10.4.7-463a114196-7261822bdf.zip and /dev/null differ diff --git a/.yarn/cache/available-typed-arrays-npm-1.0.5-88f321e4d3-4d4d5e86ea.zip b/.yarn/cache/available-typed-arrays-npm-1.0.5-88f321e4d3-4d4d5e86ea.zip deleted file mode 100644 index e12575572d67..000000000000 Binary files a/.yarn/cache/available-typed-arrays-npm-1.0.5-88f321e4d3-4d4d5e86ea.zip and /dev/null differ diff --git a/.yarn/cache/available-typed-arrays-npm-1.0.7-e5e5d79687-6c9da3a66c.zip b/.yarn/cache/available-typed-arrays-npm-1.0.7-e5e5d79687-6c9da3a66c.zip new file mode 100644 index 000000000000..330a85719f2e Binary files /dev/null and b/.yarn/cache/available-typed-arrays-npm-1.0.7-e5e5d79687-6c9da3a66c.zip differ diff --git a/.yarn/cache/axe-core-npm-4.10.0-90ec287b5d-6158489a7a.zip b/.yarn/cache/axe-core-npm-4.10.0-90ec287b5d-6158489a7a.zip new file mode 100644 index 000000000000..f299e54ac344 Binary files /dev/null and b/.yarn/cache/axe-core-npm-4.10.0-90ec287b5d-6158489a7a.zip differ diff --git a/.yarn/cache/axe-core-npm-4.6.3-9dbbe807a0-280f6a7067.zip b/.yarn/cache/axe-core-npm-4.6.3-9dbbe807a0-280f6a7067.zip deleted file mode 100644 index 001ddcabd533..000000000000 Binary files a/.yarn/cache/axe-core-npm-4.6.3-9dbbe807a0-280f6a7067.zip and /dev/null differ diff --git a/.yarn/cache/axios-npm-0.21.1-d192f6b3b3-271afc6138.zip b/.yarn/cache/axios-npm-0.21.1-d192f6b3b3-271afc6138.zip deleted file mode 100644 index 3bcc054f58af..000000000000 Binary files a/.yarn/cache/axios-npm-0.21.1-d192f6b3b3-271afc6138.zip and /dev/null differ diff --git a/.yarn/cache/babel-jest-npm-28.1.0-a0908fd547-1d69933453.zip b/.yarn/cache/babel-jest-npm-28.1.0-a0908fd547-1d69933453.zip deleted file mode 100644 index 1e6c4e064ae4..000000000000 Binary files a/.yarn/cache/babel-jest-npm-28.1.0-a0908fd547-1d69933453.zip and /dev/null differ diff --git a/.yarn/cache/babel-jest-npm-28.1.3-3bb56d0efd-6dcbf194a0.zip b/.yarn/cache/babel-jest-npm-28.1.3-3bb56d0efd-6dcbf194a0.zip new file mode 100644 index 000000000000..650b530e9081 Binary files /dev/null and b/.yarn/cache/babel-jest-npm-28.1.3-3bb56d0efd-6dcbf194a0.zip differ diff --git a/.yarn/cache/babel-loader-npm-8.3.0-a5239d7ed2-e775e96f60.zip b/.yarn/cache/babel-loader-npm-8.3.0-a5239d7ed2-e775e96f60.zip new file mode 100644 index 000000000000..e73364ca5aea Binary files /dev/null and b/.yarn/cache/babel-loader-npm-8.3.0-a5239d7ed2-e775e96f60.zip differ diff --git a/.yarn/cache/babel-plugin-jest-hoist-npm-28.0.2-2fdcf35bda-9547c7d735.zip b/.yarn/cache/babel-plugin-jest-hoist-npm-28.0.2-2fdcf35bda-9547c7d735.zip deleted file mode 100644 index 9be3bb764bb5..000000000000 Binary files a/.yarn/cache/babel-plugin-jest-hoist-npm-28.0.2-2fdcf35bda-9547c7d735.zip and /dev/null differ diff --git a/.yarn/cache/babel-plugin-jest-hoist-npm-28.1.3-ffadc60ff3-355e383dae.zip b/.yarn/cache/babel-plugin-jest-hoist-npm-28.1.3-ffadc60ff3-355e383dae.zip new file mode 100644 index 000000000000..e2bd2702a11c Binary files /dev/null and b/.yarn/cache/babel-plugin-jest-hoist-npm-28.1.3-ffadc60ff3-355e383dae.zip differ diff --git a/.yarn/cache/babel-preset-jest-npm-28.0.2-fa8c76021a-1e17c5a2fc.zip b/.yarn/cache/babel-preset-jest-npm-28.0.2-fa8c76021a-1e17c5a2fc.zip deleted file mode 100644 index 469f2401ba6e..000000000000 Binary files a/.yarn/cache/babel-preset-jest-npm-28.0.2-fa8c76021a-1e17c5a2fc.zip and /dev/null differ diff --git a/.yarn/cache/babel-preset-jest-npm-28.1.3-8e610faead-8248a4a5ca.zip b/.yarn/cache/babel-preset-jest-npm-28.1.3-8e610faead-8248a4a5ca.zip new file mode 100644 index 000000000000..72ed52192063 Binary files /dev/null and b/.yarn/cache/babel-preset-jest-npm-28.1.3-8e610faead-8248a4a5ca.zip differ diff --git a/.yarn/cache/balanced-match-npm-1.0.0-951a2ad706-9b67bfe558.zip b/.yarn/cache/balanced-match-npm-1.0.0-951a2ad706-9b67bfe558.zip deleted file mode 100644 index 23c098323181..000000000000 Binary files a/.yarn/cache/balanced-match-npm-1.0.0-951a2ad706-9b67bfe558.zip and /dev/null differ diff --git a/.yarn/cache/balanced-match-npm-1.0.2-a53c126459-9706c088a2.zip b/.yarn/cache/balanced-match-npm-1.0.2-a53c126459-9706c088a2.zip new file mode 100644 index 000000000000..0693b6d7be2d Binary files /dev/null and b/.yarn/cache/balanced-match-npm-1.0.2-a53c126459-9706c088a2.zip differ diff --git a/.yarn/cache/basic-ftp-npm-5.0.5-4f7972e368-3dc56b2092.zip b/.yarn/cache/basic-ftp-npm-5.0.5-4f7972e368-3dc56b2092.zip new file mode 100644 index 000000000000..d95b407f6947 Binary files /dev/null and b/.yarn/cache/basic-ftp-npm-5.0.5-4f7972e368-3dc56b2092.zip differ diff --git a/.yarn/cache/before-after-hook-npm-2.2.2-b463f0552f-34c190def5.zip b/.yarn/cache/before-after-hook-npm-2.2.2-b463f0552f-34c190def5.zip deleted file mode 100644 index 555671877b38..000000000000 Binary files a/.yarn/cache/before-after-hook-npm-2.2.2-b463f0552f-34c190def5.zip and /dev/null differ diff --git a/.yarn/cache/before-after-hook-npm-2.2.3-d79e3d6608-e676f769db.zip b/.yarn/cache/before-after-hook-npm-2.2.3-d79e3d6608-e676f769db.zip new file mode 100644 index 000000000000..9f2525b67fc6 Binary files /dev/null and b/.yarn/cache/before-after-hook-npm-2.2.3-d79e3d6608-e676f769db.zip differ diff --git a/.yarn/cache/big.js-npm-5.2.2-e147c30820-c04416aeb0.zip b/.yarn/cache/big.js-npm-5.2.2-e147c30820-c04416aeb0.zip new file mode 100644 index 000000000000..34e2a7b767c5 Binary files /dev/null and b/.yarn/cache/big.js-npm-5.2.2-e147c30820-c04416aeb0.zip differ diff --git a/.yarn/cache/bin-links-npm-4.0.4-d69a54d1b0-58d62143aa.zip b/.yarn/cache/bin-links-npm-4.0.4-d69a54d1b0-58d62143aa.zip new file mode 100644 index 000000000000..4013da42416e Binary files /dev/null and b/.yarn/cache/bin-links-npm-4.0.4-d69a54d1b0-58d62143aa.zip differ diff --git a/.yarn/cache/binary-extensions-npm-2.0.0-8343f65d59-554f65d337.zip b/.yarn/cache/binary-extensions-npm-2.0.0-8343f65d59-554f65d337.zip deleted file mode 100644 index 9cd72f8f23ce..000000000000 Binary files a/.yarn/cache/binary-extensions-npm-2.0.0-8343f65d59-554f65d337.zip and /dev/null differ diff --git a/.yarn/cache/binary-extensions-npm-2.3.0-bd3f20d865-bcad01494e.zip b/.yarn/cache/binary-extensions-npm-2.3.0-bd3f20d865-bcad01494e.zip new file mode 100644 index 000000000000..94214c4b860d Binary files /dev/null and b/.yarn/cache/binary-extensions-npm-2.3.0-bd3f20d865-bcad01494e.zip differ diff --git a/.yarn/cache/body-parser-npm-1.20.2-44738662cf-3cf171b821.zip b/.yarn/cache/body-parser-npm-1.20.2-44738662cf-3cf171b821.zip new file mode 100644 index 000000000000..0b5da1dbc98d Binary files /dev/null and b/.yarn/cache/body-parser-npm-1.20.2-44738662cf-3cf171b821.zip differ diff --git a/.yarn/cache/body-parser-npm-1.20.3-c7b184cd14-8723e3d7a6.zip b/.yarn/cache/body-parser-npm-1.20.3-c7b184cd14-8723e3d7a6.zip deleted file mode 100644 index 20637461b032..000000000000 Binary files a/.yarn/cache/body-parser-npm-1.20.3-c7b184cd14-8723e3d7a6.zip and /dev/null differ diff --git a/.yarn/cache/boundary-npm-1.0.1-584c4d130a-3168dffb1b.zip b/.yarn/cache/boundary-npm-1.0.1-584c4d130a-3168dffb1b.zip deleted file mode 100644 index 817b51cbd0ac..000000000000 Binary files a/.yarn/cache/boundary-npm-1.0.1-584c4d130a-3168dffb1b.zip and /dev/null differ diff --git a/.yarn/cache/bplist-parser-npm-0.2.0-91a681e495-15d31c1b0c.zip b/.yarn/cache/bplist-parser-npm-0.2.0-91a681e495-15d31c1b0c.zip deleted file mode 100644 index 47ebe273a4d4..000000000000 Binary files a/.yarn/cache/bplist-parser-npm-0.2.0-91a681e495-15d31c1b0c.zip and /dev/null differ diff --git a/.yarn/cache/buffer-equal-npm-1.0.0-f497e443d4-c63a62d25f.zip b/.yarn/cache/buffer-equal-npm-1.0.0-f497e443d4-c63a62d25f.zip deleted file mode 100644 index 0fbf26f045cc..000000000000 Binary files a/.yarn/cache/buffer-equal-npm-1.0.0-f497e443d4-c63a62d25f.zip and /dev/null differ diff --git a/.yarn/cache/buffer-equal-npm-1.0.1-eca4aa6d0d-0d56dbeec3.zip b/.yarn/cache/buffer-equal-npm-1.0.1-eca4aa6d0d-0d56dbeec3.zip new file mode 100644 index 000000000000..c343737b1bb1 Binary files /dev/null and b/.yarn/cache/buffer-equal-npm-1.0.1-eca4aa6d0d-0d56dbeec3.zip differ diff --git a/.yarn/cache/buffer-from-npm-1.1.1-22917b8ed8-ccc53b6973.zip b/.yarn/cache/buffer-from-npm-1.1.1-22917b8ed8-ccc53b6973.zip deleted file mode 100644 index df60234cb1e0..000000000000 Binary files a/.yarn/cache/buffer-from-npm-1.1.1-22917b8ed8-ccc53b6973.zip and /dev/null differ diff --git a/.yarn/cache/buffer-from-npm-1.1.2-03d2f20d7e-0448524a56.zip b/.yarn/cache/buffer-from-npm-1.1.2-03d2f20d7e-0448524a56.zip new file mode 100644 index 000000000000..efe1b763807f Binary files /dev/null and b/.yarn/cache/buffer-from-npm-1.1.2-03d2f20d7e-0448524a56.zip differ diff --git a/.yarn/cache/builtins-npm-1.0.3-f09d2d57f2-8f756616bd.zip b/.yarn/cache/builtins-npm-1.0.3-f09d2d57f2-8f756616bd.zip deleted file mode 100644 index d507d7705b50..000000000000 Binary files a/.yarn/cache/builtins-npm-1.0.3-f09d2d57f2-8f756616bd.zip and /dev/null differ diff --git a/.yarn/cache/builtins-npm-5.0.1-6d4820dd76-90136fa0ba.zip b/.yarn/cache/builtins-npm-5.0.1-6d4820dd76-90136fa0ba.zip deleted file mode 100644 index 48aec5e1e1e7..000000000000 Binary files a/.yarn/cache/builtins-npm-5.0.1-6d4820dd76-90136fa0ba.zip and /dev/null differ diff --git a/.yarn/cache/bundle-name-npm-3.0.0-d7e52ba2a3-edf2b1fbe6.zip b/.yarn/cache/bundle-name-npm-3.0.0-d7e52ba2a3-edf2b1fbe6.zip deleted file mode 100644 index 80f958c6728f..000000000000 Binary files a/.yarn/cache/bundle-name-npm-3.0.0-d7e52ba2a3-edf2b1fbe6.zip and /dev/null differ diff --git a/.yarn/cache/cacache-npm-16.1.3-4e2088ed0d-a14524d90e.zip b/.yarn/cache/cacache-npm-16.1.3-4e2088ed0d-a14524d90e.zip deleted file mode 100644 index 10cba98357f2..000000000000 Binary files a/.yarn/cache/cacache-npm-16.1.3-4e2088ed0d-a14524d90e.zip and /dev/null differ diff --git a/.yarn/cache/cacache-npm-17.1.3-f75f768a29-216fb41c73.zip b/.yarn/cache/cacache-npm-17.1.3-f75f768a29-216fb41c73.zip deleted file mode 100644 index c918fd16ce0f..000000000000 Binary files a/.yarn/cache/cacache-npm-17.1.3-f75f768a29-216fb41c73.zip and /dev/null differ diff --git a/.yarn/cache/cacache-npm-18.0.4-3dc4edc849-ca2f7b2d30.zip b/.yarn/cache/cacache-npm-18.0.4-3dc4edc849-ca2f7b2d30.zip new file mode 100644 index 000000000000..59cbc87d2fe6 Binary files /dev/null and b/.yarn/cache/cacache-npm-18.0.4-3dc4edc849-ca2f7b2d30.zip differ diff --git a/.yarn/cache/cacheable-request-npm-10.2.14-fd919b07d7-102f454ac6.zip b/.yarn/cache/cacheable-request-npm-10.2.14-fd919b07d7-102f454ac6.zip deleted file mode 100644 index 635136b31511..000000000000 Binary files a/.yarn/cache/cacheable-request-npm-10.2.14-fd919b07d7-102f454ac6.zip and /dev/null differ diff --git a/.yarn/cache/cacheable-request-npm-12.0.1-64bacb6bfb-91ca6f3cdc.zip b/.yarn/cache/cacheable-request-npm-12.0.1-64bacb6bfb-91ca6f3cdc.zip new file mode 100644 index 000000000000..9872e36dbda6 Binary files /dev/null and b/.yarn/cache/cacheable-request-npm-12.0.1-64bacb6bfb-91ca6f3cdc.zip differ diff --git a/.yarn/cache/caniuse-lite-npm-1.0.30001644-28dd59af35-39a55adddd.zip b/.yarn/cache/caniuse-lite-npm-1.0.30001644-28dd59af35-39a55adddd.zip new file mode 100644 index 000000000000..79c10aafc3fc Binary files /dev/null and b/.yarn/cache/caniuse-lite-npm-1.0.30001644-28dd59af35-39a55adddd.zip differ diff --git a/.yarn/cache/caniuse-lite-npm-1.0.30001653-f5f1782475-cd9b1c0fe0.zip b/.yarn/cache/caniuse-lite-npm-1.0.30001653-f5f1782475-cd9b1c0fe0.zip deleted file mode 100644 index 32907ffe79cb..000000000000 Binary files a/.yarn/cache/caniuse-lite-npm-1.0.30001653-f5f1782475-cd9b1c0fe0.zip and /dev/null differ diff --git a/.yarn/cache/ccount-npm-1.0.4-d5765a2389-14e143d557.zip b/.yarn/cache/ccount-npm-1.0.4-d5765a2389-14e143d557.zip deleted file mode 100644 index 3ef90e88da3d..000000000000 Binary files a/.yarn/cache/ccount-npm-1.0.4-d5765a2389-14e143d557.zip and /dev/null differ diff --git a/.yarn/cache/ccount-npm-1.1.0-c87febc594-b335a79d0a.zip b/.yarn/cache/ccount-npm-1.1.0-c87febc594-b335a79d0a.zip new file mode 100644 index 000000000000..3cc57262c435 Binary files /dev/null and b/.yarn/cache/ccount-npm-1.1.0-c87febc594-b335a79d0a.zip differ diff --git a/.yarn/cache/char-regex-npm-2.0.0-14d6718a7d-6084a8f0f6.zip b/.yarn/cache/char-regex-npm-2.0.0-14d6718a7d-6084a8f0f6.zip deleted file mode 100644 index ee0079cee6aa..000000000000 Binary files a/.yarn/cache/char-regex-npm-2.0.0-14d6718a7d-6084a8f0f6.zip and /dev/null differ diff --git a/.yarn/cache/char-regex-npm-2.0.1-a51fbd7459-fadd100b96.zip b/.yarn/cache/char-regex-npm-2.0.1-a51fbd7459-fadd100b96.zip new file mode 100644 index 000000000000..659779cdb65c Binary files /dev/null and b/.yarn/cache/char-regex-npm-2.0.1-a51fbd7459-fadd100b96.zip differ diff --git a/.yarn/cache/cheerio-npm-1.0.0-rc.12-6785a97c2a-812fed61aa.zip b/.yarn/cache/cheerio-npm-1.0.0-rc.12-6785a97c2a-812fed61aa.zip new file mode 100644 index 000000000000..e1ab1e0052bf Binary files /dev/null and b/.yarn/cache/cheerio-npm-1.0.0-rc.12-6785a97c2a-812fed61aa.zip differ diff --git a/.yarn/cache/cheerio-select-npm-2.1.0-e92bc2f296-b5d89208c2.zip b/.yarn/cache/cheerio-select-npm-2.1.0-e92bc2f296-b5d89208c2.zip new file mode 100644 index 000000000000..9c184dd1f7db Binary files /dev/null and b/.yarn/cache/cheerio-select-npm-2.1.0-e92bc2f296-b5d89208c2.zip differ diff --git a/.yarn/cache/chownr-npm-1.1.3-706dbfd282-898800b6ab.zip b/.yarn/cache/chownr-npm-1.1.3-706dbfd282-898800b6ab.zip deleted file mode 100644 index bd3c4c24bafc..000000000000 Binary files a/.yarn/cache/chownr-npm-1.1.3-706dbfd282-898800b6ab.zip and /dev/null differ diff --git a/.yarn/cache/chownr-npm-1.1.4-5bd400ab08-115648f8eb.zip b/.yarn/cache/chownr-npm-1.1.4-5bd400ab08-115648f8eb.zip new file mode 100644 index 000000000000..b4f504340cee Binary files /dev/null and b/.yarn/cache/chownr-npm-1.1.4-5bd400ab08-115648f8eb.zip differ diff --git a/.yarn/cache/chrome-trace-event-npm-1.0.2-c73a69cbd7-9fa8b567b9.zip b/.yarn/cache/chrome-trace-event-npm-1.0.2-c73a69cbd7-9fa8b567b9.zip deleted file mode 100644 index 8f9dd72c27ff..000000000000 Binary files a/.yarn/cache/chrome-trace-event-npm-1.0.2-c73a69cbd7-9fa8b567b9.zip and /dev/null differ diff --git a/.yarn/cache/chrome-trace-event-npm-1.0.4-4f22eb2c55-1762bed739.zip b/.yarn/cache/chrome-trace-event-npm-1.0.4-4f22eb2c55-1762bed739.zip new file mode 100644 index 000000000000..fcb322322a4d Binary files /dev/null and b/.yarn/cache/chrome-trace-event-npm-1.0.4-4f22eb2c55-1762bed739.zip differ diff --git a/.yarn/cache/chromedriver-npm-127.0.0-d436b121c8-8b56f51b79.zip b/.yarn/cache/chromedriver-npm-127.0.0-d436b121c8-8b56f51b79.zip new file mode 100644 index 000000000000..1294f4ca86fd Binary files /dev/null and b/.yarn/cache/chromedriver-npm-127.0.0-d436b121c8-8b56f51b79.zip differ diff --git a/.yarn/cache/chromedriver-npm-91.0.1-5d85da17b8-600e1fafe2.zip b/.yarn/cache/chromedriver-npm-91.0.1-5d85da17b8-600e1fafe2.zip deleted file mode 100644 index 54779e8a7869..000000000000 Binary files a/.yarn/cache/chromedriver-npm-91.0.1-5d85da17b8-600e1fafe2.zip and /dev/null differ diff --git a/.yarn/cache/ci-info-npm-4.0.0-90a0683096-c983bb7ff1.zip b/.yarn/cache/ci-info-npm-4.0.0-90a0683096-c983bb7ff1.zip new file mode 100644 index 000000000000..cdc441e0155f Binary files /dev/null and b/.yarn/cache/ci-info-npm-4.0.0-90a0683096-c983bb7ff1.zip differ diff --git a/.yarn/cache/citty-npm-0.1.6-60b76c16d8-3208947e73.zip b/.yarn/cache/citty-npm-0.1.6-60b76c16d8-3208947e73.zip new file mode 100644 index 000000000000..09f133f9e648 Binary files /dev/null and b/.yarn/cache/citty-npm-0.1.6-60b76c16d8-3208947e73.zip differ diff --git a/.yarn/cache/clean-css-npm-5.2.2-ccb3a2a994-fd018eeb81.zip b/.yarn/cache/clean-css-npm-5.2.2-ccb3a2a994-fd018eeb81.zip deleted file mode 100644 index 581e649730b8..000000000000 Binary files a/.yarn/cache/clean-css-npm-5.2.2-ccb3a2a994-fd018eeb81.zip and /dev/null differ diff --git a/.yarn/cache/clean-css-npm-5.3.3-d2bb553a94-2db1ae37b3.zip b/.yarn/cache/clean-css-npm-5.3.3-d2bb553a94-2db1ae37b3.zip new file mode 100644 index 000000000000..5945b11333fb Binary files /dev/null and b/.yarn/cache/clean-css-npm-5.3.3-d2bb553a94-2db1ae37b3.zip differ diff --git a/.yarn/cache/cli-cursor-npm-4.0.0-08e7cbaf41-ab3f3ea207.zip b/.yarn/cache/cli-cursor-npm-4.0.0-08e7cbaf41-ab3f3ea207.zip deleted file mode 100644 index 38e63c54f52f..000000000000 Binary files a/.yarn/cache/cli-cursor-npm-4.0.0-08e7cbaf41-ab3f3ea207.zip and /dev/null differ diff --git a/.yarn/cache/cli-cursor-npm-5.0.0-444bec1bef-1eb9a3f878.zip b/.yarn/cache/cli-cursor-npm-5.0.0-444bec1bef-1eb9a3f878.zip new file mode 100644 index 000000000000..e79adf695f8e Binary files /dev/null and b/.yarn/cache/cli-cursor-npm-5.0.0-444bec1bef-1eb9a3f878.zip differ diff --git a/.yarn/cache/cli-spinners-npm-2.9.2-be9c08efee-a0a863f442.zip b/.yarn/cache/cli-spinners-npm-2.9.2-be9c08efee-a0a863f442.zip new file mode 100644 index 000000000000..0a7507dd8a53 Binary files /dev/null and b/.yarn/cache/cli-spinners-npm-2.9.2-be9c08efee-a0a863f442.zip differ diff --git a/.yarn/cache/cli-truncate-npm-3.1.0-654d2989ef-c3243e4197.zip b/.yarn/cache/cli-truncate-npm-3.1.0-654d2989ef-c3243e4197.zip deleted file mode 100644 index 6ad23df2a16f..000000000000 Binary files a/.yarn/cache/cli-truncate-npm-3.1.0-654d2989ef-c3243e4197.zip and /dev/null differ diff --git a/.yarn/cache/cli-truncate-npm-4.0.0-3113917cdb-d5149175fd.zip b/.yarn/cache/cli-truncate-npm-4.0.0-3113917cdb-d5149175fd.zip new file mode 100644 index 000000000000..88229c815c13 Binary files /dev/null and b/.yarn/cache/cli-truncate-npm-4.0.0-3113917cdb-d5149175fd.zip differ diff --git a/.yarn/cache/cli-width-npm-2.2.0-0e002b49d0-05f1cf7de5.zip b/.yarn/cache/cli-width-npm-2.2.0-0e002b49d0-05f1cf7de5.zip deleted file mode 100644 index 76351a14005a..000000000000 Binary files a/.yarn/cache/cli-width-npm-2.2.0-0e002b49d0-05f1cf7de5.zip and /dev/null differ diff --git a/.yarn/cache/cli-width-npm-2.2.1-4bdb77393c-e173dbe2bb.zip b/.yarn/cache/cli-width-npm-2.2.1-4bdb77393c-e173dbe2bb.zip new file mode 100644 index 000000000000..674bb3d5458e Binary files /dev/null and b/.yarn/cache/cli-width-npm-2.2.1-4bdb77393c-e173dbe2bb.zip differ diff --git a/.yarn/cache/clipboardy-npm-2.1.0-8d8943b05c-c31abb2c3e.zip b/.yarn/cache/clipboardy-npm-2.1.0-8d8943b05c-c31abb2c3e.zip deleted file mode 100644 index fa0882b39777..000000000000 Binary files a/.yarn/cache/clipboardy-npm-2.1.0-8d8943b05c-c31abb2c3e.zip and /dev/null differ diff --git a/.yarn/cache/clipboardy-npm-2.3.0-9566d5e797-a112920915.zip b/.yarn/cache/clipboardy-npm-2.3.0-9566d5e797-a112920915.zip new file mode 100644 index 000000000000..3fc04755bd25 Binary files /dev/null and b/.yarn/cache/clipboardy-npm-2.3.0-9566d5e797-a112920915.zip differ diff --git a/.yarn/cache/clone-response-npm-1.0.2-135ae8239d-2d0e61547f.zip b/.yarn/cache/clone-response-npm-1.0.2-135ae8239d-2d0e61547f.zip deleted file mode 100644 index 5b5af5351edf..000000000000 Binary files a/.yarn/cache/clone-response-npm-1.0.2-135ae8239d-2d0e61547f.zip and /dev/null differ diff --git a/.yarn/cache/clone-response-npm-1.0.3-f71cb6aff5-4e671cac39.zip b/.yarn/cache/clone-response-npm-1.0.3-f71cb6aff5-4e671cac39.zip new file mode 100644 index 000000000000..020cff2ac25e Binary files /dev/null and b/.yarn/cache/clone-response-npm-1.0.3-f71cb6aff5-4e671cac39.zip differ diff --git a/.yarn/cache/clsx-npm-2.0.0-afafbbe44a-943766d1b0.zip b/.yarn/cache/clsx-npm-2.0.0-afafbbe44a-943766d1b0.zip deleted file mode 100644 index aa37a7c34e5f..000000000000 Binary files a/.yarn/cache/clsx-npm-2.0.0-afafbbe44a-943766d1b0.zip and /dev/null differ diff --git a/.yarn/cache/clsx-npm-2.1.1-96125b98be-cdfb57fa6c.zip b/.yarn/cache/clsx-npm-2.1.1-96125b98be-cdfb57fa6c.zip new file mode 100644 index 000000000000..74c4aaae6aec Binary files /dev/null and b/.yarn/cache/clsx-npm-2.1.1-96125b98be-cdfb57fa6c.zip differ diff --git a/.yarn/cache/cmd-shim-npm-6.0.1-87ebf774a0-d0718e4a49.zip b/.yarn/cache/cmd-shim-npm-6.0.1-87ebf774a0-d0718e4a49.zip deleted file mode 100644 index 43d25d7a1bfc..000000000000 Binary files a/.yarn/cache/cmd-shim-npm-6.0.1-87ebf774a0-d0718e4a49.zip and /dev/null differ diff --git a/.yarn/cache/cmd-shim-npm-6.0.3-88c8f0cd90-791c9779cf.zip b/.yarn/cache/cmd-shim-npm-6.0.3-88c8f0cd90-791c9779cf.zip new file mode 100644 index 000000000000..d548d601a6ff Binary files /dev/null and b/.yarn/cache/cmd-shim-npm-6.0.3-88c8f0cd90-791c9779cf.zip differ diff --git a/.yarn/cache/collect-v8-coverage-npm-1.0.0-5992a7b0f8-99d6059eb0.zip b/.yarn/cache/collect-v8-coverage-npm-1.0.0-5992a7b0f8-99d6059eb0.zip deleted file mode 100644 index 2cf7e6749c9d..000000000000 Binary files a/.yarn/cache/collect-v8-coverage-npm-1.0.0-5992a7b0f8-99d6059eb0.zip and /dev/null differ diff --git a/.yarn/cache/collect-v8-coverage-npm-1.0.2-bd20d0c572-30ea7d5c9e.zip b/.yarn/cache/collect-v8-coverage-npm-1.0.2-bd20d0c572-30ea7d5c9e.zip new file mode 100644 index 000000000000..ff7114fa0438 Binary files /dev/null and b/.yarn/cache/collect-v8-coverage-npm-1.0.2-bd20d0c572-30ea7d5c9e.zip differ diff --git a/.yarn/cache/colorette-npm-1.4.0-7e94b44dc3-c8d6c8c3ef.zip b/.yarn/cache/colorette-npm-1.4.0-7e94b44dc3-c8d6c8c3ef.zip new file mode 100644 index 000000000000..af41cf2027f7 Binary files /dev/null and b/.yarn/cache/colorette-npm-1.4.0-7e94b44dc3-c8d6c8c3ef.zip differ diff --git a/.yarn/cache/commander-npm-12.1.0-65c868e907-cdaeb672d9.zip b/.yarn/cache/commander-npm-12.1.0-65c868e907-cdaeb672d9.zip new file mode 100644 index 000000000000..3299aa9bd5d7 Binary files /dev/null and b/.yarn/cache/commander-npm-12.1.0-65c868e907-cdaeb672d9.zip differ diff --git a/.yarn/cache/common-ancestor-path-npm-1.0.1-27534e68da-1d2e418606.zip b/.yarn/cache/common-ancestor-path-npm-1.0.1-27534e68da-1d2e418606.zip new file mode 100644 index 000000000000..431dda39a35f Binary files /dev/null and b/.yarn/cache/common-ancestor-path-npm-1.0.1-27534e68da-1d2e418606.zip differ diff --git a/.yarn/cache/compare-versions-npm-6.1.0-43f6eabab2-20f349e7f8.zip b/.yarn/cache/compare-versions-npm-6.1.0-43f6eabab2-20f349e7f8.zip deleted file mode 100644 index 6326f605f5a6..000000000000 Binary files a/.yarn/cache/compare-versions-npm-6.1.0-43f6eabab2-20f349e7f8.zip and /dev/null differ diff --git a/.yarn/cache/compare-versions-npm-6.1.1-4b4ac16a32-9325c0fadf.zip b/.yarn/cache/compare-versions-npm-6.1.1-4b4ac16a32-9325c0fadf.zip new file mode 100644 index 000000000000..35c9137d4c5a Binary files /dev/null and b/.yarn/cache/compare-versions-npm-6.1.1-4b4ac16a32-9325c0fadf.zip differ diff --git a/.yarn/cache/compress-commons-npm-4.1.1-9ac41d7ac3-7e35816503.zip b/.yarn/cache/compress-commons-npm-4.1.1-9ac41d7ac3-7e35816503.zip deleted file mode 100644 index 14e03e0d41a2..000000000000 Binary files a/.yarn/cache/compress-commons-npm-4.1.1-9ac41d7ac3-7e35816503.zip and /dev/null differ diff --git a/.yarn/cache/compress-commons-npm-4.1.2-78ffde93d9-76fa281412.zip b/.yarn/cache/compress-commons-npm-4.1.2-78ffde93d9-76fa281412.zip new file mode 100644 index 000000000000..70d6f658eb5b Binary files /dev/null and b/.yarn/cache/compress-commons-npm-4.1.2-78ffde93d9-76fa281412.zip differ diff --git a/.yarn/cache/compute-scroll-into-view-npm-3.0.3-434f5634cf-65cbfe9ee8.zip b/.yarn/cache/compute-scroll-into-view-npm-3.0.3-434f5634cf-65cbfe9ee8.zip deleted file mode 100644 index 446e05f40c2d..000000000000 Binary files a/.yarn/cache/compute-scroll-into-view-npm-3.0.3-434f5634cf-65cbfe9ee8.zip and /dev/null differ diff --git a/.yarn/cache/compute-scroll-into-view-npm-3.1.0-14155669cf-cc5211d49b.zip b/.yarn/cache/compute-scroll-into-view-npm-3.1.0-14155669cf-cc5211d49b.zip new file mode 100644 index 000000000000..0e498f1b1017 Binary files /dev/null and b/.yarn/cache/compute-scroll-into-view-npm-3.1.0-14155669cf-cc5211d49b.zip differ diff --git a/.yarn/cache/confbox-npm-0.1.7-0fb39b2d88-3086687b9a.zip b/.yarn/cache/confbox-npm-0.1.7-0fb39b2d88-3086687b9a.zip new file mode 100644 index 000000000000..f57b035f37be Binary files /dev/null and b/.yarn/cache/confbox-npm-0.1.7-0fb39b2d88-3086687b9a.zip differ diff --git a/.yarn/cache/consola-npm-3.2.3-fb2514b783-02972dcb04.zip b/.yarn/cache/consola-npm-3.2.3-fb2514b783-02972dcb04.zip new file mode 100644 index 000000000000..5b15f1a208b0 Binary files /dev/null and b/.yarn/cache/consola-npm-3.2.3-fb2514b783-02972dcb04.zip differ diff --git a/.yarn/cache/conventional-changelog-angular-npm-6.0.0-7d83e24a10-ddc59ead53.zip b/.yarn/cache/conventional-changelog-angular-npm-6.0.0-7d83e24a10-ddc59ead53.zip deleted file mode 100644 index 3044f73a44cb..000000000000 Binary files a/.yarn/cache/conventional-changelog-angular-npm-6.0.0-7d83e24a10-ddc59ead53.zip and /dev/null differ diff --git a/.yarn/cache/conventional-changelog-writer-npm-6.0.0-164f883ecb-be8a1a4cc7.zip b/.yarn/cache/conventional-changelog-writer-npm-6.0.0-164f883ecb-be8a1a4cc7.zip deleted file mode 100644 index e2bb306361cf..000000000000 Binary files a/.yarn/cache/conventional-changelog-writer-npm-6.0.0-164f883ecb-be8a1a4cc7.zip and /dev/null differ diff --git a/.yarn/cache/conventional-changelog-writer-npm-6.0.1-11f2e19df2-9649d390b9.zip b/.yarn/cache/conventional-changelog-writer-npm-6.0.1-11f2e19df2-9649d390b9.zip new file mode 100644 index 000000000000..d9030d2f708e Binary files /dev/null and b/.yarn/cache/conventional-changelog-writer-npm-6.0.1-11f2e19df2-9649d390b9.zip differ diff --git a/.yarn/cache/core-js-compat-npm-3.37.1-51cca8bb53-30c6fdbd9f.zip b/.yarn/cache/core-js-compat-npm-3.37.1-51cca8bb53-30c6fdbd9f.zip new file mode 100644 index 000000000000..08613e590aa4 Binary files /dev/null and b/.yarn/cache/core-js-compat-npm-3.37.1-51cca8bb53-30c6fdbd9f.zip differ diff --git a/.yarn/cache/core-js-compat-npm-3.38.0-cd0aa312bc-7ebdca6b30.zip b/.yarn/cache/core-js-compat-npm-3.38.0-cd0aa312bc-7ebdca6b30.zip deleted file mode 100644 index 8726620bbb3f..000000000000 Binary files a/.yarn/cache/core-js-compat-npm-3.38.0-cd0aa312bc-7ebdca6b30.zip and /dev/null differ diff --git a/.yarn/cache/core-js-npm-2.6.11-15178ded27-4aee521824.zip b/.yarn/cache/core-js-npm-2.6.11-15178ded27-4aee521824.zip deleted file mode 100644 index 6c8bedec8a51..000000000000 Binary files a/.yarn/cache/core-js-npm-2.6.11-15178ded27-4aee521824.zip and /dev/null differ diff --git a/.yarn/cache/core-js-npm-2.6.12-0b93d77d31-7c624eb00a.zip b/.yarn/cache/core-js-npm-2.6.12-0b93d77d31-7c624eb00a.zip new file mode 100644 index 000000000000..ae1aaeda2abf Binary files /dev/null and b/.yarn/cache/core-js-npm-2.6.12-0b93d77d31-7c624eb00a.zip differ diff --git a/.yarn/cache/core-util-is-npm-1.0.3-ca74b76c90-9de8597363.zip b/.yarn/cache/core-util-is-npm-1.0.3-ca74b76c90-9de8597363.zip new file mode 100644 index 000000000000..2c844fee1b32 Binary files /dev/null and b/.yarn/cache/core-util-is-npm-1.0.3-ca74b76c90-9de8597363.zip differ diff --git a/.yarn/cache/cosmiconfig-npm-7.0.1-dd19ae2403-861bf4c2c9.zip b/.yarn/cache/cosmiconfig-npm-7.0.1-dd19ae2403-861bf4c2c9.zip deleted file mode 100644 index 1d67d580cdfb..000000000000 Binary files a/.yarn/cache/cosmiconfig-npm-7.0.1-dd19ae2403-861bf4c2c9.zip and /dev/null differ diff --git a/.yarn/cache/cosmiconfig-npm-7.1.0-13a5090bcd-03600bb387.zip b/.yarn/cache/cosmiconfig-npm-7.1.0-13a5090bcd-03600bb387.zip new file mode 100644 index 000000000000..bf5e1e375748 Binary files /dev/null and b/.yarn/cache/cosmiconfig-npm-7.1.0-13a5090bcd-03600bb387.zip differ diff --git a/.yarn/cache/cosmiconfig-npm-8.2.0-9b42f8a44e-e0b188f9a6.zip b/.yarn/cache/cosmiconfig-npm-8.2.0-9b42f8a44e-e0b188f9a6.zip deleted file mode 100644 index cff993a7ad6a..000000000000 Binary files a/.yarn/cache/cosmiconfig-npm-8.2.0-9b42f8a44e-e0b188f9a6.zip and /dev/null differ diff --git a/.yarn/cache/cosmiconfig-npm-8.3.6-a5566e2779-91d082baca.zip b/.yarn/cache/cosmiconfig-npm-8.3.6-a5566e2779-91d082baca.zip new file mode 100644 index 000000000000..64ae8327d638 Binary files /dev/null and b/.yarn/cache/cosmiconfig-npm-8.3.6-a5566e2779-91d082baca.zip differ diff --git a/.yarn/cache/crc32-stream-npm-4.0.2-32a2ec50b7-1099559283.zip b/.yarn/cache/crc32-stream-npm-4.0.2-32a2ec50b7-1099559283.zip deleted file mode 100644 index cf38addbd406..000000000000 Binary files a/.yarn/cache/crc32-stream-npm-4.0.2-32a2ec50b7-1099559283.zip and /dev/null differ diff --git a/.yarn/cache/crc32-stream-npm-4.0.3-7860b6069c-d44d0ec6f0.zip b/.yarn/cache/crc32-stream-npm-4.0.3-7860b6069c-d44d0ec6f0.zip new file mode 100644 index 000000000000..0aded5765893 Binary files /dev/null and b/.yarn/cache/crc32-stream-npm-4.0.3-7860b6069c-d44d0ec6f0.zip differ diff --git a/.yarn/cache/css-functions-list-npm-3.1.0-56c193d794-8a7c9d4ae5.zip b/.yarn/cache/css-functions-list-npm-3.1.0-56c193d794-8a7c9d4ae5.zip deleted file mode 100644 index 47371e54546a..000000000000 Binary files a/.yarn/cache/css-functions-list-npm-3.1.0-56c193d794-8a7c9d4ae5.zip and /dev/null differ diff --git a/.yarn/cache/css-functions-list-npm-3.2.2-b3f5bc8484-b8a564118b.zip b/.yarn/cache/css-functions-list-npm-3.2.2-b3f5bc8484-b8a564118b.zip new file mode 100644 index 000000000000..1c71f1d3d65a Binary files /dev/null and b/.yarn/cache/css-functions-list-npm-3.2.2-b3f5bc8484-b8a564118b.zip differ diff --git a/.yarn/cache/css-loader-npm-6.11.0-d945f9f4c0-9e3665509f.zip b/.yarn/cache/css-loader-npm-6.11.0-d945f9f4c0-9e3665509f.zip new file mode 100644 index 000000000000..f0401b495fe3 Binary files /dev/null and b/.yarn/cache/css-loader-npm-6.11.0-d945f9f4c0-9e3665509f.zip differ diff --git a/.yarn/cache/css-loader-npm-6.8.1-30d84b4cf1-f20bb2a181.zip b/.yarn/cache/css-loader-npm-6.8.1-30d84b4cf1-f20bb2a181.zip deleted file mode 100644 index b718bddb14ee..000000000000 Binary files a/.yarn/cache/css-loader-npm-6.8.1-30d84b4cf1-f20bb2a181.zip and /dev/null differ diff --git a/.yarn/cache/css-loader-npm-7.1.1-25b990b98a-435a21f195.zip b/.yarn/cache/css-loader-npm-7.1.1-25b990b98a-435a21f195.zip deleted file mode 100644 index d32a15aab9b9..000000000000 Binary files a/.yarn/cache/css-loader-npm-7.1.1-25b990b98a-435a21f195.zip and /dev/null differ diff --git a/.yarn/cache/css-loader-npm-7.1.2-7540f12884-ddde22fb10.zip b/.yarn/cache/css-loader-npm-7.1.2-7540f12884-ddde22fb10.zip new file mode 100644 index 000000000000..8183e77436d0 Binary files /dev/null and b/.yarn/cache/css-loader-npm-7.1.2-7540f12884-ddde22fb10.zip differ diff --git a/.yarn/cache/css-select-npm-4.1.3-97d7b817c1-53743b2d08.zip b/.yarn/cache/css-select-npm-4.1.3-97d7b817c1-53743b2d08.zip deleted file mode 100644 index ce603790db5c..000000000000 Binary files a/.yarn/cache/css-select-npm-4.1.3-97d7b817c1-53743b2d08.zip and /dev/null differ diff --git a/.yarn/cache/css-select-npm-4.3.0-72f53028ec-8f7310c9af.zip b/.yarn/cache/css-select-npm-4.3.0-72f53028ec-8f7310c9af.zip new file mode 100644 index 000000000000..9a3b4f17d4a6 Binary files /dev/null and b/.yarn/cache/css-select-npm-4.3.0-72f53028ec-8f7310c9af.zip differ diff --git a/.yarn/cache/css-what-npm-3.2.1-c8cafff2b6-445d94e499.zip b/.yarn/cache/css-what-npm-3.2.1-c8cafff2b6-445d94e499.zip deleted file mode 100644 index a234ee1a102a..000000000000 Binary files a/.yarn/cache/css-what-npm-3.2.1-c8cafff2b6-445d94e499.zip and /dev/null differ diff --git a/.yarn/cache/css-what-npm-3.4.2-7b91a90423-d5a5343619.zip b/.yarn/cache/css-what-npm-3.4.2-7b91a90423-d5a5343619.zip new file mode 100644 index 000000000000..51795479fe4b Binary files /dev/null and b/.yarn/cache/css-what-npm-3.4.2-7b91a90423-d5a5343619.zip differ diff --git a/.yarn/cache/css-what-npm-5.1.0-9991ae71a8-3b1f0abdf1.zip b/.yarn/cache/css-what-npm-5.1.0-9991ae71a8-3b1f0abdf1.zip deleted file mode 100644 index 844078ac53f7..000000000000 Binary files a/.yarn/cache/css-what-npm-5.1.0-9991ae71a8-3b1f0abdf1.zip and /dev/null differ diff --git a/.yarn/cache/cssnano-npm-7.0.1-5aac4eb965-595aa89f80.zip b/.yarn/cache/cssnano-npm-7.0.1-5aac4eb965-595aa89f80.zip deleted file mode 100644 index 6058202e6297..000000000000 Binary files a/.yarn/cache/cssnano-npm-7.0.1-5aac4eb965-595aa89f80.zip and /dev/null differ diff --git a/.yarn/cache/cssnano-npm-7.0.4-089b6efda5-fb73639928.zip b/.yarn/cache/cssnano-npm-7.0.4-089b6efda5-fb73639928.zip new file mode 100644 index 000000000000..94206798595f Binary files /dev/null and b/.yarn/cache/cssnano-npm-7.0.4-089b6efda5-fb73639928.zip differ diff --git a/.yarn/cache/cssnano-preset-default-npm-7.0.1-183349fe9f-025677b6e8.zip b/.yarn/cache/cssnano-preset-default-npm-7.0.1-183349fe9f-025677b6e8.zip deleted file mode 100644 index 67a5fa22b06e..000000000000 Binary files a/.yarn/cache/cssnano-preset-default-npm-7.0.1-183349fe9f-025677b6e8.zip and /dev/null differ diff --git a/.yarn/cache/cssnano-preset-default-npm-7.0.4-5f1d879528-4c0cff0491.zip b/.yarn/cache/cssnano-preset-default-npm-7.0.4-5f1d879528-4c0cff0491.zip new file mode 100644 index 000000000000..2dc5a8f2682f Binary files /dev/null and b/.yarn/cache/cssnano-preset-default-npm-7.0.4-5f1d879528-4c0cff0491.zip differ diff --git a/.yarn/cache/cssstyle-npm-4.1.0-2bda2835e6-8ca9e2d1f1.zip b/.yarn/cache/cssstyle-npm-4.1.0-2bda2835e6-8ca9e2d1f1.zip new file mode 100644 index 000000000000..a07697081dab Binary files /dev/null and b/.yarn/cache/cssstyle-npm-4.1.0-2bda2835e6-8ca9e2d1f1.zip differ diff --git a/.yarn/cache/csstype-npm-3.0.11-b49897178d-10e35e2ec9.zip b/.yarn/cache/csstype-npm-3.0.11-b49897178d-10e35e2ec9.zip deleted file mode 100644 index d9361b89d9d5..000000000000 Binary files a/.yarn/cache/csstype-npm-3.0.11-b49897178d-10e35e2ec9.zip and /dev/null differ diff --git a/.yarn/cache/csstype-npm-3.1.3-e9a1c85013-f593cce41f.zip b/.yarn/cache/csstype-npm-3.1.3-e9a1c85013-f593cce41f.zip new file mode 100644 index 000000000000..b08ed9c0d917 Binary files /dev/null and b/.yarn/cache/csstype-npm-3.1.3-e9a1c85013-f593cce41f.zip differ diff --git a/.yarn/cache/data-uri-to-buffer-npm-6.0.2-1725fff558-8b6927c33f.zip b/.yarn/cache/data-uri-to-buffer-npm-6.0.2-1725fff558-8b6927c33f.zip new file mode 100644 index 000000000000..b63db4648efd Binary files /dev/null and b/.yarn/cache/data-uri-to-buffer-npm-6.0.2-1725fff558-8b6927c33f.zip differ diff --git a/.yarn/cache/data-urls-npm-5.0.0-4b58b89bfe-5c40568c31.zip b/.yarn/cache/data-urls-npm-5.0.0-4b58b89bfe-5c40568c31.zip new file mode 100644 index 000000000000..2f5f097509cf Binary files /dev/null and b/.yarn/cache/data-urls-npm-5.0.0-4b58b89bfe-5c40568c31.zip differ diff --git a/.yarn/cache/data-view-buffer-npm-1.0.1-d911beebce-5919a39a18.zip b/.yarn/cache/data-view-buffer-npm-1.0.1-d911beebce-5919a39a18.zip new file mode 100644 index 000000000000..a210dee6fea0 Binary files /dev/null and b/.yarn/cache/data-view-buffer-npm-1.0.1-d911beebce-5919a39a18.zip differ diff --git a/.yarn/cache/data-view-byte-length-npm-1.0.1-538a9e432e-f33c65e58d.zip b/.yarn/cache/data-view-byte-length-npm-1.0.1-538a9e432e-f33c65e58d.zip new file mode 100644 index 000000000000..1062071d2e6b Binary files /dev/null and b/.yarn/cache/data-view-byte-length-npm-1.0.1-538a9e432e-f33c65e58d.zip differ diff --git a/.yarn/cache/data-view-byte-offset-npm-1.0.0-7112a24a4b-96f34f151b.zip b/.yarn/cache/data-view-byte-offset-npm-1.0.0-7112a24a4b-96f34f151b.zip new file mode 100644 index 000000000000..9e3c7737c7e2 Binary files /dev/null and b/.yarn/cache/data-view-byte-offset-npm-1.0.0-7112a24a4b-96f34f151b.zip differ diff --git a/.yarn/cache/date-fns-npm-3.0.6-5f59bceef3-4eb4c1f152.zip b/.yarn/cache/date-fns-npm-3.0.6-5f59bceef3-4eb4c1f152.zip deleted file mode 100644 index 3c30027a0f8b..000000000000 Binary files a/.yarn/cache/date-fns-npm-3.0.6-5f59bceef3-4eb4c1f152.zip and /dev/null differ diff --git a/.yarn/cache/date-fns-npm-3.6.0-e59d980978-cac35c5892.zip b/.yarn/cache/date-fns-npm-3.6.0-e59d980978-cac35c5892.zip new file mode 100644 index 000000000000..6092a7733043 Binary files /dev/null and b/.yarn/cache/date-fns-npm-3.6.0-e59d980978-cac35c5892.zip differ diff --git a/.yarn/cache/dayjs-npm-1.11.12-ce23245b6e-8ee7c1e149.zip b/.yarn/cache/dayjs-npm-1.11.12-ce23245b6e-8ee7c1e149.zip new file mode 100644 index 000000000000..4d25a34c7b5e Binary files /dev/null and b/.yarn/cache/dayjs-npm-1.11.12-ce23245b6e-8ee7c1e149.zip differ diff --git a/.yarn/cache/dayjs-npm-1.11.7-d5cd5b2919-341d7dc917.zip b/.yarn/cache/dayjs-npm-1.11.7-d5cd5b2919-341d7dc917.zip deleted file mode 100644 index 35fd22b0c2c5..000000000000 Binary files a/.yarn/cache/dayjs-npm-1.11.7-d5cd5b2919-341d7dc917.zip and /dev/null differ diff --git a/.yarn/cache/debug-npm-4.1.0-87184f7b48-41be7dbe92.zip b/.yarn/cache/debug-npm-4.1.0-87184f7b48-41be7dbe92.zip deleted file mode 100644 index 74f924e6e30f..000000000000 Binary files a/.yarn/cache/debug-npm-4.1.0-87184f7b48-41be7dbe92.zip and /dev/null differ diff --git a/.yarn/cache/debug-npm-4.3.1-22e08d605e-37b9f90428.zip b/.yarn/cache/debug-npm-4.3.1-22e08d605e-37b9f90428.zip new file mode 100644 index 000000000000..8d327cf827a9 Binary files /dev/null and b/.yarn/cache/debug-npm-4.3.1-22e08d605e-37b9f90428.zip differ diff --git a/.yarn/cache/decamelize-keys-npm-1.1.0-75168ffadd-968813219e.zip b/.yarn/cache/decamelize-keys-npm-1.1.0-75168ffadd-968813219e.zip deleted file mode 100644 index da2ccc26eecd..000000000000 Binary files a/.yarn/cache/decamelize-keys-npm-1.1.0-75168ffadd-968813219e.zip and /dev/null differ diff --git a/.yarn/cache/decamelize-keys-npm-1.1.1-4cfa36ed4b-71d5898174.zip b/.yarn/cache/decamelize-keys-npm-1.1.1-4cfa36ed4b-71d5898174.zip new file mode 100644 index 000000000000..2e9982a56301 Binary files /dev/null and b/.yarn/cache/decamelize-keys-npm-1.1.1-4cfa36ed4b-71d5898174.zip differ diff --git a/.yarn/cache/decimal.js-npm-10.3.1-797c736b6c-3570557550.zip b/.yarn/cache/decimal.js-npm-10.3.1-797c736b6c-3570557550.zip deleted file mode 100644 index 477e5d6efbec..000000000000 Binary files a/.yarn/cache/decimal.js-npm-10.3.1-797c736b6c-3570557550.zip and /dev/null differ diff --git a/.yarn/cache/decimal.js-npm-10.4.3-e7d483387c-de663a7bc4.zip b/.yarn/cache/decimal.js-npm-10.4.3-e7d483387c-de663a7bc4.zip new file mode 100644 index 000000000000..83e95f12f8a0 Binary files /dev/null and b/.yarn/cache/decimal.js-npm-10.4.3-e7d483387c-de663a7bc4.zip differ diff --git a/.yarn/cache/dedent-npm-1.5.3-123726df15-e5277f6268.zip b/.yarn/cache/dedent-npm-1.5.3-123726df15-e5277f6268.zip new file mode 100644 index 000000000000..90dbc34a2dd5 Binary files /dev/null and b/.yarn/cache/dedent-npm-1.5.3-123726df15-e5277f6268.zip differ diff --git a/.yarn/cache/deep-equal-npm-2.2.0-d9712e0040-c59f1ca675.zip b/.yarn/cache/deep-equal-npm-2.2.0-d9712e0040-c59f1ca675.zip deleted file mode 100644 index 3b1cfb0d2ee3..000000000000 Binary files a/.yarn/cache/deep-equal-npm-2.2.0-d9712e0040-c59f1ca675.zip and /dev/null differ diff --git a/.yarn/cache/deep-equal-npm-2.2.3-86cbe803a7-1ce49d0b71.zip b/.yarn/cache/deep-equal-npm-2.2.3-86cbe803a7-1ce49d0b71.zip new file mode 100644 index 000000000000..4b5f80c7e9be Binary files /dev/null and b/.yarn/cache/deep-equal-npm-2.2.3-86cbe803a7-1ce49d0b71.zip differ diff --git a/.yarn/cache/deep-is-npm-0.1.3-0941784645-dee1094e98.zip b/.yarn/cache/deep-is-npm-0.1.3-0941784645-dee1094e98.zip deleted file mode 100644 index 5ff8b8bc9fd6..000000000000 Binary files a/.yarn/cache/deep-is-npm-0.1.3-0941784645-dee1094e98.zip and /dev/null differ diff --git a/.yarn/cache/deep-is-npm-0.1.4-88938b5a67-ec12d074ae.zip b/.yarn/cache/deep-is-npm-0.1.4-88938b5a67-ec12d074ae.zip new file mode 100644 index 000000000000..cabb0513505b Binary files /dev/null and b/.yarn/cache/deep-is-npm-0.1.4-88938b5a67-ec12d074ae.zip differ diff --git a/.yarn/cache/deepmerge-npm-4.2.2-112165ced2-0e58ed14f5.zip b/.yarn/cache/deepmerge-npm-4.2.2-112165ced2-0e58ed14f5.zip deleted file mode 100644 index 13792fff10f8..000000000000 Binary files a/.yarn/cache/deepmerge-npm-4.2.2-112165ced2-0e58ed14f5.zip and /dev/null differ diff --git a/.yarn/cache/deepmerge-npm-4.3.1-4f751a0844-058d9e1b0f.zip b/.yarn/cache/deepmerge-npm-4.3.1-4f751a0844-058d9e1b0f.zip new file mode 100644 index 000000000000..cb05c8500380 Binary files /dev/null and b/.yarn/cache/deepmerge-npm-4.3.1-4f751a0844-058d9e1b0f.zip differ diff --git a/.yarn/cache/default-browser-id-npm-3.0.0-f65ceaa214-279c7ad492.zip b/.yarn/cache/default-browser-id-npm-3.0.0-f65ceaa214-279c7ad492.zip deleted file mode 100644 index 5aca3fb26070..000000000000 Binary files a/.yarn/cache/default-browser-id-npm-3.0.0-f65ceaa214-279c7ad492.zip and /dev/null differ diff --git a/.yarn/cache/default-browser-npm-4.0.0-e9e9c8aba0-40c5af9847.zip b/.yarn/cache/default-browser-npm-4.0.0-e9e9c8aba0-40c5af9847.zip deleted file mode 100644 index 956855fd94b5..000000000000 Binary files a/.yarn/cache/default-browser-npm-4.0.0-e9e9c8aba0-40c5af9847.zip and /dev/null differ diff --git a/.yarn/cache/default-gateway-npm-6.0.3-d8d9292176-126f8273ec.zip b/.yarn/cache/default-gateway-npm-6.0.3-d8d9292176-126f8273ec.zip deleted file mode 100644 index 791154108b49..000000000000 Binary files a/.yarn/cache/default-gateway-npm-6.0.3-d8d9292176-126f8273ec.zip and /dev/null differ diff --git a/.yarn/cache/defaults-npm-1.0.3-e829107b9e-96e2112da6.zip b/.yarn/cache/defaults-npm-1.0.3-e829107b9e-96e2112da6.zip deleted file mode 100644 index 0b0bc1beb0f8..000000000000 Binary files a/.yarn/cache/defaults-npm-1.0.3-e829107b9e-96e2112da6.zip and /dev/null differ diff --git a/.yarn/cache/defaults-npm-1.0.4-f3fbaf2528-3a88b7a587.zip b/.yarn/cache/defaults-npm-1.0.4-f3fbaf2528-3a88b7a587.zip new file mode 100644 index 000000000000..cbd9cc402ff2 Binary files /dev/null and b/.yarn/cache/defaults-npm-1.0.4-f3fbaf2528-3a88b7a587.zip differ diff --git a/.yarn/cache/define-properties-npm-1.2.0-3547cd0fd2-e60aee6a19.zip b/.yarn/cache/define-properties-npm-1.2.0-3547cd0fd2-e60aee6a19.zip deleted file mode 100644 index bcbfcf6e68f9..000000000000 Binary files a/.yarn/cache/define-properties-npm-1.2.0-3547cd0fd2-e60aee6a19.zip and /dev/null differ diff --git a/.yarn/cache/define-properties-npm-1.2.1-8a4d42413b-b4ccd00597.zip b/.yarn/cache/define-properties-npm-1.2.1-8a4d42413b-b4ccd00597.zip new file mode 100644 index 000000000000..b5958c58b1b9 Binary files /dev/null and b/.yarn/cache/define-properties-npm-1.2.1-8a4d42413b-b4ccd00597.zip differ diff --git a/.yarn/cache/defu-npm-6.1.2-65c0503295-5704aa6ea0.zip b/.yarn/cache/defu-npm-6.1.2-65c0503295-5704aa6ea0.zip deleted file mode 100644 index 176c1fbe32f4..000000000000 Binary files a/.yarn/cache/defu-npm-6.1.2-65c0503295-5704aa6ea0.zip and /dev/null differ diff --git a/.yarn/cache/defu-npm-6.1.4-c791c7f2cc-aeffdb4730.zip b/.yarn/cache/defu-npm-6.1.4-c791c7f2cc-aeffdb4730.zip new file mode 100644 index 000000000000..df708b6ab781 Binary files /dev/null and b/.yarn/cache/defu-npm-6.1.4-c791c7f2cc-aeffdb4730.zip differ diff --git a/.yarn/cache/degenerator-npm-5.0.1-97c678cdaf-a64fa39cdf.zip b/.yarn/cache/degenerator-npm-5.0.1-97c678cdaf-a64fa39cdf.zip new file mode 100644 index 000000000000..6eba6b78679c Binary files /dev/null and b/.yarn/cache/degenerator-npm-5.0.1-97c678cdaf-a64fa39cdf.zip differ diff --git a/.yarn/cache/del-npm-6.0.0-fb1f14b406-5742891627.zip b/.yarn/cache/del-npm-6.0.0-fb1f14b406-5742891627.zip deleted file mode 100644 index f8649b302dfa..000000000000 Binary files a/.yarn/cache/del-npm-6.0.0-fb1f14b406-5742891627.zip and /dev/null differ diff --git a/.yarn/cache/diff-sequences-npm-28.0.2-4e9e201736-4ff9a8f862.zip b/.yarn/cache/diff-sequences-npm-28.0.2-4e9e201736-4ff9a8f862.zip deleted file mode 100644 index a511a2928287..000000000000 Binary files a/.yarn/cache/diff-sequences-npm-28.0.2-4e9e201736-4ff9a8f862.zip and /dev/null differ diff --git a/.yarn/cache/diff-sequences-npm-28.1.1-70eb43c727-8975270821.zip b/.yarn/cache/diff-sequences-npm-28.1.1-70eb43c727-8975270821.zip new file mode 100644 index 000000000000..254b96cc0d32 Binary files /dev/null and b/.yarn/cache/diff-sequences-npm-28.1.1-70eb43c727-8975270821.zip differ diff --git a/.yarn/cache/doctoc-npm-2.1.0-5443fba10c-b97d1144e7.zip b/.yarn/cache/doctoc-npm-2.1.0-5443fba10c-b97d1144e7.zip deleted file mode 100644 index 5f98f71b8bb1..000000000000 Binary files a/.yarn/cache/doctoc-npm-2.1.0-5443fba10c-b97d1144e7.zip and /dev/null differ diff --git a/.yarn/cache/doctoc-npm-2.2.1-2a829d3d70-c1e4e53351.zip b/.yarn/cache/doctoc-npm-2.2.1-2a829d3d70-c1e4e53351.zip new file mode 100644 index 000000000000..98111bf5cc1e Binary files /dev/null and b/.yarn/cache/doctoc-npm-2.2.1-2a829d3d70-c1e4e53351.zip differ diff --git a/.yarn/cache/dom-accessibility-api-npm-0.6.3-0345e4dede-83d3371f82.zip b/.yarn/cache/dom-accessibility-api-npm-0.6.3-0345e4dede-83d3371f82.zip new file mode 100644 index 000000000000..0bbab47e241f Binary files /dev/null and b/.yarn/cache/dom-accessibility-api-npm-0.6.3-0345e4dede-83d3371f82.zip differ diff --git a/.yarn/cache/dom-serializer-npm-1.3.2-133de2b9ce-102ea83664.zip b/.yarn/cache/dom-serializer-npm-1.3.2-133de2b9ce-102ea83664.zip deleted file mode 100644 index 9fa68c7e36db..000000000000 Binary files a/.yarn/cache/dom-serializer-npm-1.3.2-133de2b9ce-102ea83664.zip and /dev/null differ diff --git a/.yarn/cache/dom-serializer-npm-1.4.1-ebb24349c1-53b217bcfe.zip b/.yarn/cache/dom-serializer-npm-1.4.1-ebb24349c1-53b217bcfe.zip new file mode 100644 index 000000000000..e8f186ba48fb Binary files /dev/null and b/.yarn/cache/dom-serializer-npm-1.4.1-ebb24349c1-53b217bcfe.zip differ diff --git a/.yarn/cache/domhandler-npm-3.3.0-6417f7e17e-31baccfeb2.zip b/.yarn/cache/domhandler-npm-3.3.0-6417f7e17e-31baccfeb2.zip deleted file mode 100644 index 2345f6f92e8c..000000000000 Binary files a/.yarn/cache/domhandler-npm-3.3.0-6417f7e17e-31baccfeb2.zip and /dev/null differ diff --git a/.yarn/cache/domhandler-npm-4.3.0-d142f8b6f6-9f158c0af1.zip b/.yarn/cache/domhandler-npm-4.3.0-d142f8b6f6-9f158c0af1.zip deleted file mode 100644 index c82cf8db8881..000000000000 Binary files a/.yarn/cache/domhandler-npm-4.3.0-d142f8b6f6-9f158c0af1.zip and /dev/null differ diff --git a/.yarn/cache/domhandler-npm-4.3.1-493539c1ca-e0d2af7403.zip b/.yarn/cache/domhandler-npm-4.3.1-493539c1ca-e0d2af7403.zip new file mode 100644 index 000000000000..b962a57dc622 Binary files /dev/null and b/.yarn/cache/domhandler-npm-4.3.1-493539c1ca-e0d2af7403.zip differ diff --git a/.yarn/cache/domutils-npm-3.0.1-7937818218-c0031e4bf8.zip b/.yarn/cache/domutils-npm-3.0.1-7937818218-c0031e4bf8.zip deleted file mode 100644 index e6f2dcb32f8a..000000000000 Binary files a/.yarn/cache/domutils-npm-3.0.1-7937818218-c0031e4bf8.zip and /dev/null differ diff --git a/.yarn/cache/domutils-npm-3.1.0-66c92ef7eb-9a169a6e57.zip b/.yarn/cache/domutils-npm-3.1.0-66c92ef7eb-9a169a6e57.zip new file mode 100644 index 000000000000..3fa8f274ff69 Binary files /dev/null and b/.yarn/cache/domutils-npm-3.1.0-66c92ef7eb-9a169a6e57.zip differ diff --git a/.yarn/cache/dotenv-expand-npm-10.0.0-fa5b032ad9-b41eb278bc.zip b/.yarn/cache/dotenv-expand-npm-10.0.0-fa5b032ad9-b41eb278bc.zip deleted file mode 100644 index 4da26c95d8a3..000000000000 Binary files a/.yarn/cache/dotenv-expand-npm-10.0.0-fa5b032ad9-b41eb278bc.zip and /dev/null differ diff --git a/.yarn/cache/dotenv-expand-npm-11.0.6-bb141097d1-8912aba44c.zip b/.yarn/cache/dotenv-expand-npm-11.0.6-bb141097d1-8912aba44c.zip new file mode 100644 index 000000000000..f5ff612a8757 Binary files /dev/null and b/.yarn/cache/dotenv-expand-npm-11.0.6-bb141097d1-8912aba44c.zip differ diff --git a/.yarn/cache/dotenv-npm-16.3.1-e6d380a398-dbb778237e.zip b/.yarn/cache/dotenv-npm-16.3.1-e6d380a398-dbb778237e.zip deleted file mode 100644 index 592331adb3a7..000000000000 Binary files a/.yarn/cache/dotenv-npm-16.3.1-e6d380a398-dbb778237e.zip and /dev/null differ diff --git a/.yarn/cache/duplexer3-npm-0.1.4-361a33d994-2f8e9d93d0.zip b/.yarn/cache/duplexer3-npm-0.1.4-361a33d994-2f8e9d93d0.zip deleted file mode 100644 index 74bd9b31d3ae..000000000000 Binary files a/.yarn/cache/duplexer3-npm-0.1.4-361a33d994-2f8e9d93d0.zip and /dev/null differ diff --git a/.yarn/cache/duplexer3-npm-0.1.5-343d4ab7e3-e677cb4c48.zip b/.yarn/cache/duplexer3-npm-0.1.5-343d4ab7e3-e677cb4c48.zip new file mode 100644 index 000000000000..041c03e936c1 Binary files /dev/null and b/.yarn/cache/duplexer3-npm-0.1.5-343d4ab7e3-e677cb4c48.zip differ diff --git a/.yarn/cache/duplexify-npm-4.1.2-7f2140a477-eeb4f362de.zip b/.yarn/cache/duplexify-npm-4.1.2-7f2140a477-eeb4f362de.zip deleted file mode 100644 index e39b920dfe2a..000000000000 Binary files a/.yarn/cache/duplexify-npm-4.1.2-7f2140a477-eeb4f362de.zip and /dev/null differ diff --git a/.yarn/cache/duplexify-npm-4.1.3-f0053971e9-b44b98ba0f.zip b/.yarn/cache/duplexify-npm-4.1.3-f0053971e9-b44b98ba0f.zip new file mode 100644 index 000000000000..cbed2616b0b4 Binary files /dev/null and b/.yarn/cache/duplexify-npm-4.1.3-f0053971e9-b44b98ba0f.zip differ diff --git a/.yarn/cache/electron-to-chromium-npm-1.5.13-be9902b49c-b3de6dbca6.zip b/.yarn/cache/electron-to-chromium-npm-1.5.13-be9902b49c-b3de6dbca6.zip deleted file mode 100644 index dfac92cfc152..000000000000 Binary files a/.yarn/cache/electron-to-chromium-npm-1.5.13-be9902b49c-b3de6dbca6.zip and /dev/null differ diff --git a/.yarn/cache/electron-to-chromium-npm-1.5.3-3c8fe1bd43-f0cf761556.zip b/.yarn/cache/electron-to-chromium-npm-1.5.3-3c8fe1bd43-f0cf761556.zip new file mode 100644 index 000000000000..3eabf2786f2a Binary files /dev/null and b/.yarn/cache/electron-to-chromium-npm-1.5.3-3c8fe1bd43-f0cf761556.zip differ diff --git a/.yarn/cache/emoji-regex-npm-10.1.0-ce4169bfff-a06227a571.zip b/.yarn/cache/emoji-regex-npm-10.1.0-ce4169bfff-a06227a571.zip new file mode 100644 index 000000000000..d28a736d8127 Binary files /dev/null and b/.yarn/cache/emoji-regex-npm-10.1.0-ce4169bfff-a06227a571.zip differ diff --git a/.yarn/cache/emoji-regex-npm-10.3.0-0c9fc2ef7f-b9b084ebe9.zip b/.yarn/cache/emoji-regex-npm-10.3.0-0c9fc2ef7f-b9b084ebe9.zip new file mode 100644 index 000000000000..3a3a8b9c051d Binary files /dev/null and b/.yarn/cache/emoji-regex-npm-10.3.0-0c9fc2ef7f-b9b084ebe9.zip differ diff --git a/.yarn/cache/emoji-regex-npm-6.1.3-b537cfd5fa-348c4808cd.zip b/.yarn/cache/emoji-regex-npm-6.1.3-b537cfd5fa-348c4808cd.zip deleted file mode 100644 index d36090c6e213..000000000000 Binary files a/.yarn/cache/emoji-regex-npm-6.1.3-b537cfd5fa-348c4808cd.zip and /dev/null differ diff --git a/.yarn/cache/emoji-regex-npm-7.0.3-cfe9479bb3-9159b2228b.zip b/.yarn/cache/emoji-regex-npm-7.0.3-cfe9479bb3-9159b2228b.zip deleted file mode 100644 index 22e27d234b19..000000000000 Binary files a/.yarn/cache/emoji-regex-npm-7.0.3-cfe9479bb3-9159b2228b.zip and /dev/null differ diff --git a/.yarn/cache/emojis-list-npm-3.0.0-7faa48e6fd-114f47d6d4.zip b/.yarn/cache/emojis-list-npm-3.0.0-7faa48e6fd-114f47d6d4.zip new file mode 100644 index 000000000000..3d306eceac46 Binary files /dev/null and b/.yarn/cache/emojis-list-npm-3.0.0-7faa48e6fd-114f47d6d4.zip differ diff --git a/.yarn/cache/encodeurl-npm-2.0.0-3660bcc92a-abf5cd51b7.zip b/.yarn/cache/encodeurl-npm-2.0.0-3660bcc92a-abf5cd51b7.zip deleted file mode 100644 index 2a60a778602c..000000000000 Binary files a/.yarn/cache/encodeurl-npm-2.0.0-3660bcc92a-abf5cd51b7.zip and /dev/null differ diff --git a/.yarn/cache/entities-npm-2.1.0-b27b8aebc6-fe71642e42.zip b/.yarn/cache/entities-npm-2.1.0-b27b8aebc6-fe71642e42.zip deleted file mode 100644 index da134c5c9b31..000000000000 Binary files a/.yarn/cache/entities-npm-2.1.0-b27b8aebc6-fe71642e42.zip and /dev/null differ diff --git a/.yarn/cache/entities-npm-2.2.0-0fc8d5b2f7-2c765221ee.zip b/.yarn/cache/entities-npm-2.2.0-0fc8d5b2f7-2c765221ee.zip new file mode 100644 index 000000000000..399a938a64dc Binary files /dev/null and b/.yarn/cache/entities-npm-2.2.0-0fc8d5b2f7-2c765221ee.zip differ diff --git a/.yarn/cache/entities-npm-3.0.1-21eeb201ba-3706e0292e.zip b/.yarn/cache/entities-npm-3.0.1-21eeb201ba-3706e0292e.zip new file mode 100644 index 000000000000..45f0886d7578 Binary files /dev/null and b/.yarn/cache/entities-npm-3.0.1-21eeb201ba-3706e0292e.zip differ diff --git a/.yarn/cache/entities-npm-4.4.0-97635dc5cc-b627cb900e.zip b/.yarn/cache/entities-npm-4.4.0-97635dc5cc-b627cb900e.zip deleted file mode 100644 index 3bbdff6b850b..000000000000 Binary files a/.yarn/cache/entities-npm-4.4.0-97635dc5cc-b627cb900e.zip and /dev/null differ diff --git a/.yarn/cache/entities-npm-4.5.0-7cdb83b832-ede2a35c9b.zip b/.yarn/cache/entities-npm-4.5.0-7cdb83b832-ede2a35c9b.zip new file mode 100644 index 000000000000..5ccebecd08c9 Binary files /dev/null and b/.yarn/cache/entities-npm-4.5.0-7cdb83b832-ede2a35c9b.zip differ diff --git a/.yarn/cache/envinfo-npm-7.13.0-a98aeb2561-450c962053.zip b/.yarn/cache/envinfo-npm-7.13.0-a98aeb2561-450c962053.zip new file mode 100644 index 000000000000..a19718411661 Binary files /dev/null and b/.yarn/cache/envinfo-npm-7.13.0-a98aeb2561-450c962053.zip differ diff --git a/.yarn/cache/envinfo-npm-7.8.1-f320033691-e7a2d71c7d.zip b/.yarn/cache/envinfo-npm-7.8.1-f320033691-e7a2d71c7d.zip deleted file mode 100644 index 44a108bc43d8..000000000000 Binary files a/.yarn/cache/envinfo-npm-7.8.1-f320033691-e7a2d71c7d.zip and /dev/null differ diff --git a/.yarn/cache/envinfo-npm-7.9.0-f6329c04b5-737e3d21f6.zip b/.yarn/cache/envinfo-npm-7.9.0-f6329c04b5-737e3d21f6.zip deleted file mode 100644 index cba703f9effe..000000000000 Binary files a/.yarn/cache/envinfo-npm-7.9.0-f6329c04b5-737e3d21f6.zip and /dev/null differ diff --git a/.yarn/cache/environment-npm-1.1.0-3f2409b698-dd3c1b9825.zip b/.yarn/cache/environment-npm-1.1.0-3f2409b698-dd3c1b9825.zip new file mode 100644 index 000000000000..92e278781374 Binary files /dev/null and b/.yarn/cache/environment-npm-1.1.0-3f2409b698-dd3c1b9825.zip differ diff --git a/.yarn/cache/es-abstract-npm-1.21.1-28d9a4a469-065c46977c.zip b/.yarn/cache/es-abstract-npm-1.21.1-28d9a4a469-065c46977c.zip deleted file mode 100644 index acbb9cdb29db..000000000000 Binary files a/.yarn/cache/es-abstract-npm-1.21.1-28d9a4a469-065c46977c.zip and /dev/null differ diff --git a/.yarn/cache/es-abstract-npm-1.23.3-ffd85665f7-2da795a6a1.zip b/.yarn/cache/es-abstract-npm-1.23.3-ffd85665f7-2da795a6a1.zip new file mode 100644 index 000000000000..188e1ce1bcb0 Binary files /dev/null and b/.yarn/cache/es-abstract-npm-1.23.3-ffd85665f7-2da795a6a1.zip differ diff --git a/.yarn/cache/es-array-method-boxes-properly-npm-1.0.0-d4bc728109-27a8a21acf.zip b/.yarn/cache/es-array-method-boxes-properly-npm-1.0.0-d4bc728109-27a8a21acf.zip new file mode 100644 index 000000000000..06b1914a2c01 Binary files /dev/null and b/.yarn/cache/es-array-method-boxes-properly-npm-1.0.0-d4bc728109-27a8a21acf.zip differ diff --git a/.yarn/cache/es-iterator-helpers-npm-1.0.19-5a0b930ca7-980a8081cf.zip b/.yarn/cache/es-iterator-helpers-npm-1.0.19-5a0b930ca7-980a8081cf.zip new file mode 100644 index 000000000000..870481352a82 Binary files /dev/null and b/.yarn/cache/es-iterator-helpers-npm-1.0.19-5a0b930ca7-980a8081cf.zip differ diff --git a/.yarn/cache/es-object-atoms-npm-1.0.0-c5cca6d760-f8910cf477.zip b/.yarn/cache/es-object-atoms-npm-1.0.0-c5cca6d760-f8910cf477.zip new file mode 100644 index 000000000000..3c8a8dbaecf3 Binary files /dev/null and b/.yarn/cache/es-object-atoms-npm-1.0.0-c5cca6d760-f8910cf477.zip differ diff --git a/.yarn/cache/es-set-tostringtag-npm-2.0.1-c87b5de872-ec416a1294.zip b/.yarn/cache/es-set-tostringtag-npm-2.0.1-c87b5de872-ec416a1294.zip deleted file mode 100644 index af638f13cd5d..000000000000 Binary files a/.yarn/cache/es-set-tostringtag-npm-2.0.1-c87b5de872-ec416a1294.zip and /dev/null differ diff --git a/.yarn/cache/es-set-tostringtag-npm-2.0.3-8a191fed13-7227fa48a4.zip b/.yarn/cache/es-set-tostringtag-npm-2.0.3-8a191fed13-7227fa48a4.zip new file mode 100644 index 000000000000..43cd0ecd8b6f Binary files /dev/null and b/.yarn/cache/es-set-tostringtag-npm-2.0.3-8a191fed13-7227fa48a4.zip differ diff --git a/.yarn/cache/es-shim-unscopables-npm-1.0.0-06186593f1-ac2db2c70d.zip b/.yarn/cache/es-shim-unscopables-npm-1.0.0-06186593f1-ac2db2c70d.zip deleted file mode 100644 index 6ce95877de0e..000000000000 Binary files a/.yarn/cache/es-shim-unscopables-npm-1.0.0-06186593f1-ac2db2c70d.zip and /dev/null differ diff --git a/.yarn/cache/es-shim-unscopables-npm-1.0.2-a3056a4c0d-6d3bf91f65.zip b/.yarn/cache/es-shim-unscopables-npm-1.0.2-a3056a4c0d-6d3bf91f65.zip new file mode 100644 index 000000000000..bbd630abbe7e Binary files /dev/null and b/.yarn/cache/es-shim-unscopables-npm-1.0.2-a3056a4c0d-6d3bf91f65.zip differ diff --git a/.yarn/cache/esbuild-npm-0.17.19-f690397756-86ada7cad6.zip b/.yarn/cache/esbuild-npm-0.17.19-f690397756-86ada7cad6.zip deleted file mode 100644 index 0a7bebaf1e39..000000000000 Binary files a/.yarn/cache/esbuild-npm-0.17.19-f690397756-86ada7cad6.zip and /dev/null differ diff --git a/.yarn/cache/esbuild-npm-0.18.20-004a76d281-1f723ec71c.zip b/.yarn/cache/esbuild-npm-0.18.20-004a76d281-1f723ec71c.zip new file mode 100644 index 000000000000..2b0f17e21f12 Binary files /dev/null and b/.yarn/cache/esbuild-npm-0.18.20-004a76d281-1f723ec71c.zip differ diff --git a/.yarn/cache/esbuild-npm-0.23.0-176e4eb3ff-d3d91bf9ca.zip b/.yarn/cache/esbuild-npm-0.23.0-176e4eb3ff-d3d91bf9ca.zip deleted file mode 100644 index 95fc6dc92b25..000000000000 Binary files a/.yarn/cache/esbuild-npm-0.23.0-176e4eb3ff-d3d91bf9ca.zip and /dev/null differ diff --git a/.yarn/cache/esbuild-npm-0.23.1-6e231886af-f55fbd0bfb.zip b/.yarn/cache/esbuild-npm-0.23.1-6e231886af-f55fbd0bfb.zip new file mode 100644 index 000000000000..878dc5e42902 Binary files /dev/null and b/.yarn/cache/esbuild-npm-0.23.1-6e231886af-f55fbd0bfb.zip differ diff --git a/.yarn/cache/eslint-config-prettier-npm-9.0.0-8f5ce20d27-276b0b5b5b.zip b/.yarn/cache/eslint-config-prettier-npm-9.0.0-8f5ce20d27-276b0b5b5b.zip deleted file mode 100644 index 9f640f85ca5e..000000000000 Binary files a/.yarn/cache/eslint-config-prettier-npm-9.0.0-8f5ce20d27-276b0b5b5b.zip and /dev/null differ diff --git a/.yarn/cache/eslint-config-prettier-npm-9.1.0-0e1fd42d7d-411e3b3b1c.zip b/.yarn/cache/eslint-config-prettier-npm-9.1.0-0e1fd42d7d-411e3b3b1c.zip new file mode 100644 index 000000000000..6e471758be90 Binary files /dev/null and b/.yarn/cache/eslint-config-prettier-npm-9.1.0-0e1fd42d7d-411e3b3b1c.zip differ diff --git a/.yarn/cache/eslint-import-resolver-node-npm-0.3.7-65bed19543-31c6dfbd34.zip b/.yarn/cache/eslint-import-resolver-node-npm-0.3.7-65bed19543-31c6dfbd34.zip deleted file mode 100644 index 3869a765d3ef..000000000000 Binary files a/.yarn/cache/eslint-import-resolver-node-npm-0.3.7-65bed19543-31c6dfbd34.zip and /dev/null differ diff --git a/.yarn/cache/eslint-import-resolver-node-npm-0.3.9-2a426afc4b-d52e08e1d9.zip b/.yarn/cache/eslint-import-resolver-node-npm-0.3.9-2a426afc4b-d52e08e1d9.zip new file mode 100644 index 000000000000..b9ff946ab033 Binary files /dev/null and b/.yarn/cache/eslint-import-resolver-node-npm-0.3.9-2a426afc4b-d52e08e1d9.zip differ diff --git a/.yarn/cache/eslint-import-resolver-typescript-npm-3.5.5-ea69fbfbc9-e739b33203.zip b/.yarn/cache/eslint-import-resolver-typescript-npm-3.5.5-ea69fbfbc9-e739b33203.zip deleted file mode 100644 index 5609a0e71832..000000000000 Binary files a/.yarn/cache/eslint-import-resolver-typescript-npm-3.5.5-ea69fbfbc9-e739b33203.zip and /dev/null differ diff --git a/.yarn/cache/eslint-import-resolver-typescript-npm-3.6.3-dc2ee1f728-5f9956dbbd.zip b/.yarn/cache/eslint-import-resolver-typescript-npm-3.6.3-dc2ee1f728-5f9956dbbd.zip new file mode 100644 index 000000000000..5a013dc2c8d6 Binary files /dev/null and b/.yarn/cache/eslint-import-resolver-typescript-npm-3.6.3-dc2ee1f728-5f9956dbbd.zip differ diff --git a/.yarn/cache/eslint-module-utils-npm-2.7.4-a1640084cb-25527e03d4.zip b/.yarn/cache/eslint-module-utils-npm-2.7.4-a1640084cb-25527e03d4.zip deleted file mode 100644 index 5448844972de..000000000000 Binary files a/.yarn/cache/eslint-module-utils-npm-2.7.4-a1640084cb-25527e03d4.zip and /dev/null differ diff --git a/.yarn/cache/eslint-module-utils-npm-2.8.2-410ed06a22-d86a8c6747.zip b/.yarn/cache/eslint-module-utils-npm-2.8.2-410ed06a22-d86a8c6747.zip new file mode 100644 index 000000000000..d90566e0653b Binary files /dev/null and b/.yarn/cache/eslint-module-utils-npm-2.8.2-410ed06a22-d86a8c6747.zip differ diff --git a/.yarn/cache/eslint-npm-9.5.0-c1652fa321-47578c2426.zip b/.yarn/cache/eslint-npm-9.5.0-c1652fa321-47578c2426.zip deleted file mode 100644 index 79a088bd5939..000000000000 Binary files a/.yarn/cache/eslint-npm-9.5.0-c1652fa321-47578c2426.zip and /dev/null differ diff --git a/.yarn/cache/eslint-npm-9.8.0-e0df5c5fa7-b1dd864170.zip b/.yarn/cache/eslint-npm-9.8.0-e0df5c5fa7-b1dd864170.zip new file mode 100644 index 000000000000..c78534212dbf Binary files /dev/null and b/.yarn/cache/eslint-npm-9.8.0-e0df5c5fa7-b1dd864170.zip differ diff --git a/.yarn/cache/eslint-plugin-import-npm-2.27.5-35b044b26f-b8ab9521bd.zip b/.yarn/cache/eslint-plugin-import-npm-2.27.5-35b044b26f-b8ab9521bd.zip deleted file mode 100644 index 14d1f78e848a..000000000000 Binary files a/.yarn/cache/eslint-plugin-import-npm-2.27.5-35b044b26f-b8ab9521bd.zip and /dev/null differ diff --git a/.yarn/cache/eslint-plugin-import-npm-2.29.1-b94305f7dc-5865f05c38.zip b/.yarn/cache/eslint-plugin-import-npm-2.29.1-b94305f7dc-5865f05c38.zip new file mode 100644 index 000000000000..c9d786095cb5 Binary files /dev/null and b/.yarn/cache/eslint-plugin-import-npm-2.29.1-b94305f7dc-5865f05c38.zip differ diff --git a/.yarn/cache/eslint-plugin-jest-dom-npm-5.0.1-ac102ffff6-d0219c1939.zip b/.yarn/cache/eslint-plugin-jest-dom-npm-5.0.1-ac102ffff6-d0219c1939.zip deleted file mode 100644 index 31c1847c371d..000000000000 Binary files a/.yarn/cache/eslint-plugin-jest-dom-npm-5.0.1-ac102ffff6-d0219c1939.zip and /dev/null differ diff --git a/.yarn/cache/eslint-plugin-jest-dom-npm-5.4.0-e7d6b364a7-b8b0b0249d.zip b/.yarn/cache/eslint-plugin-jest-dom-npm-5.4.0-e7d6b364a7-b8b0b0249d.zip new file mode 100644 index 000000000000..012b4cdc9bab Binary files /dev/null and b/.yarn/cache/eslint-plugin-jest-dom-npm-5.4.0-e7d6b364a7-b8b0b0249d.zip differ diff --git a/.yarn/cache/eslint-plugin-jsx-a11y-npm-6.7.1-84f912ba17-b7eb451304.zip b/.yarn/cache/eslint-plugin-jsx-a11y-npm-6.7.1-84f912ba17-b7eb451304.zip deleted file mode 100644 index b65fa3c9f0a5..000000000000 Binary files a/.yarn/cache/eslint-plugin-jsx-a11y-npm-6.7.1-84f912ba17-b7eb451304.zip and /dev/null differ diff --git a/.yarn/cache/eslint-plugin-jsx-a11y-npm-6.9.0-be49ca57a2-00a854a1a1.zip b/.yarn/cache/eslint-plugin-jsx-a11y-npm-6.9.0-be49ca57a2-00a854a1a1.zip new file mode 100644 index 000000000000..6b6700b60285 Binary files /dev/null and b/.yarn/cache/eslint-plugin-jsx-a11y-npm-6.9.0-be49ca57a2-00a854a1a1.zip differ diff --git a/.yarn/cache/eslint-plugin-prettier-npm-5.0.0-2f21113cba-4ea0e5f82a.zip b/.yarn/cache/eslint-plugin-prettier-npm-5.0.0-2f21113cba-4ea0e5f82a.zip deleted file mode 100644 index 35b5713e8199..000000000000 Binary files a/.yarn/cache/eslint-plugin-prettier-npm-5.0.0-2f21113cba-4ea0e5f82a.zip and /dev/null differ diff --git a/.yarn/cache/eslint-plugin-prettier-npm-5.2.1-7057756a8d-10ddf68215.zip b/.yarn/cache/eslint-plugin-prettier-npm-5.2.1-7057756a8d-10ddf68215.zip new file mode 100644 index 000000000000..872bc240f151 Binary files /dev/null and b/.yarn/cache/eslint-plugin-prettier-npm-5.2.1-7057756a8d-10ddf68215.zip differ diff --git a/.yarn/cache/eslint-plugin-react-hooks-npm-4.6.0-b429fac07f-3c63134e05.zip b/.yarn/cache/eslint-plugin-react-hooks-npm-4.6.0-b429fac07f-3c63134e05.zip deleted file mode 100644 index dae633edde6b..000000000000 Binary files a/.yarn/cache/eslint-plugin-react-hooks-npm-4.6.0-b429fac07f-3c63134e05.zip and /dev/null differ diff --git a/.yarn/cache/eslint-plugin-react-hooks-npm-4.6.2-05bc129286-5a0680941f.zip b/.yarn/cache/eslint-plugin-react-hooks-npm-4.6.2-05bc129286-5a0680941f.zip new file mode 100644 index 000000000000..cb2aa9c7a197 Binary files /dev/null and b/.yarn/cache/eslint-plugin-react-hooks-npm-4.6.2-05bc129286-5a0680941f.zip differ diff --git a/.yarn/cache/eslint-plugin-react-npm-7.32.2-b8b92d1b99-5ca7959c85.zip b/.yarn/cache/eslint-plugin-react-npm-7.32.2-b8b92d1b99-5ca7959c85.zip deleted file mode 100644 index 1d19ba53a878..000000000000 Binary files a/.yarn/cache/eslint-plugin-react-npm-7.32.2-b8b92d1b99-5ca7959c85.zip and /dev/null differ diff --git a/.yarn/cache/eslint-plugin-react-npm-7.35.0-ce51a7759c-fa0a54f9ea.zip b/.yarn/cache/eslint-plugin-react-npm-7.35.0-ce51a7759c-fa0a54f9ea.zip new file mode 100644 index 000000000000..c421d859c639 Binary files /dev/null and b/.yarn/cache/eslint-plugin-react-npm-7.35.0-ce51a7759c-fa0a54f9ea.zip differ diff --git a/.yarn/cache/eslint-plugin-testing-library-npm-6.0.1-fcfca71813-2fff4d9a41.zip b/.yarn/cache/eslint-plugin-testing-library-npm-6.0.1-fcfca71813-2fff4d9a41.zip deleted file mode 100644 index 5102107998ee..000000000000 Binary files a/.yarn/cache/eslint-plugin-testing-library-npm-6.0.1-fcfca71813-2fff4d9a41.zip and /dev/null differ diff --git a/.yarn/cache/eslint-plugin-testing-library-npm-6.2.2-e24e9c065a-61947d0b81.zip b/.yarn/cache/eslint-plugin-testing-library-npm-6.2.2-e24e9c065a-61947d0b81.zip new file mode 100644 index 000000000000..0a44da9d9953 Binary files /dev/null and b/.yarn/cache/eslint-plugin-testing-library-npm-6.2.2-e24e9c065a-61947d0b81.zip differ diff --git a/.yarn/cache/eslint-scope-npm-7.2.0-88784f5a38-94d8942840.zip b/.yarn/cache/eslint-scope-npm-7.2.0-88784f5a38-94d8942840.zip deleted file mode 100644 index e39c6d280a32..000000000000 Binary files a/.yarn/cache/eslint-scope-npm-7.2.0-88784f5a38-94d8942840.zip and /dev/null differ diff --git a/.yarn/cache/eslint-scope-npm-7.2.2-53cb0df8e8-5c660fb905.zip b/.yarn/cache/eslint-scope-npm-7.2.2-53cb0df8e8-5c660fb905.zip new file mode 100644 index 000000000000..628d419ed063 Binary files /dev/null and b/.yarn/cache/eslint-scope-npm-7.2.2-53cb0df8e8-5c660fb905.zip differ diff --git a/.yarn/cache/eslint-scope-npm-8.0.1-20a4626de0-458513863d.zip b/.yarn/cache/eslint-scope-npm-8.0.1-20a4626de0-458513863d.zip deleted file mode 100644 index c3a483f5ee2c..000000000000 Binary files a/.yarn/cache/eslint-scope-npm-8.0.1-20a4626de0-458513863d.zip and /dev/null differ diff --git a/.yarn/cache/eslint-scope-npm-8.0.2-984149bd64-d17c2e1ff4.zip b/.yarn/cache/eslint-scope-npm-8.0.2-984149bd64-d17c2e1ff4.zip new file mode 100644 index 000000000000..8025202576a6 Binary files /dev/null and b/.yarn/cache/eslint-scope-npm-8.0.2-984149bd64-d17c2e1ff4.zip differ diff --git a/.yarn/cache/espree-npm-9.5.2-5fc9506cda-2c9d0fec9a.zip b/.yarn/cache/espree-npm-9.5.2-5fc9506cda-2c9d0fec9a.zip deleted file mode 100644 index f0f800f8c33d..000000000000 Binary files a/.yarn/cache/espree-npm-9.5.2-5fc9506cda-2c9d0fec9a.zip and /dev/null differ diff --git a/.yarn/cache/espree-npm-9.6.1-a50722a5a9-255ab260f0.zip b/.yarn/cache/espree-npm-9.6.1-a50722a5a9-255ab260f0.zip new file mode 100644 index 000000000000..9edd42d5e0dd Binary files /dev/null and b/.yarn/cache/espree-npm-9.6.1-a50722a5a9-255ab260f0.zip differ diff --git a/.yarn/cache/estree-walker-npm-0.6.1-fe92d0e1f6-b8da781503.zip b/.yarn/cache/estree-walker-npm-0.6.1-fe92d0e1f6-b8da781503.zip deleted file mode 100644 index e01bb81200ff..000000000000 Binary files a/.yarn/cache/estree-walker-npm-0.6.1-fe92d0e1f6-b8da781503.zip and /dev/null differ diff --git a/.yarn/cache/exceljs-npm-4.3.0-9a71e3a25c-1cb54d3c1c.zip b/.yarn/cache/exceljs-npm-4.3.0-9a71e3a25c-1cb54d3c1c.zip deleted file mode 100644 index ea34ae5b1ad9..000000000000 Binary files a/.yarn/cache/exceljs-npm-4.3.0-9a71e3a25c-1cb54d3c1c.zip and /dev/null differ diff --git a/.yarn/cache/exceljs-npm-4.4.0-15bcfdd142-2d31014613.zip b/.yarn/cache/exceljs-npm-4.4.0-15bcfdd142-2d31014613.zip new file mode 100644 index 000000000000..35f65f240b21 Binary files /dev/null and b/.yarn/cache/exceljs-npm-4.4.0-15bcfdd142-2d31014613.zip differ diff --git a/.yarn/cache/execa-npm-7.2.0-7797cafb24-473feff60f.zip b/.yarn/cache/execa-npm-7.2.0-7797cafb24-473feff60f.zip deleted file mode 100644 index 818fef752b03..000000000000 Binary files a/.yarn/cache/execa-npm-7.2.0-7797cafb24-473feff60f.zip and /dev/null differ diff --git a/.yarn/cache/expect-npm-28.1.0-4d2d6beaf9-895476ded0.zip b/.yarn/cache/expect-npm-28.1.0-4d2d6beaf9-895476ded0.zip deleted file mode 100644 index cb91a284c11c..000000000000 Binary files a/.yarn/cache/expect-npm-28.1.0-4d2d6beaf9-895476ded0.zip and /dev/null differ diff --git a/.yarn/cache/expect-npm-28.1.3-e3316724f1-87033c88f7.zip b/.yarn/cache/expect-npm-28.1.3-e3316724f1-87033c88f7.zip new file mode 100644 index 000000000000..c120eb16f395 Binary files /dev/null and b/.yarn/cache/expect-npm-28.1.3-e3316724f1-87033c88f7.zip differ diff --git a/.yarn/cache/expect-npm-29.7.0-62e9f7979e-63f97bc51f.zip b/.yarn/cache/expect-npm-29.7.0-62e9f7979e-63f97bc51f.zip new file mode 100644 index 000000000000..b292f78fa877 Binary files /dev/null and b/.yarn/cache/expect-npm-29.7.0-62e9f7979e-63f97bc51f.zip differ diff --git a/.yarn/cache/exponential-backoff-npm-3.1.1-04df458b30-2d9bbb6473.zip b/.yarn/cache/exponential-backoff-npm-3.1.1-04df458b30-2d9bbb6473.zip new file mode 100644 index 000000000000..8c4361661755 Binary files /dev/null and b/.yarn/cache/exponential-backoff-npm-3.1.1-04df458b30-2d9bbb6473.zip differ diff --git a/.yarn/cache/express-npm-4.19.2-f81334a22a-3fcd792536.zip b/.yarn/cache/express-npm-4.19.2-f81334a22a-3fcd792536.zip new file mode 100644 index 000000000000..310f90f2a0f2 Binary files /dev/null and b/.yarn/cache/express-npm-4.19.2-f81334a22a-3fcd792536.zip differ diff --git a/.yarn/cache/express-npm-4.20.0-a4b76bf3f8-4131f566cf.zip b/.yarn/cache/express-npm-4.20.0-a4b76bf3f8-4131f566cf.zip deleted file mode 100644 index 2616c558bc4f..000000000000 Binary files a/.yarn/cache/express-npm-4.20.0-a4b76bf3f8-4131f566cf.zip and /dev/null differ diff --git a/.yarn/cache/fast-diff-npm-1.2.0-5ba4171bb6-f62419b3d7.zip b/.yarn/cache/fast-diff-npm-1.2.0-5ba4171bb6-f62419b3d7.zip deleted file mode 100644 index b651d0321a08..000000000000 Binary files a/.yarn/cache/fast-diff-npm-1.2.0-5ba4171bb6-f62419b3d7.zip and /dev/null differ diff --git a/.yarn/cache/fast-diff-npm-1.3.0-9f19e3b743-9e57415bc6.zip b/.yarn/cache/fast-diff-npm-1.3.0-9f19e3b743-9e57415bc6.zip new file mode 100644 index 000000000000..0d23182a43a9 Binary files /dev/null and b/.yarn/cache/fast-diff-npm-1.3.0-9f19e3b743-9e57415bc6.zip differ diff --git a/.yarn/cache/fastq-npm-1.17.1-56d4554993-a443180068.zip b/.yarn/cache/fastq-npm-1.17.1-56d4554993-a443180068.zip new file mode 100644 index 000000000000..155a545ec366 Binary files /dev/null and b/.yarn/cache/fastq-npm-1.17.1-56d4554993-a443180068.zip differ diff --git a/.yarn/cache/fastq-npm-1.6.0-b53b5275fa-c4dd8630dc.zip b/.yarn/cache/fastq-npm-1.6.0-b53b5275fa-c4dd8630dc.zip deleted file mode 100644 index b61d1abebe8a..000000000000 Binary files a/.yarn/cache/fastq-npm-1.6.0-b53b5275fa-c4dd8630dc.zip and /dev/null differ diff --git a/.yarn/cache/fb-watchman-npm-2.0.1-30005d50fe-9a03efc7d4.zip b/.yarn/cache/fb-watchman-npm-2.0.1-30005d50fe-9a03efc7d4.zip deleted file mode 100644 index 37333a9401c5..000000000000 Binary files a/.yarn/cache/fb-watchman-npm-2.0.1-30005d50fe-9a03efc7d4.zip and /dev/null differ diff --git a/.yarn/cache/fb-watchman-npm-2.0.2-bcb6f8f831-4f95d336fb.zip b/.yarn/cache/fb-watchman-npm-2.0.2-bcb6f8f831-4f95d336fb.zip new file mode 100644 index 000000000000..c1ce619dde75 Binary files /dev/null and b/.yarn/cache/fb-watchman-npm-2.0.2-bcb6f8f831-4f95d336fb.zip differ diff --git a/.yarn/cache/file-entry-cache-npm-7.0.2-9ddf8eaba9-e03e99beb9.zip b/.yarn/cache/file-entry-cache-npm-7.0.2-9ddf8eaba9-e03e99beb9.zip new file mode 100644 index 000000000000..865084bd10e5 Binary files /dev/null and b/.yarn/cache/file-entry-cache-npm-7.0.2-9ddf8eaba9-e03e99beb9.zip differ diff --git a/.yarn/cache/filelist-npm-1.0.2-d98495ab20-1de9ff4fa8.zip b/.yarn/cache/filelist-npm-1.0.2-d98495ab20-1de9ff4fa8.zip deleted file mode 100644 index 487b193f53f1..000000000000 Binary files a/.yarn/cache/filelist-npm-1.0.2-d98495ab20-1de9ff4fa8.zip and /dev/null differ diff --git a/.yarn/cache/filelist-npm-1.0.4-3a835ae0a7-4b436fa944.zip b/.yarn/cache/filelist-npm-1.0.4-3a835ae0a7-4b436fa944.zip new file mode 100644 index 000000000000..186f4e23764b Binary files /dev/null and b/.yarn/cache/filelist-npm-1.0.4-3a835ae0a7-4b436fa944.zip differ diff --git a/.yarn/cache/find-up-simple-npm-1.0.0-81eb875be8-91c3d51c11.zip b/.yarn/cache/find-up-simple-npm-1.0.0-81eb875be8-91c3d51c11.zip new file mode 100644 index 000000000000..d225e3ad39ab Binary files /dev/null and b/.yarn/cache/find-up-simple-npm-1.0.0-81eb875be8-91c3d51c11.zip differ diff --git a/.yarn/cache/flat-cache-npm-3.0.4-ee77e5911e-9fe5d0cb97.zip b/.yarn/cache/flat-cache-npm-3.0.4-ee77e5911e-9fe5d0cb97.zip deleted file mode 100644 index 8fad0082303c..000000000000 Binary files a/.yarn/cache/flat-cache-npm-3.0.4-ee77e5911e-9fe5d0cb97.zip and /dev/null differ diff --git a/.yarn/cache/flat-cache-npm-3.2.0-9a887f084e-02381c6ece.zip b/.yarn/cache/flat-cache-npm-3.2.0-9a887f084e-02381c6ece.zip new file mode 100644 index 000000000000..dd4cc331b7e0 Binary files /dev/null and b/.yarn/cache/flat-cache-npm-3.2.0-9a887f084e-02381c6ece.zip differ diff --git a/.yarn/cache/flow-parser-npm-0.169.0-968646f669-132ceee319.zip b/.yarn/cache/flow-parser-npm-0.169.0-968646f669-132ceee319.zip deleted file mode 100644 index 66036e13ea2b..000000000000 Binary files a/.yarn/cache/flow-parser-npm-0.169.0-968646f669-132ceee319.zip and /dev/null differ diff --git a/.yarn/cache/flow-parser-npm-0.242.1-242aa11233-579713b596.zip b/.yarn/cache/flow-parser-npm-0.242.1-242aa11233-579713b596.zip new file mode 100644 index 000000000000..2185b455b8b7 Binary files /dev/null and b/.yarn/cache/flow-parser-npm-0.242.1-242aa11233-579713b596.zip differ diff --git a/.yarn/cache/foreground-child-npm-3.1.1-77e78ed774-087edd4485.zip b/.yarn/cache/foreground-child-npm-3.1.1-77e78ed774-087edd4485.zip deleted file mode 100644 index 748261a708e8..000000000000 Binary files a/.yarn/cache/foreground-child-npm-3.1.1-77e78ed774-087edd4485.zip and /dev/null differ diff --git a/.yarn/cache/foreground-child-npm-3.2.1-788dc2267e-77b33b3c43.zip b/.yarn/cache/foreground-child-npm-3.2.1-788dc2267e-77b33b3c43.zip new file mode 100644 index 000000000000..b0215b54f3b2 Binary files /dev/null and b/.yarn/cache/foreground-child-npm-3.2.1-788dc2267e-77b33b3c43.zip differ diff --git a/.yarn/cache/fraction.js-npm-4.2.0-28efe4afc7-8f8e3c02a4.zip b/.yarn/cache/fraction.js-npm-4.2.0-28efe4afc7-8f8e3c02a4.zip deleted file mode 100644 index 10d311cd08f4..000000000000 Binary files a/.yarn/cache/fraction.js-npm-4.2.0-28efe4afc7-8f8e3c02a4.zip and /dev/null differ diff --git a/.yarn/cache/fraction.js-npm-4.3.7-c2c7e95a8e-bb5ebcdeef.zip b/.yarn/cache/fraction.js-npm-4.3.7-c2c7e95a8e-bb5ebcdeef.zip new file mode 100644 index 000000000000..ad1e711efed5 Binary files /dev/null and b/.yarn/cache/fraction.js-npm-4.3.7-c2c7e95a8e-bb5ebcdeef.zip differ diff --git a/.yarn/cache/front-matter-npm-4.0.2-e1cc0efa69-8897a831a8.zip b/.yarn/cache/front-matter-npm-4.0.2-e1cc0efa69-8897a831a8.zip new file mode 100644 index 000000000000..28b673c743e4 Binary files /dev/null and b/.yarn/cache/front-matter-npm-4.0.2-e1cc0efa69-8897a831a8.zip differ diff --git a/.yarn/cache/fs-extra-npm-11.2.0-6783080799-0579bf6726.zip b/.yarn/cache/fs-extra-npm-11.2.0-6783080799-0579bf6726.zip new file mode 100644 index 000000000000..e4eed64e46e6 Binary files /dev/null and b/.yarn/cache/fs-extra-npm-11.2.0-6783080799-0579bf6726.zip differ diff --git a/.yarn/cache/fs-extra-npm-8.1.0-197473387f-6fb12449f5.zip b/.yarn/cache/fs-extra-npm-8.1.0-197473387f-6fb12449f5.zip new file mode 100644 index 000000000000..ff210c0895ce Binary files /dev/null and b/.yarn/cache/fs-extra-npm-8.1.0-197473387f-6fb12449f5.zip differ diff --git a/.yarn/cache/fs-minipass-npm-3.0.2-a27ef235f5-1c071b5b8f.zip b/.yarn/cache/fs-minipass-npm-3.0.2-a27ef235f5-1c071b5b8f.zip deleted file mode 100644 index 026d886e098b..000000000000 Binary files a/.yarn/cache/fs-minipass-npm-3.0.2-a27ef235f5-1c071b5b8f.zip and /dev/null differ diff --git a/.yarn/cache/fs-minipass-npm-3.0.3-d148d6ac19-af143246cf.zip b/.yarn/cache/fs-minipass-npm-3.0.3-d148d6ac19-af143246cf.zip new file mode 100644 index 000000000000..ee7e68e44f2a Binary files /dev/null and b/.yarn/cache/fs-minipass-npm-3.0.3-d148d6ac19-af143246cf.zip differ diff --git a/.yarn/cache/fs-monkey-npm-1.0.4-d8be500c32-9944223c25.zip b/.yarn/cache/fs-monkey-npm-1.0.4-d8be500c32-9944223c25.zip deleted file mode 100644 index 325bc5210213..000000000000 Binary files a/.yarn/cache/fs-monkey-npm-1.0.4-d8be500c32-9944223c25.zip and /dev/null differ diff --git a/.yarn/cache/fs-monkey-npm-1.0.6-9155bd1580-a0502a23aa.zip b/.yarn/cache/fs-monkey-npm-1.0.6-9155bd1580-a0502a23aa.zip new file mode 100644 index 000000000000..49307767675f Binary files /dev/null and b/.yarn/cache/fs-monkey-npm-1.0.6-9155bd1580-a0502a23aa.zip differ diff --git a/.yarn/cache/fsevents-npm-2.3.3-ce9fb0ffae-4c1ade961d.zip b/.yarn/cache/fsevents-npm-2.3.3-ce9fb0ffae-4c1ade961d.zip new file mode 100644 index 000000000000..7164f878b600 Binary files /dev/null and b/.yarn/cache/fsevents-npm-2.3.3-ce9fb0ffae-4c1ade961d.zip differ diff --git a/.yarn/cache/fsevents-patch-6b67494872-10.zip b/.yarn/cache/fsevents-patch-6b67494872-10.zip new file mode 100644 index 000000000000..9887ada72d9b Binary files /dev/null and b/.yarn/cache/fsevents-patch-6b67494872-10.zip differ diff --git a/.yarn/cache/function.prototype.name-npm-1.1.5-e776a642bb-5d426e5a38.zip b/.yarn/cache/function.prototype.name-npm-1.1.5-e776a642bb-5d426e5a38.zip deleted file mode 100644 index 46ce2d234f85..000000000000 Binary files a/.yarn/cache/function.prototype.name-npm-1.1.5-e776a642bb-5d426e5a38.zip and /dev/null differ diff --git a/.yarn/cache/function.prototype.name-npm-1.1.6-fd3a6a5cdd-4d40be44d4.zip b/.yarn/cache/function.prototype.name-npm-1.1.6-fd3a6a5cdd-4d40be44d4.zip new file mode 100644 index 000000000000..e9902c747e6a Binary files /dev/null and b/.yarn/cache/function.prototype.name-npm-1.1.6-fd3a6a5cdd-4d40be44d4.zip differ diff --git a/.yarn/cache/functions-have-names-npm-1.2.2-c348c7c2a0-3553a12edf.zip b/.yarn/cache/functions-have-names-npm-1.2.2-c348c7c2a0-3553a12edf.zip deleted file mode 100644 index 3d8fa3764a83..000000000000 Binary files a/.yarn/cache/functions-have-names-npm-1.2.2-c348c7c2a0-3553a12edf.zip and /dev/null differ diff --git a/.yarn/cache/functions-have-names-npm-1.2.3-e5cf1e2208-0ddfd3ed10.zip b/.yarn/cache/functions-have-names-npm-1.2.3-e5cf1e2208-0ddfd3ed10.zip new file mode 100644 index 000000000000..71d3a967e837 Binary files /dev/null and b/.yarn/cache/functions-have-names-npm-1.2.3-e5cf1e2208-0ddfd3ed10.zip differ diff --git a/.yarn/cache/gauge-npm-4.0.4-8f878385e9-09535dd53b.zip b/.yarn/cache/gauge-npm-4.0.4-8f878385e9-09535dd53b.zip deleted file mode 100644 index a4b48e73a8e7..000000000000 Binary files a/.yarn/cache/gauge-npm-4.0.4-8f878385e9-09535dd53b.zip and /dev/null differ diff --git a/.yarn/cache/get-east-asian-width-npm-1.2.0-6cd8491dbe-c9b280e7c7.zip b/.yarn/cache/get-east-asian-width-npm-1.2.0-6cd8491dbe-c9b280e7c7.zip new file mode 100644 index 000000000000..6a4d35c24f2b Binary files /dev/null and b/.yarn/cache/get-east-asian-width-npm-1.2.0-6cd8491dbe-c9b280e7c7.zip differ diff --git a/.yarn/cache/get-package-type-npm-0.1.0-6c70cdc8ab-bba0811116.zip b/.yarn/cache/get-package-type-npm-0.1.0-6c70cdc8ab-bba0811116.zip new file mode 100644 index 000000000000..3ea9023ca271 Binary files /dev/null and b/.yarn/cache/get-package-type-npm-0.1.0-6c70cdc8ab-bba0811116.zip differ diff --git a/.yarn/cache/get-stream-npm-9.0.1-2e58b883c0-ce56e6db6b.zip b/.yarn/cache/get-stream-npm-9.0.1-2e58b883c0-ce56e6db6b.zip new file mode 100644 index 000000000000..6c444ded9c00 Binary files /dev/null and b/.yarn/cache/get-stream-npm-9.0.1-2e58b883c0-ce56e6db6b.zip differ diff --git a/.yarn/cache/get-symbol-description-npm-1.0.0-9c95a4bc1f-7e5f298afe.zip b/.yarn/cache/get-symbol-description-npm-1.0.0-9c95a4bc1f-7e5f298afe.zip deleted file mode 100644 index c2382c1222a6..000000000000 Binary files a/.yarn/cache/get-symbol-description-npm-1.0.0-9c95a4bc1f-7e5f298afe.zip and /dev/null differ diff --git a/.yarn/cache/get-symbol-description-npm-1.0.2-f8c332e0b5-e1cb53bc21.zip b/.yarn/cache/get-symbol-description-npm-1.0.2-f8c332e0b5-e1cb53bc21.zip new file mode 100644 index 000000000000..3eb9b9105468 Binary files /dev/null and b/.yarn/cache/get-symbol-description-npm-1.0.2-f8c332e0b5-e1cb53bc21.zip differ diff --git a/.yarn/cache/get-tsconfig-npm-4.6.2-89eaf98a6d-b2652679bd.zip b/.yarn/cache/get-tsconfig-npm-4.6.2-89eaf98a6d-b2652679bd.zip deleted file mode 100644 index 527e1c9b2fd3..000000000000 Binary files a/.yarn/cache/get-tsconfig-npm-4.6.2-89eaf98a6d-b2652679bd.zip and /dev/null differ diff --git a/.yarn/cache/get-tsconfig-npm-4.7.6-d5dc417da7-32da95a89f.zip b/.yarn/cache/get-tsconfig-npm-4.7.6-d5dc417da7-32da95a89f.zip new file mode 100644 index 000000000000..2c8dfff78f92 Binary files /dev/null and b/.yarn/cache/get-tsconfig-npm-4.7.6-d5dc417da7-32da95a89f.zip differ diff --git a/.yarn/cache/get-uri-npm-6.0.3-48f26c742e-a807f252c9.zip b/.yarn/cache/get-uri-npm-6.0.3-48f26c742e-a807f252c9.zip new file mode 100644 index 000000000000..6ab51d726885 Binary files /dev/null and b/.yarn/cache/get-uri-npm-6.0.3-48f26c742e-a807f252c9.zip differ diff --git a/.yarn/cache/get-value-npm-2.0.6-03cd422e0a-5c3b99cb53.zip b/.yarn/cache/get-value-npm-2.0.6-03cd422e0a-5c3b99cb53.zip deleted file mode 100644 index 101e5bb883d4..000000000000 Binary files a/.yarn/cache/get-value-npm-2.0.6-03cd422e0a-5c3b99cb53.zip and /dev/null differ diff --git a/.yarn/cache/giget-npm-1.1.2-5a01fa1d39-f5080b1843.zip b/.yarn/cache/giget-npm-1.1.2-5a01fa1d39-f5080b1843.zip deleted file mode 100644 index 83ed9ece357d..000000000000 Binary files a/.yarn/cache/giget-npm-1.1.2-5a01fa1d39-f5080b1843.zip and /dev/null differ diff --git a/.yarn/cache/giget-npm-1.2.3-65f7f9d31a-85bdcf3805.zip b/.yarn/cache/giget-npm-1.2.3-65f7f9d31a-85bdcf3805.zip new file mode 100644 index 000000000000..a89062c48670 Binary files /dev/null and b/.yarn/cache/giget-npm-1.2.3-65f7f9d31a-85bdcf3805.zip differ diff --git a/.yarn/cache/git-semver-tags-npm-5.0.0-63587d8aab-8b09c68bd5.zip b/.yarn/cache/git-semver-tags-npm-5.0.0-63587d8aab-8b09c68bd5.zip deleted file mode 100644 index 86ba03996518..000000000000 Binary files a/.yarn/cache/git-semver-tags-npm-5.0.0-63587d8aab-8b09c68bd5.zip and /dev/null differ diff --git a/.yarn/cache/git-semver-tags-npm-5.0.1-e2e36d6d4c-056e34a3dd.zip b/.yarn/cache/git-semver-tags-npm-5.0.1-e2e36d6d4c-056e34a3dd.zip new file mode 100644 index 000000000000..8d41a501acc3 Binary files /dev/null and b/.yarn/cache/git-semver-tags-npm-5.0.1-e2e36d6d4c-056e34a3dd.zip differ diff --git a/.yarn/cache/git-url-parse-npm-13.1.0-724765d793-a088e9b572.zip b/.yarn/cache/git-url-parse-npm-13.1.0-724765d793-a088e9b572.zip deleted file mode 100644 index a65d235f5861..000000000000 Binary files a/.yarn/cache/git-url-parse-npm-13.1.0-724765d793-a088e9b572.zip and /dev/null differ diff --git a/.yarn/cache/git-url-parse-npm-14.0.0-7e16f727c4-c194309478.zip b/.yarn/cache/git-url-parse-npm-14.0.0-7e16f727c4-c194309478.zip new file mode 100644 index 000000000000..434adc14873e Binary files /dev/null and b/.yarn/cache/git-url-parse-npm-14.0.0-7e16f727c4-c194309478.zip differ diff --git a/.yarn/cache/glob-npm-7.1.4-8bd8317a74-776bcc3137.zip b/.yarn/cache/glob-npm-7.1.4-8bd8317a74-776bcc3137.zip deleted file mode 100644 index 37e260caa514..000000000000 Binary files a/.yarn/cache/glob-npm-7.1.4-8bd8317a74-776bcc3137.zip and /dev/null differ diff --git a/.yarn/cache/globalthis-npm-1.0.3-96cd56020d-45ae2f3b40.zip b/.yarn/cache/globalthis-npm-1.0.3-96cd56020d-45ae2f3b40.zip deleted file mode 100644 index 5f8b526ac249..000000000000 Binary files a/.yarn/cache/globalthis-npm-1.0.3-96cd56020d-45ae2f3b40.zip and /dev/null differ diff --git a/.yarn/cache/globalthis-npm-1.0.4-de22ac6193-1f1fd078fb.zip b/.yarn/cache/globalthis-npm-1.0.4-de22ac6193-1f1fd078fb.zip new file mode 100644 index 000000000000..a1b0ba8fb91c Binary files /dev/null and b/.yarn/cache/globalthis-npm-1.0.4-de22ac6193-1f1fd078fb.zip differ diff --git a/.yarn/cache/globby-npm-10.0.1-35fa2ba87a-ea724a820d.zip b/.yarn/cache/globby-npm-10.0.1-35fa2ba87a-ea724a820d.zip new file mode 100644 index 000000000000..74e0f63bc1f8 Binary files /dev/null and b/.yarn/cache/globby-npm-10.0.1-35fa2ba87a-ea724a820d.zip differ diff --git a/.yarn/cache/globby-npm-13.2.0-529cdb70b4-13a8311f01.zip b/.yarn/cache/globby-npm-13.2.0-529cdb70b4-13a8311f01.zip deleted file mode 100644 index a47fd3d05755..000000000000 Binary files a/.yarn/cache/globby-npm-13.2.0-529cdb70b4-13a8311f01.zip and /dev/null differ diff --git a/.yarn/cache/got-npm-14.0.0-d68df50f64-3afcf60c83.zip b/.yarn/cache/got-npm-14.0.0-d68df50f64-3afcf60c83.zip deleted file mode 100644 index 5d8894537605..000000000000 Binary files a/.yarn/cache/got-npm-14.0.0-d68df50f64-3afcf60c83.zip and /dev/null differ diff --git a/.yarn/cache/got-npm-14.4.2-58bd359030-4f3b37594c.zip b/.yarn/cache/got-npm-14.4.2-58bd359030-4f3b37594c.zip new file mode 100644 index 000000000000..3cd6dc4ade0e Binary files /dev/null and b/.yarn/cache/got-npm-14.4.2-58bd359030-4f3b37594c.zip differ diff --git a/.yarn/cache/graphemer-npm-1.4.0-0627732d35-6dd60dba97.zip b/.yarn/cache/graphemer-npm-1.4.0-0627732d35-6dd60dba97.zip new file mode 100644 index 000000000000..cbccd9439801 Binary files /dev/null and b/.yarn/cache/graphemer-npm-1.4.0-0627732d35-6dd60dba97.zip differ diff --git a/.yarn/cache/handlebars-npm-4.7.7-a9ccfabf80-617b1e689b.zip b/.yarn/cache/handlebars-npm-4.7.7-a9ccfabf80-617b1e689b.zip deleted file mode 100644 index 8e130ccba7b7..000000000000 Binary files a/.yarn/cache/handlebars-npm-4.7.7-a9ccfabf80-617b1e689b.zip and /dev/null differ diff --git a/.yarn/cache/handlebars-npm-4.7.8-25244c2c82-bd528f4dd1.zip b/.yarn/cache/handlebars-npm-4.7.8-25244c2c82-bd528f4dd1.zip new file mode 100644 index 000000000000..9e735fb47671 Binary files /dev/null and b/.yarn/cache/handlebars-npm-4.7.8-25244c2c82-bd528f4dd1.zip differ diff --git a/.yarn/cache/has-npm-1.0.3-b7f00631c1-a449f3185b.zip b/.yarn/cache/has-npm-1.0.3-b7f00631c1-a449f3185b.zip deleted file mode 100644 index 948b7fd545e7..000000000000 Binary files a/.yarn/cache/has-npm-1.0.3-b7f00631c1-a449f3185b.zip and /dev/null differ diff --git a/.yarn/cache/has-proto-npm-1.0.1-631ea9d820-eab2ab0ed1.zip b/.yarn/cache/has-proto-npm-1.0.1-631ea9d820-eab2ab0ed1.zip deleted file mode 100644 index 77b871df6a43..000000000000 Binary files a/.yarn/cache/has-proto-npm-1.0.1-631ea9d820-eab2ab0ed1.zip and /dev/null differ diff --git a/.yarn/cache/has-proto-npm-1.0.3-b598da2961-0b67c2c94e.zip b/.yarn/cache/has-proto-npm-1.0.3-b598da2961-0b67c2c94e.zip new file mode 100644 index 000000000000..85c55b677d91 Binary files /dev/null and b/.yarn/cache/has-proto-npm-1.0.3-b598da2961-0b67c2c94e.zip differ diff --git a/.yarn/cache/has-tostringtag-npm-1.0.0-b1fcf3ab55-95546e7132.zip b/.yarn/cache/has-tostringtag-npm-1.0.0-b1fcf3ab55-95546e7132.zip deleted file mode 100644 index 65492d74d4b0..000000000000 Binary files a/.yarn/cache/has-tostringtag-npm-1.0.0-b1fcf3ab55-95546e7132.zip and /dev/null differ diff --git a/.yarn/cache/has-tostringtag-npm-1.0.2-74a4800369-c74c5f5cee.zip b/.yarn/cache/has-tostringtag-npm-1.0.2-74a4800369-c74c5f5cee.zip new file mode 100644 index 000000000000..34191210115c Binary files /dev/null and b/.yarn/cache/has-tostringtag-npm-1.0.2-74a4800369-c74c5f5cee.zip differ diff --git a/.yarn/cache/has-value-npm-0.3.1-4a15b6c29f-29e2a1e657.zip b/.yarn/cache/has-value-npm-0.3.1-4a15b6c29f-29e2a1e657.zip deleted file mode 100644 index 8c018f17256f..000000000000 Binary files a/.yarn/cache/has-value-npm-0.3.1-4a15b6c29f-29e2a1e657.zip and /dev/null differ diff --git a/.yarn/cache/has-values-npm-0.1.4-6b4397786d-ab1c4bcaf8.zip b/.yarn/cache/has-values-npm-0.1.4-6b4397786d-ab1c4bcaf8.zip deleted file mode 100644 index 94c02ad9a81d..000000000000 Binary files a/.yarn/cache/has-values-npm-0.1.4-6b4397786d-ab1c4bcaf8.zip and /dev/null differ diff --git a/.yarn/cache/hosted-git-info-npm-2.8.5-1e85fc7ff5-75ff6ecec5.zip b/.yarn/cache/hosted-git-info-npm-2.8.5-1e85fc7ff5-75ff6ecec5.zip deleted file mode 100644 index 3ef0b257857a..000000000000 Binary files a/.yarn/cache/hosted-git-info-npm-2.8.5-1e85fc7ff5-75ff6ecec5.zip and /dev/null differ diff --git a/.yarn/cache/hosted-git-info-npm-2.8.9-62c44fa93f-96da7d4123.zip b/.yarn/cache/hosted-git-info-npm-2.8.9-62c44fa93f-96da7d4123.zip new file mode 100644 index 000000000000..2f95a7aeba9c Binary files /dev/null and b/.yarn/cache/hosted-git-info-npm-2.8.9-62c44fa93f-96da7d4123.zip differ diff --git a/.yarn/cache/hosted-git-info-npm-3.0.8-e1d95672ef-fac26fe551.zip b/.yarn/cache/hosted-git-info-npm-3.0.8-e1d95672ef-fac26fe551.zip deleted file mode 100644 index ebe4db09bb69..000000000000 Binary files a/.yarn/cache/hosted-git-info-npm-3.0.8-e1d95672ef-fac26fe551.zip and /dev/null differ diff --git a/.yarn/cache/hosted-git-info-npm-6.1.1-d57807f6a5-2e48e3fac7.zip b/.yarn/cache/hosted-git-info-npm-6.1.1-d57807f6a5-2e48e3fac7.zip deleted file mode 100644 index 981c1a7efd68..000000000000 Binary files a/.yarn/cache/hosted-git-info-npm-6.1.1-d57807f6a5-2e48e3fac7.zip and /dev/null differ diff --git a/.yarn/cache/hosted-git-info-npm-7.0.2-cd527dd33f-8f085df8a4.zip b/.yarn/cache/hosted-git-info-npm-7.0.2-cd527dd33f-8f085df8a4.zip new file mode 100644 index 000000000000..c4330120ed83 Binary files /dev/null and b/.yarn/cache/hosted-git-info-npm-7.0.2-cd527dd33f-8f085df8a4.zip differ diff --git a/.yarn/cache/html-encoding-sniffer-npm-4.0.0-5f6627070d-e86efd4932.zip b/.yarn/cache/html-encoding-sniffer-npm-4.0.0-5f6627070d-e86efd4932.zip new file mode 100644 index 000000000000..ef219f88ea10 Binary files /dev/null and b/.yarn/cache/html-encoding-sniffer-npm-4.0.0-5f6627070d-e86efd4932.zip differ diff --git a/.yarn/cache/html-escaper-npm-2.0.0-f1eee1667f-3e16f56727.zip b/.yarn/cache/html-escaper-npm-2.0.0-f1eee1667f-3e16f56727.zip deleted file mode 100644 index bccf5fe14709..000000000000 Binary files a/.yarn/cache/html-escaper-npm-2.0.0-f1eee1667f-3e16f56727.zip and /dev/null differ diff --git a/.yarn/cache/html-escaper-npm-2.0.2-38e51ef294-034d74029d.zip b/.yarn/cache/html-escaper-npm-2.0.2-38e51ef294-034d74029d.zip new file mode 100644 index 000000000000..3137a4effed3 Binary files /dev/null and b/.yarn/cache/html-escaper-npm-2.0.2-38e51ef294-034d74029d.zip differ diff --git a/.yarn/cache/html-webpack-plugin-npm-5.5.0-75c5a14e55-16b08c3284.zip b/.yarn/cache/html-webpack-plugin-npm-5.5.0-75c5a14e55-16b08c3284.zip deleted file mode 100644 index e96330987494..000000000000 Binary files a/.yarn/cache/html-webpack-plugin-npm-5.5.0-75c5a14e55-16b08c3284.zip and /dev/null differ diff --git a/.yarn/cache/html-webpack-plugin-npm-5.6.0-4225ed9587-d651f3a88a.zip b/.yarn/cache/html-webpack-plugin-npm-5.6.0-4225ed9587-d651f3a88a.zip new file mode 100644 index 000000000000..455283598255 Binary files /dev/null and b/.yarn/cache/html-webpack-plugin-npm-5.6.0-4225ed9587-d651f3a88a.zip differ diff --git a/.yarn/cache/htmlparser2-npm-4.1.0-484402b323-e8ed0d9a4c.zip b/.yarn/cache/htmlparser2-npm-4.1.0-484402b323-e8ed0d9a4c.zip deleted file mode 100644 index 35d1ff3ef6b5..000000000000 Binary files a/.yarn/cache/htmlparser2-npm-4.1.0-484402b323-e8ed0d9a4c.zip and /dev/null differ diff --git a/.yarn/cache/htmlparser2-npm-7.2.0-ec7c96986f-fd097e19c0.zip b/.yarn/cache/htmlparser2-npm-7.2.0-ec7c96986f-fd097e19c0.zip new file mode 100644 index 000000000000..da2d21c89d6e Binary files /dev/null and b/.yarn/cache/htmlparser2-npm-7.2.0-ec7c96986f-fd097e19c0.zip differ diff --git a/.yarn/cache/htmlparser2-npm-8.0.2-5d9f901bb6-ea5512956e.zip b/.yarn/cache/htmlparser2-npm-8.0.2-5d9f901bb6-ea5512956e.zip new file mode 100644 index 000000000000..15e39b3e0d67 Binary files /dev/null and b/.yarn/cache/htmlparser2-npm-8.0.2-5d9f901bb6-ea5512956e.zip differ diff --git a/.yarn/cache/http-parser-js-npm-0.5.6-6140699129-701ce58fda.zip b/.yarn/cache/http-parser-js-npm-0.5.6-6140699129-701ce58fda.zip deleted file mode 100644 index 5e5d5ffcdd2a..000000000000 Binary files a/.yarn/cache/http-parser-js-npm-0.5.6-6140699129-701ce58fda.zip and /dev/null differ diff --git a/.yarn/cache/http-parser-js-npm-0.5.8-f80208ea99-2a78a567ee.zip b/.yarn/cache/http-parser-js-npm-0.5.8-f80208ea99-2a78a567ee.zip new file mode 100644 index 000000000000..7f4c1852ac6f Binary files /dev/null and b/.yarn/cache/http-parser-js-npm-0.5.8-f80208ea99-2a78a567ee.zip differ diff --git a/.yarn/cache/http-proxy-agent-npm-7.0.2-643ed7cc33-d062acfa0c.zip b/.yarn/cache/http-proxy-agent-npm-7.0.2-643ed7cc33-d062acfa0c.zip new file mode 100644 index 000000000000..b24cf08c8fc4 Binary files /dev/null and b/.yarn/cache/http-proxy-agent-npm-7.0.2-643ed7cc33-d062acfa0c.zip differ diff --git a/.yarn/cache/https-proxy-agent-npm-7.0.5-94c14d4619-6679d46159.zip b/.yarn/cache/https-proxy-agent-npm-7.0.5-94c14d4619-6679d46159.zip new file mode 100644 index 000000000000..6307cc159b68 Binary files /dev/null and b/.yarn/cache/https-proxy-agent-npm-7.0.5-94c14d4619-6679d46159.zip differ diff --git a/.yarn/cache/human-signals-npm-4.3.1-d723001512-fa59894c35.zip b/.yarn/cache/human-signals-npm-4.3.1-d723001512-fa59894c35.zip deleted file mode 100644 index 959fac731c9f..000000000000 Binary files a/.yarn/cache/human-signals-npm-4.3.1-d723001512-fa59894c35.zip and /dev/null differ diff --git a/.yarn/cache/humanize-duration-npm-3.21.0-36954a8753-ea7d42a9e7.zip b/.yarn/cache/humanize-duration-npm-3.21.0-36954a8753-ea7d42a9e7.zip deleted file mode 100644 index 2e26030c35f3..000000000000 Binary files a/.yarn/cache/humanize-duration-npm-3.21.0-36954a8753-ea7d42a9e7.zip and /dev/null differ diff --git a/.yarn/cache/humanize-duration-npm-3.32.1-374209afec-5909107485.zip b/.yarn/cache/humanize-duration-npm-3.32.1-374209afec-5909107485.zip new file mode 100644 index 000000000000..de03e9f9a7c6 Binary files /dev/null and b/.yarn/cache/humanize-duration-npm-3.32.1-374209afec-5909107485.zip differ diff --git a/.yarn/cache/humanize-ms-npm-1.2.1-e942bd7329-9c7a74a282.zip b/.yarn/cache/humanize-ms-npm-1.2.1-e942bd7329-9c7a74a282.zip deleted file mode 100644 index c09856b33487..000000000000 Binary files a/.yarn/cache/humanize-ms-npm-1.2.1-e942bd7329-9c7a74a282.zip and /dev/null differ diff --git a/.yarn/cache/husky-npm-9.0.10-93b6062488-c303f1862e.zip b/.yarn/cache/husky-npm-9.0.10-93b6062488-c303f1862e.zip deleted file mode 100644 index 00f17c3d3a7b..000000000000 Binary files a/.yarn/cache/husky-npm-9.0.10-93b6062488-c303f1862e.zip and /dev/null differ diff --git a/.yarn/cache/husky-npm-9.1.4-45a26bd693-c43aa7cbf9.zip b/.yarn/cache/husky-npm-9.1.4-45a26bd693-c43aa7cbf9.zip new file mode 100644 index 000000000000..b2f947bcb717 Binary files /dev/null and b/.yarn/cache/husky-npm-9.1.4-45a26bd693-c43aa7cbf9.zip differ diff --git a/.yarn/cache/ignore-npm-5.2.4-fbe6e989e5-4f7caf5d20.zip b/.yarn/cache/ignore-npm-5.2.4-fbe6e989e5-4f7caf5d20.zip deleted file mode 100644 index 4392df72dc6c..000000000000 Binary files a/.yarn/cache/ignore-npm-5.2.4-fbe6e989e5-4f7caf5d20.zip and /dev/null differ diff --git a/.yarn/cache/ignore-npm-5.3.2-346d3ba017-cceb6a4570.zip b/.yarn/cache/ignore-npm-5.3.2-346d3ba017-cceb6a4570.zip new file mode 100644 index 000000000000..e7580729a887 Binary files /dev/null and b/.yarn/cache/ignore-npm-5.3.2-346d3ba017-cceb6a4570.zip differ diff --git a/.yarn/cache/ignore-walk-npm-5.0.1-58258fb4ca-a88b3fbda1.zip b/.yarn/cache/ignore-walk-npm-5.0.1-58258fb4ca-a88b3fbda1.zip deleted file mode 100644 index bc554e33eecd..000000000000 Binary files a/.yarn/cache/ignore-walk-npm-5.0.1-58258fb4ca-a88b3fbda1.zip and /dev/null differ diff --git a/.yarn/cache/ignore-walk-npm-6.0.3-ebca6b06c4-3cbc0b52c7.zip b/.yarn/cache/ignore-walk-npm-6.0.3-ebca6b06c4-3cbc0b52c7.zip deleted file mode 100644 index da91bdf46b80..000000000000 Binary files a/.yarn/cache/ignore-walk-npm-6.0.3-ebca6b06c4-3cbc0b52c7.zip and /dev/null differ diff --git a/.yarn/cache/ignore-walk-npm-6.0.5-dc11005d4e-08757abff4.zip b/.yarn/cache/ignore-walk-npm-6.0.5-dc11005d4e-08757abff4.zip new file mode 100644 index 000000000000..fc4e98b8369b Binary files /dev/null and b/.yarn/cache/ignore-walk-npm-6.0.5-dc11005d4e-08757abff4.zip differ diff --git a/.yarn/cache/image-size-npm-1.0.0-0d3b1ec70c-af55ab1285.zip b/.yarn/cache/image-size-npm-1.0.0-0d3b1ec70c-af55ab1285.zip deleted file mode 100644 index d8b3f0ee4b84..000000000000 Binary files a/.yarn/cache/image-size-npm-1.0.0-0d3b1ec70c-af55ab1285.zip and /dev/null differ diff --git a/.yarn/cache/image-size-npm-1.1.1-4e6d664667-f28966dd3f.zip b/.yarn/cache/image-size-npm-1.1.1-4e6d664667-f28966dd3f.zip new file mode 100644 index 000000000000..7b60fbb8046f Binary files /dev/null and b/.yarn/cache/image-size-npm-1.1.1-4e6d664667-f28966dd3f.zip differ diff --git a/.yarn/cache/immutable-npm-4.0.0-74b844f82e-bc8e3f46a5.zip b/.yarn/cache/immutable-npm-4.0.0-74b844f82e-bc8e3f46a5.zip deleted file mode 100644 index 26a97575a8fa..000000000000 Binary files a/.yarn/cache/immutable-npm-4.0.0-74b844f82e-bc8e3f46a5.zip and /dev/null differ diff --git a/.yarn/cache/immutable-npm-4.3.7-a76ac3621b-37d963c505.zip b/.yarn/cache/immutable-npm-4.3.7-a76ac3621b-37d963c505.zip new file mode 100644 index 000000000000..7cc8ebcc5c73 Binary files /dev/null and b/.yarn/cache/immutable-npm-4.3.7-a76ac3621b-37d963c505.zip differ diff --git a/.yarn/cache/import-local-npm-3.2.0-bf54ec7842-0b0b0b412b.zip b/.yarn/cache/import-local-npm-3.2.0-bf54ec7842-0b0b0b412b.zip new file mode 100644 index 000000000000..c9e4ee29cee6 Binary files /dev/null and b/.yarn/cache/import-local-npm-3.2.0-bf54ec7842-0b0b0b412b.zip differ diff --git a/.yarn/cache/index-to-position-npm-0.1.2-0706eaf734-ae8e2304ed.zip b/.yarn/cache/index-to-position-npm-0.1.2-0706eaf734-ae8e2304ed.zip new file mode 100644 index 000000000000..00756a75eb60 Binary files /dev/null and b/.yarn/cache/index-to-position-npm-0.1.2-0706eaf734-ae8e2304ed.zip differ diff --git a/.yarn/cache/infer-owner-npm-1.0.4-685ac3d2af-181e732764.zip b/.yarn/cache/infer-owner-npm-1.0.4-685ac3d2af-181e732764.zip deleted file mode 100644 index bdc705082a73..000000000000 Binary files a/.yarn/cache/infer-owner-npm-1.0.4-685ac3d2af-181e732764.zip and /dev/null differ diff --git a/.yarn/cache/ini-npm-4.1.3-56188f3216-f536b414d1.zip b/.yarn/cache/ini-npm-4.1.3-56188f3216-f536b414d1.zip new file mode 100644 index 000000000000..03052e8eb876 Binary files /dev/null and b/.yarn/cache/ini-npm-4.1.3-56188f3216-f536b414d1.zip differ diff --git a/.yarn/cache/init-package-json-npm-5.0.0-0656c8f580-2816821b49.zip b/.yarn/cache/init-package-json-npm-5.0.0-0656c8f580-2816821b49.zip deleted file mode 100644 index 9b58cf1b857f..000000000000 Binary files a/.yarn/cache/init-package-json-npm-5.0.0-0656c8f580-2816821b49.zip and /dev/null differ diff --git a/.yarn/cache/init-package-json-npm-6.0.3-2a9f8f943e-1274365e2c.zip b/.yarn/cache/init-package-json-npm-6.0.3-2a9f8f943e-1274365e2c.zip new file mode 100644 index 000000000000..ef6028faad7e Binary files /dev/null and b/.yarn/cache/init-package-json-npm-6.0.3-2a9f8f943e-1274365e2c.zip differ diff --git a/.yarn/cache/inquirer-npm-8.2.5-ffce7548f9-50a240dfea.zip b/.yarn/cache/inquirer-npm-8.2.5-ffce7548f9-50a240dfea.zip deleted file mode 100644 index dab7ffdd1e8c..000000000000 Binary files a/.yarn/cache/inquirer-npm-8.2.5-ffce7548f9-50a240dfea.zip and /dev/null differ diff --git a/.yarn/cache/inquirer-npm-8.2.6-dad82b499b-f642b9e5a9.zip b/.yarn/cache/inquirer-npm-8.2.6-dad82b499b-f642b9e5a9.zip new file mode 100644 index 000000000000..aae8bb4ae4ab Binary files /dev/null and b/.yarn/cache/inquirer-npm-8.2.6-dad82b499b-f642b9e5a9.zip differ diff --git a/.yarn/cache/internal-slot-npm-1.0.5-a2241f3e66-e2eb5b348e.zip b/.yarn/cache/internal-slot-npm-1.0.5-a2241f3e66-e2eb5b348e.zip deleted file mode 100644 index d60d330830ea..000000000000 Binary files a/.yarn/cache/internal-slot-npm-1.0.5-a2241f3e66-e2eb5b348e.zip and /dev/null differ diff --git a/.yarn/cache/internal-slot-npm-1.0.7-6e3758af00-3e66720508.zip b/.yarn/cache/internal-slot-npm-1.0.7-6e3758af00-3e66720508.zip new file mode 100644 index 000000000000..c1cebda0be26 Binary files /dev/null and b/.yarn/cache/internal-slot-npm-1.0.7-6e3758af00-3e66720508.zip differ diff --git a/.yarn/cache/ip-address-npm-9.0.5-9fa024d42a-1ed81e0672.zip b/.yarn/cache/ip-address-npm-9.0.5-9fa024d42a-1ed81e0672.zip new file mode 100644 index 000000000000..f29f3f6f189b Binary files /dev/null and b/.yarn/cache/ip-address-npm-9.0.5-9fa024d42a-1ed81e0672.zip differ diff --git a/.yarn/cache/ip-npm-2.0.0-204facb3cc-1270b11e53.zip b/.yarn/cache/ip-npm-2.0.0-204facb3cc-1270b11e53.zip deleted file mode 100644 index c751a851ab95..000000000000 Binary files a/.yarn/cache/ip-npm-2.0.0-204facb3cc-1270b11e53.zip and /dev/null differ diff --git a/.yarn/cache/ip-regex-npm-2.1.0-7eb0f6c4ab-331d95052a.zip b/.yarn/cache/ip-regex-npm-2.1.0-7eb0f6c4ab-331d95052a.zip deleted file mode 100644 index 3d05f86d7ba8..000000000000 Binary files a/.yarn/cache/ip-regex-npm-2.1.0-7eb0f6c4ab-331d95052a.zip and /dev/null differ diff --git a/.yarn/cache/ip-regex-npm-4.3.0-4ac12c6be9-7ff904b891.zip b/.yarn/cache/ip-regex-npm-4.3.0-4ac12c6be9-7ff904b891.zip new file mode 100644 index 000000000000..57f27084cdd4 Binary files /dev/null and b/.yarn/cache/ip-regex-npm-4.3.0-4ac12c6be9-7ff904b891.zip differ diff --git a/.yarn/cache/is-array-buffer-npm-3.0.1-3e93b14326-f26ab87448.zip b/.yarn/cache/is-array-buffer-npm-3.0.1-3e93b14326-f26ab87448.zip deleted file mode 100644 index 4fb5eb3634a1..000000000000 Binary files a/.yarn/cache/is-array-buffer-npm-3.0.1-3e93b14326-f26ab87448.zip and /dev/null differ diff --git a/.yarn/cache/is-array-buffer-npm-3.0.4-c1d4ec5b64-34a26213d9.zip b/.yarn/cache/is-array-buffer-npm-3.0.4-c1d4ec5b64-34a26213d9.zip new file mode 100644 index 000000000000..84bfe0b8b500 Binary files /dev/null and b/.yarn/cache/is-array-buffer-npm-3.0.4-c1d4ec5b64-34a26213d9.zip differ diff --git a/.yarn/cache/is-async-function-npm-2.0.0-ebf8596ab1-2cf336fbf8.zip b/.yarn/cache/is-async-function-npm-2.0.0-ebf8596ab1-2cf336fbf8.zip new file mode 100644 index 000000000000..8b7bee20136f Binary files /dev/null and b/.yarn/cache/is-async-function-npm-2.0.0-ebf8596ab1-2cf336fbf8.zip differ diff --git a/.yarn/cache/is-bigint-npm-1.0.2-db0dde4bd4-7e01ddae28.zip b/.yarn/cache/is-bigint-npm-1.0.2-db0dde4bd4-7e01ddae28.zip deleted file mode 100644 index fa4bcc1d7e7e..000000000000 Binary files a/.yarn/cache/is-bigint-npm-1.0.2-db0dde4bd4-7e01ddae28.zip and /dev/null differ diff --git a/.yarn/cache/is-bigint-npm-1.0.4-31c2eecbc9-cc981cf056.zip b/.yarn/cache/is-bigint-npm-1.0.4-31c2eecbc9-cc981cf056.zip new file mode 100644 index 000000000000..40076c0023fb Binary files /dev/null and b/.yarn/cache/is-bigint-npm-1.0.4-31c2eecbc9-cc981cf056.zip differ diff --git a/.yarn/cache/is-boolean-object-npm-1.1.1-4a132c53e4-63fbf0841b.zip b/.yarn/cache/is-boolean-object-npm-1.1.1-4a132c53e4-63fbf0841b.zip deleted file mode 100644 index 1bd820e5f52b..000000000000 Binary files a/.yarn/cache/is-boolean-object-npm-1.1.1-4a132c53e4-63fbf0841b.zip and /dev/null differ diff --git a/.yarn/cache/is-boolean-object-npm-1.1.2-ecbd575e6a-ba794223b5.zip b/.yarn/cache/is-boolean-object-npm-1.1.2-ecbd575e6a-ba794223b5.zip new file mode 100644 index 000000000000..c5d5957a5d2e Binary files /dev/null and b/.yarn/cache/is-boolean-object-npm-1.1.2-ecbd575e6a-ba794223b5.zip differ diff --git a/.yarn/cache/is-buffer-npm-2.0.4-ce097f06a1-3a0a079bd3.zip b/.yarn/cache/is-buffer-npm-2.0.4-ce097f06a1-3a0a079bd3.zip deleted file mode 100644 index ba8bb7da50c4..000000000000 Binary files a/.yarn/cache/is-buffer-npm-2.0.4-ce097f06a1-3a0a079bd3.zip and /dev/null differ diff --git a/.yarn/cache/is-buffer-npm-2.0.5-17e563f277-3261a8b858.zip b/.yarn/cache/is-buffer-npm-2.0.5-17e563f277-3261a8b858.zip new file mode 100644 index 000000000000..30a4e9d6f515 Binary files /dev/null and b/.yarn/cache/is-buffer-npm-2.0.5-17e563f277-3261a8b858.zip differ diff --git a/.yarn/cache/is-bun-module-npm-1.1.0-ba326bf12e-f6d2b16291.zip b/.yarn/cache/is-bun-module-npm-1.1.0-ba326bf12e-f6d2b16291.zip new file mode 100644 index 000000000000..7cef23e3d4f1 Binary files /dev/null and b/.yarn/cache/is-bun-module-npm-1.1.0-ba326bf12e-f6d2b16291.zip differ diff --git a/.yarn/cache/is-data-view-npm-1.0.1-d6136250e8-4ba4562ac2.zip b/.yarn/cache/is-data-view-npm-1.0.1-d6136250e8-4ba4562ac2.zip new file mode 100644 index 000000000000..1085c5b2a280 Binary files /dev/null and b/.yarn/cache/is-data-view-npm-1.0.1-d6136250e8-4ba4562ac2.zip differ diff --git a/.yarn/cache/is-finalizationregistry-npm-1.0.2-15bf1bd7ce-1b8e9e1bf2.zip b/.yarn/cache/is-finalizationregistry-npm-1.0.2-15bf1bd7ce-1b8e9e1bf2.zip new file mode 100644 index 000000000000..cf0d52879190 Binary files /dev/null and b/.yarn/cache/is-finalizationregistry-npm-1.0.2-15bf1bd7ce-1b8e9e1bf2.zip differ diff --git a/.yarn/cache/is-fullwidth-code-point-npm-5.0.0-5eb90c2a6e-8dfb2d2831.zip b/.yarn/cache/is-fullwidth-code-point-npm-5.0.0-5eb90c2a6e-8dfb2d2831.zip new file mode 100644 index 000000000000..5e0e355d3b4b Binary files /dev/null and b/.yarn/cache/is-fullwidth-code-point-npm-5.0.0-5eb90c2a6e-8dfb2d2831.zip differ diff --git a/.yarn/cache/is-map-npm-2.0.2-486724dabc-60ba910f83.zip b/.yarn/cache/is-map-npm-2.0.2-486724dabc-60ba910f83.zip deleted file mode 100644 index 50be7dff7ece..000000000000 Binary files a/.yarn/cache/is-map-npm-2.0.2-486724dabc-60ba910f83.zip and /dev/null differ diff --git a/.yarn/cache/is-map-npm-2.0.3-9e061e76e3-8de7b41715.zip b/.yarn/cache/is-map-npm-2.0.3-9e061e76e3-8de7b41715.zip new file mode 100644 index 000000000000..ba460dc2f085 Binary files /dev/null and b/.yarn/cache/is-map-npm-2.0.3-9e061e76e3-8de7b41715.zip differ diff --git a/.yarn/cache/is-negative-zero-npm-2.0.2-0adac91f15-edbec1a9e6.zip b/.yarn/cache/is-negative-zero-npm-2.0.2-0adac91f15-edbec1a9e6.zip deleted file mode 100644 index d7c31fff381e..000000000000 Binary files a/.yarn/cache/is-negative-zero-npm-2.0.2-0adac91f15-edbec1a9e6.zip and /dev/null differ diff --git a/.yarn/cache/is-negative-zero-npm-2.0.3-d06b09e322-8fe5cffd8d.zip b/.yarn/cache/is-negative-zero-npm-2.0.3-d06b09e322-8fe5cffd8d.zip new file mode 100644 index 000000000000..4d055b36eddd Binary files /dev/null and b/.yarn/cache/is-negative-zero-npm-2.0.3-d06b09e322-8fe5cffd8d.zip differ diff --git a/.yarn/cache/is-number-object-npm-1.0.4-c8e38aaa89-02939c84b2.zip b/.yarn/cache/is-number-object-npm-1.0.4-c8e38aaa89-02939c84b2.zip deleted file mode 100644 index 8c5d3c3d708d..000000000000 Binary files a/.yarn/cache/is-number-object-npm-1.0.4-c8e38aaa89-02939c84b2.zip and /dev/null differ diff --git a/.yarn/cache/is-number-object-npm-1.0.7-539d0e274d-8700dcf7f6.zip b/.yarn/cache/is-number-object-npm-1.0.7-539d0e274d-8700dcf7f6.zip new file mode 100644 index 000000000000..845ffb2297cd Binary files /dev/null and b/.yarn/cache/is-number-object-npm-1.0.7-539d0e274d-8700dcf7f6.zip differ diff --git a/.yarn/cache/is-path-cwd-npm-2.2.0-e35e4aab5f-46a840921b.zip b/.yarn/cache/is-path-cwd-npm-2.2.0-e35e4aab5f-46a840921b.zip deleted file mode 100644 index 95fe55975a9c..000000000000 Binary files a/.yarn/cache/is-path-cwd-npm-2.2.0-e35e4aab5f-46a840921b.zip and /dev/null differ diff --git a/.yarn/cache/is-plain-obj-npm-2.1.0-8dffd7ae9c-cec9100678.zip b/.yarn/cache/is-plain-obj-npm-2.1.0-8dffd7ae9c-cec9100678.zip new file mode 100644 index 000000000000..49504a5bbc52 Binary files /dev/null and b/.yarn/cache/is-plain-obj-npm-2.1.0-8dffd7ae9c-cec9100678.zip differ diff --git a/.yarn/cache/is-plain-object-npm-3.0.1-15b47fb6eb-d13fe75db3.zip b/.yarn/cache/is-plain-object-npm-3.0.1-15b47fb6eb-d13fe75db3.zip new file mode 100644 index 000000000000..558fecbb74fa Binary files /dev/null and b/.yarn/cache/is-plain-object-npm-3.0.1-15b47fb6eb-d13fe75db3.zip differ diff --git a/.yarn/cache/is-port-reachable-npm-3.1.0-2ef8bb0444-f6e51a1517.zip b/.yarn/cache/is-port-reachable-npm-3.1.0-2ef8bb0444-f6e51a1517.zip new file mode 100644 index 000000000000..b71b1df505ad Binary files /dev/null and b/.yarn/cache/is-port-reachable-npm-3.1.0-2ef8bb0444-f6e51a1517.zip differ diff --git a/.yarn/cache/is-set-npm-2.0.2-7e9ba84a8c-d89e82acdc.zip b/.yarn/cache/is-set-npm-2.0.2-7e9ba84a8c-d89e82acdc.zip deleted file mode 100644 index 73b13f3c3c0b..000000000000 Binary files a/.yarn/cache/is-set-npm-2.0.2-7e9ba84a8c-d89e82acdc.zip and /dev/null differ diff --git a/.yarn/cache/is-set-npm-2.0.3-1b72c9a855-5685df33f0.zip b/.yarn/cache/is-set-npm-2.0.3-1b72c9a855-5685df33f0.zip new file mode 100644 index 000000000000..3b1e3d0efbed Binary files /dev/null and b/.yarn/cache/is-set-npm-2.0.3-1b72c9a855-5685df33f0.zip differ diff --git a/.yarn/cache/is-shared-array-buffer-npm-1.0.2-32e4181fcd-23d82259d6.zip b/.yarn/cache/is-shared-array-buffer-npm-1.0.2-32e4181fcd-23d82259d6.zip deleted file mode 100644 index 190d00758e03..000000000000 Binary files a/.yarn/cache/is-shared-array-buffer-npm-1.0.2-32e4181fcd-23d82259d6.zip and /dev/null differ diff --git a/.yarn/cache/is-shared-array-buffer-npm-1.0.3-3b3b3142a6-bc5402900d.zip b/.yarn/cache/is-shared-array-buffer-npm-1.0.3-3b3b3142a6-bc5402900d.zip new file mode 100644 index 000000000000..d4372dd3d9be Binary files /dev/null and b/.yarn/cache/is-shared-array-buffer-npm-1.0.3-3b3b3142a6-bc5402900d.zip differ diff --git a/.yarn/cache/is-stream-npm-2.0.1-c802db55e7-b8e05ccdf9.zip b/.yarn/cache/is-stream-npm-2.0.1-c802db55e7-b8e05ccdf9.zip new file mode 100644 index 000000000000..c5699a4eeb79 Binary files /dev/null and b/.yarn/cache/is-stream-npm-2.0.1-c802db55e7-b8e05ccdf9.zip differ diff --git a/.yarn/cache/is-stream-npm-4.0.1-328fd196cc-cbea3f1fc2.zip b/.yarn/cache/is-stream-npm-4.0.1-328fd196cc-cbea3f1fc2.zip new file mode 100644 index 000000000000..d997500aa23d Binary files /dev/null and b/.yarn/cache/is-stream-npm-4.0.1-328fd196cc-cbea3f1fc2.zip differ diff --git a/.yarn/cache/is-symbol-npm-1.0.3-6bebca15dc-4854604be4.zip b/.yarn/cache/is-symbol-npm-1.0.3-6bebca15dc-4854604be4.zip deleted file mode 100644 index 1891472369ad..000000000000 Binary files a/.yarn/cache/is-symbol-npm-1.0.3-6bebca15dc-4854604be4.zip and /dev/null differ diff --git a/.yarn/cache/is-symbol-npm-1.0.4-eb9baac703-a47dd899a8.zip b/.yarn/cache/is-symbol-npm-1.0.4-eb9baac703-a47dd899a8.zip new file mode 100644 index 000000000000..7b6b1d44c3be Binary files /dev/null and b/.yarn/cache/is-symbol-npm-1.0.4-eb9baac703-a47dd899a8.zip differ diff --git a/.yarn/cache/is-typed-array-npm-1.1.10-fe4ef83cdc-2392b2473b.zip b/.yarn/cache/is-typed-array-npm-1.1.10-fe4ef83cdc-2392b2473b.zip deleted file mode 100644 index 305419609d85..000000000000 Binary files a/.yarn/cache/is-typed-array-npm-1.1.10-fe4ef83cdc-2392b2473b.zip and /dev/null differ diff --git a/.yarn/cache/is-typed-array-npm-1.1.13-0dce6ee7c2-f850ba0828.zip b/.yarn/cache/is-typed-array-npm-1.1.13-0dce6ee7c2-f850ba0828.zip new file mode 100644 index 000000000000..135744f7b7ec Binary files /dev/null and b/.yarn/cache/is-typed-array-npm-1.1.13-0dce6ee7c2-f850ba0828.zip differ diff --git a/.yarn/cache/is-weakmap-npm-2.0.1-88ca3d1dc4-289fa4e8ba.zip b/.yarn/cache/is-weakmap-npm-2.0.1-88ca3d1dc4-289fa4e8ba.zip deleted file mode 100644 index 15c5be50f8b1..000000000000 Binary files a/.yarn/cache/is-weakmap-npm-2.0.1-88ca3d1dc4-289fa4e8ba.zip and /dev/null differ diff --git a/.yarn/cache/is-weakmap-npm-2.0.2-ced3cab2dc-a7b7e23206.zip b/.yarn/cache/is-weakmap-npm-2.0.2-ced3cab2dc-a7b7e23206.zip new file mode 100644 index 000000000000..56e3990f2f10 Binary files /dev/null and b/.yarn/cache/is-weakmap-npm-2.0.2-ced3cab2dc-a7b7e23206.zip differ diff --git a/.yarn/cache/is-weakset-npm-2.0.2-b3cbc6c9cd-8f2ddb9639.zip b/.yarn/cache/is-weakset-npm-2.0.2-b3cbc6c9cd-8f2ddb9639.zip deleted file mode 100644 index a57dd4676fe6..000000000000 Binary files a/.yarn/cache/is-weakset-npm-2.0.2-b3cbc6c9cd-8f2ddb9639.zip and /dev/null differ diff --git a/.yarn/cache/is-weakset-npm-2.0.3-f7d282c9c1-40159582ff.zip b/.yarn/cache/is-weakset-npm-2.0.3-f7d282c9c1-40159582ff.zip new file mode 100644 index 000000000000..c600a1c7f9b4 Binary files /dev/null and b/.yarn/cache/is-weakset-npm-2.0.3-f7d282c9c1-40159582ff.zip differ diff --git a/.yarn/cache/is2-npm-2.0.1-f9d6d47786-b91c1eb740.zip b/.yarn/cache/is2-npm-2.0.1-f9d6d47786-b91c1eb740.zip deleted file mode 100644 index 7fbd27d21189..000000000000 Binary files a/.yarn/cache/is2-npm-2.0.1-f9d6d47786-b91c1eb740.zip and /dev/null differ diff --git a/.yarn/cache/is2-npm-2.0.9-69ddc5474e-ac229ce8fc.zip b/.yarn/cache/is2-npm-2.0.9-69ddc5474e-ac229ce8fc.zip new file mode 100644 index 000000000000..84d97a2d6595 Binary files /dev/null and b/.yarn/cache/is2-npm-2.0.9-69ddc5474e-ac229ce8fc.zip differ diff --git a/.yarn/cache/isexe-npm-3.1.1-9c0061eead-7fe1931ee4.zip b/.yarn/cache/isexe-npm-3.1.1-9c0061eead-7fe1931ee4.zip new file mode 100644 index 000000000000..7ea54624804c Binary files /dev/null and b/.yarn/cache/isexe-npm-3.1.1-9c0061eead-7fe1931ee4.zip differ diff --git a/.yarn/cache/istanbul-lib-coverage-npm-3.2.0-93f84b2c8c-31621b84ad.zip b/.yarn/cache/istanbul-lib-coverage-npm-3.2.0-93f84b2c8c-31621b84ad.zip deleted file mode 100644 index 1c849581e6a8..000000000000 Binary files a/.yarn/cache/istanbul-lib-coverage-npm-3.2.0-93f84b2c8c-31621b84ad.zip and /dev/null differ diff --git a/.yarn/cache/istanbul-lib-coverage-npm-3.2.2-5c0526e059-40bbdd1e93.zip b/.yarn/cache/istanbul-lib-coverage-npm-3.2.2-5c0526e059-40bbdd1e93.zip new file mode 100644 index 000000000000..960ed7af19e7 Binary files /dev/null and b/.yarn/cache/istanbul-lib-coverage-npm-3.2.2-5c0526e059-40bbdd1e93.zip differ diff --git a/.yarn/cache/istanbul-lib-instrument-npm-5.1.0-f92463b9f0-7447ba3f80.zip b/.yarn/cache/istanbul-lib-instrument-npm-5.1.0-f92463b9f0-7447ba3f80.zip deleted file mode 100644 index 19ee4f88d072..000000000000 Binary files a/.yarn/cache/istanbul-lib-instrument-npm-5.1.0-f92463b9f0-7447ba3f80.zip and /dev/null differ diff --git a/.yarn/cache/istanbul-lib-instrument-npm-5.2.1-1b3ad719a9-bbc4496c2f.zip b/.yarn/cache/istanbul-lib-instrument-npm-5.2.1-1b3ad719a9-bbc4496c2f.zip new file mode 100644 index 000000000000..812d04f5cde6 Binary files /dev/null and b/.yarn/cache/istanbul-lib-instrument-npm-5.2.1-1b3ad719a9-bbc4496c2f.zip differ diff --git a/.yarn/cache/istanbul-lib-report-npm-3.0.0-660f97340a-06b37952e9.zip b/.yarn/cache/istanbul-lib-report-npm-3.0.0-660f97340a-06b37952e9.zip deleted file mode 100644 index 117daec1b468..000000000000 Binary files a/.yarn/cache/istanbul-lib-report-npm-3.0.0-660f97340a-06b37952e9.zip and /dev/null differ diff --git a/.yarn/cache/istanbul-lib-report-npm-3.0.1-b17446ab24-86a83421ca.zip b/.yarn/cache/istanbul-lib-report-npm-3.0.1-b17446ab24-86a83421ca.zip new file mode 100644 index 000000000000..47a0ef10944f Binary files /dev/null and b/.yarn/cache/istanbul-lib-report-npm-3.0.1-b17446ab24-86a83421ca.zip differ diff --git a/.yarn/cache/istanbul-lib-source-maps-npm-4.0.0-def3895674-765252abc6.zip b/.yarn/cache/istanbul-lib-source-maps-npm-4.0.0-def3895674-765252abc6.zip deleted file mode 100644 index a36ac3cccb90..000000000000 Binary files a/.yarn/cache/istanbul-lib-source-maps-npm-4.0.0-def3895674-765252abc6.zip and /dev/null differ diff --git a/.yarn/cache/istanbul-lib-source-maps-npm-4.0.1-af0f859df7-5526983462.zip b/.yarn/cache/istanbul-lib-source-maps-npm-4.0.1-af0f859df7-5526983462.zip new file mode 100644 index 000000000000..cd5d9864e568 Binary files /dev/null and b/.yarn/cache/istanbul-lib-source-maps-npm-4.0.1-af0f859df7-5526983462.zip differ diff --git a/.yarn/cache/istanbul-reports-npm-3.1.5-fb11324e3e-1fc20a133f.zip b/.yarn/cache/istanbul-reports-npm-3.1.5-fb11324e3e-1fc20a133f.zip deleted file mode 100644 index 6d12a74fd73c..000000000000 Binary files a/.yarn/cache/istanbul-reports-npm-3.1.5-fb11324e3e-1fc20a133f.zip and /dev/null differ diff --git a/.yarn/cache/istanbul-reports-npm-3.1.7-356486c0f4-f1faaa4684.zip b/.yarn/cache/istanbul-reports-npm-3.1.7-356486c0f4-f1faaa4684.zip new file mode 100644 index 000000000000..878079f5cd39 Binary files /dev/null and b/.yarn/cache/istanbul-reports-npm-3.1.7-356486c0f4-f1faaa4684.zip differ diff --git a/.yarn/cache/iterator.prototype-npm-1.1.2-009f234a21-b5013967ad.zip b/.yarn/cache/iterator.prototype-npm-1.1.2-009f234a21-b5013967ad.zip new file mode 100644 index 000000000000..61320da367a0 Binary files /dev/null and b/.yarn/cache/iterator.prototype-npm-1.1.2-009f234a21-b5013967ad.zip differ diff --git a/.yarn/cache/jackspeak-npm-3.4.0-fdc2c6fcce-5032c43c0c.zip b/.yarn/cache/jackspeak-npm-3.4.0-fdc2c6fcce-5032c43c0c.zip deleted file mode 100644 index 04721e4edbd8..000000000000 Binary files a/.yarn/cache/jackspeak-npm-3.4.0-fdc2c6fcce-5032c43c0c.zip and /dev/null differ diff --git a/.yarn/cache/jackspeak-npm-3.4.3-546bfad080-96f8786eaa.zip b/.yarn/cache/jackspeak-npm-3.4.3-546bfad080-96f8786eaa.zip new file mode 100644 index 000000000000..c75875613c71 Binary files /dev/null and b/.yarn/cache/jackspeak-npm-3.4.3-546bfad080-96f8786eaa.zip differ diff --git a/.yarn/cache/jake-npm-10.8.5-6a5e87e533-6eaf1cd7fe.zip b/.yarn/cache/jake-npm-10.8.5-6a5e87e533-6eaf1cd7fe.zip deleted file mode 100644 index 7931ce657fa4..000000000000 Binary files a/.yarn/cache/jake-npm-10.8.5-6a5e87e533-6eaf1cd7fe.zip and /dev/null differ diff --git a/.yarn/cache/jake-npm-10.9.2-3bf2173aed-3be324708f.zip b/.yarn/cache/jake-npm-10.9.2-3bf2173aed-3be324708f.zip new file mode 100644 index 000000000000..5acb4f3a25f6 Binary files /dev/null and b/.yarn/cache/jake-npm-10.9.2-3bf2173aed-3be324708f.zip differ diff --git a/.yarn/cache/jest-changed-files-npm-28.0.2-86f0227b65-1d6609eb3e.zip b/.yarn/cache/jest-changed-files-npm-28.0.2-86f0227b65-1d6609eb3e.zip deleted file mode 100644 index 5200220dc00d..000000000000 Binary files a/.yarn/cache/jest-changed-files-npm-28.0.2-86f0227b65-1d6609eb3e.zip and /dev/null differ diff --git a/.yarn/cache/jest-changed-files-npm-28.1.3-bb00ac0321-206be715fe.zip b/.yarn/cache/jest-changed-files-npm-28.1.3-bb00ac0321-206be715fe.zip new file mode 100644 index 000000000000..fd0663e44151 Binary files /dev/null and b/.yarn/cache/jest-changed-files-npm-28.1.3-bb00ac0321-206be715fe.zip differ diff --git a/.yarn/cache/jest-circus-npm-28.1.0-7c33b8022f-d18a29b7df.zip b/.yarn/cache/jest-circus-npm-28.1.0-7c33b8022f-d18a29b7df.zip deleted file mode 100644 index 793a361d7093..000000000000 Binary files a/.yarn/cache/jest-circus-npm-28.1.0-7c33b8022f-d18a29b7df.zip and /dev/null differ diff --git a/.yarn/cache/jest-circus-npm-28.1.3-cd59c17100-3ac1f369ca.zip b/.yarn/cache/jest-circus-npm-28.1.3-cd59c17100-3ac1f369ca.zip new file mode 100644 index 000000000000..2d1bf0d4bdb2 Binary files /dev/null and b/.yarn/cache/jest-circus-npm-28.1.3-cd59c17100-3ac1f369ca.zip differ diff --git a/.yarn/cache/jest-cli-npm-28.1.0-edbd0ac89a-1dc2b40532.zip b/.yarn/cache/jest-cli-npm-28.1.0-edbd0ac89a-1dc2b40532.zip deleted file mode 100644 index 4502230738b3..000000000000 Binary files a/.yarn/cache/jest-cli-npm-28.1.0-edbd0ac89a-1dc2b40532.zip and /dev/null differ diff --git a/.yarn/cache/jest-cli-npm-28.1.3-aab5c7389d-935a0c517e.zip b/.yarn/cache/jest-cli-npm-28.1.3-aab5c7389d-935a0c517e.zip new file mode 100644 index 000000000000..3ad98a89cc59 Binary files /dev/null and b/.yarn/cache/jest-cli-npm-28.1.3-aab5c7389d-935a0c517e.zip differ diff --git a/.yarn/cache/jest-config-npm-28.1.0-189d510700-6f875bca24.zip b/.yarn/cache/jest-config-npm-28.1.0-189d510700-6f875bca24.zip deleted file mode 100644 index bc91656b7e27..000000000000 Binary files a/.yarn/cache/jest-config-npm-28.1.0-189d510700-6f875bca24.zip and /dev/null differ diff --git a/.yarn/cache/jest-config-npm-28.1.3-47d1c91477-457d8709e2.zip b/.yarn/cache/jest-config-npm-28.1.3-47d1c91477-457d8709e2.zip new file mode 100644 index 000000000000..1865c1d02bf8 Binary files /dev/null and b/.yarn/cache/jest-config-npm-28.1.3-47d1c91477-457d8709e2.zip differ diff --git a/.yarn/cache/jest-diff-npm-28.1.0-0e7842e95e-08bc1a3e79.zip b/.yarn/cache/jest-diff-npm-28.1.0-0e7842e95e-08bc1a3e79.zip deleted file mode 100644 index 5c8584cbcc79..000000000000 Binary files a/.yarn/cache/jest-diff-npm-28.1.0-0e7842e95e-08bc1a3e79.zip and /dev/null differ diff --git a/.yarn/cache/jest-diff-npm-28.1.3-cdbbfc3cc7-42b8d82c59.zip b/.yarn/cache/jest-diff-npm-28.1.3-cdbbfc3cc7-42b8d82c59.zip new file mode 100644 index 000000000000..0c1376927597 Binary files /dev/null and b/.yarn/cache/jest-diff-npm-28.1.3-cdbbfc3cc7-42b8d82c59.zip differ diff --git a/.yarn/cache/jest-docblock-npm-28.0.2-2f5a0eac8f-93c237d508.zip b/.yarn/cache/jest-docblock-npm-28.0.2-2f5a0eac8f-93c237d508.zip deleted file mode 100644 index 5a83dbce7545..000000000000 Binary files a/.yarn/cache/jest-docblock-npm-28.0.2-2f5a0eac8f-93c237d508.zip and /dev/null differ diff --git a/.yarn/cache/jest-docblock-npm-28.1.1-92269e3ff0-4062cb9ba5.zip b/.yarn/cache/jest-docblock-npm-28.1.1-92269e3ff0-4062cb9ba5.zip new file mode 100644 index 000000000000..396ce8e7a186 Binary files /dev/null and b/.yarn/cache/jest-docblock-npm-28.1.1-92269e3ff0-4062cb9ba5.zip differ diff --git a/.yarn/cache/jest-each-npm-28.1.0-e0cc71d9e4-f062ace6dd.zip b/.yarn/cache/jest-each-npm-28.1.0-e0cc71d9e4-f062ace6dd.zip deleted file mode 100644 index 8b0175d55aa2..000000000000 Binary files a/.yarn/cache/jest-each-npm-28.1.0-e0cc71d9e4-f062ace6dd.zip and /dev/null differ diff --git a/.yarn/cache/jest-each-npm-28.1.3-ca0bd1494b-4877cdda70.zip b/.yarn/cache/jest-each-npm-28.1.3-ca0bd1494b-4877cdda70.zip new file mode 100644 index 000000000000..8290348109b4 Binary files /dev/null and b/.yarn/cache/jest-each-npm-28.1.3-ca0bd1494b-4877cdda70.zip differ diff --git a/.yarn/cache/jest-environment-jsdom-npm-28.1.0-9ab6320ea8-ba4d2b9162.zip b/.yarn/cache/jest-environment-jsdom-npm-28.1.0-9ab6320ea8-ba4d2b9162.zip deleted file mode 100644 index d1a7f30b1c13..000000000000 Binary files a/.yarn/cache/jest-environment-jsdom-npm-28.1.0-9ab6320ea8-ba4d2b9162.zip and /dev/null differ diff --git a/.yarn/cache/jest-environment-jsdom-npm-28.1.3-c3ce0aea09-07596846f2.zip b/.yarn/cache/jest-environment-jsdom-npm-28.1.3-c3ce0aea09-07596846f2.zip new file mode 100644 index 000000000000..eebb6a131f27 Binary files /dev/null and b/.yarn/cache/jest-environment-jsdom-npm-28.1.3-c3ce0aea09-07596846f2.zip differ diff --git a/.yarn/cache/jest-environment-node-npm-28.1.0-0d42cf325a-8031457cf7.zip b/.yarn/cache/jest-environment-node-npm-28.1.0-0d42cf325a-8031457cf7.zip deleted file mode 100644 index 72e38e1fa632..000000000000 Binary files a/.yarn/cache/jest-environment-node-npm-28.1.0-0d42cf325a-8031457cf7.zip and /dev/null differ diff --git a/.yarn/cache/jest-environment-node-npm-28.1.3-46a696a38b-ab9ec5c573.zip b/.yarn/cache/jest-environment-node-npm-28.1.3-46a696a38b-ab9ec5c573.zip new file mode 100644 index 000000000000..cc1f7d32b730 Binary files /dev/null and b/.yarn/cache/jest-environment-node-npm-28.1.3-46a696a38b-ab9ec5c573.zip differ diff --git a/.yarn/cache/jest-haste-map-npm-28.1.0-c3fd885385-b4342da309.zip b/.yarn/cache/jest-haste-map-npm-28.1.0-c3fd885385-b4342da309.zip deleted file mode 100644 index b727812367a5..000000000000 Binary files a/.yarn/cache/jest-haste-map-npm-28.1.0-c3fd885385-b4342da309.zip and /dev/null differ diff --git a/.yarn/cache/jest-haste-map-npm-28.1.3-9ce0dea452-c78e0e81e3.zip b/.yarn/cache/jest-haste-map-npm-28.1.3-9ce0dea452-c78e0e81e3.zip new file mode 100644 index 000000000000..90a5aaafd4c8 Binary files /dev/null and b/.yarn/cache/jest-haste-map-npm-28.1.3-9ce0dea452-c78e0e81e3.zip differ diff --git a/.yarn/cache/jest-leak-detector-npm-28.1.0-65defaf593-911eec6b96.zip b/.yarn/cache/jest-leak-detector-npm-28.1.0-65defaf593-911eec6b96.zip deleted file mode 100644 index 40a00a73497e..000000000000 Binary files a/.yarn/cache/jest-leak-detector-npm-28.1.0-65defaf593-911eec6b96.zip and /dev/null differ diff --git a/.yarn/cache/jest-leak-detector-npm-28.1.3-36abac94be-2e976a4880.zip b/.yarn/cache/jest-leak-detector-npm-28.1.3-36abac94be-2e976a4880.zip new file mode 100644 index 000000000000..3e3ed7f2dcf2 Binary files /dev/null and b/.yarn/cache/jest-leak-detector-npm-28.1.3-36abac94be-2e976a4880.zip differ diff --git a/.yarn/cache/jest-matcher-utils-npm-28.1.0-552ef6acf4-eace02441b.zip b/.yarn/cache/jest-matcher-utils-npm-28.1.0-552ef6acf4-eace02441b.zip deleted file mode 100644 index 4b1f51ffffcb..000000000000 Binary files a/.yarn/cache/jest-matcher-utils-npm-28.1.0-552ef6acf4-eace02441b.zip and /dev/null differ diff --git a/.yarn/cache/jest-matcher-utils-npm-28.1.3-6a206019d4-958f4bacda.zip b/.yarn/cache/jest-matcher-utils-npm-28.1.3-6a206019d4-958f4bacda.zip new file mode 100644 index 000000000000..066a1e4ff997 Binary files /dev/null and b/.yarn/cache/jest-matcher-utils-npm-28.1.3-6a206019d4-958f4bacda.zip differ diff --git a/.yarn/cache/jest-matcher-utils-npm-29.7.0-dfc74b630e-981904a494.zip b/.yarn/cache/jest-matcher-utils-npm-29.7.0-dfc74b630e-981904a494.zip new file mode 100644 index 000000000000..b8edc33f6639 Binary files /dev/null and b/.yarn/cache/jest-matcher-utils-npm-29.7.0-dfc74b630e-981904a494.zip differ diff --git a/.yarn/cache/jest-message-util-npm-28.1.0-e935670ba1-87817d55d8.zip b/.yarn/cache/jest-message-util-npm-28.1.0-e935670ba1-87817d55d8.zip deleted file mode 100644 index 3b9a181c0e7e..000000000000 Binary files a/.yarn/cache/jest-message-util-npm-28.1.0-e935670ba1-87817d55d8.zip and /dev/null differ diff --git a/.yarn/cache/jest-message-util-npm-28.1.3-bee4da4d10-91137a507e.zip b/.yarn/cache/jest-message-util-npm-28.1.3-bee4da4d10-91137a507e.zip new file mode 100644 index 000000000000..dc988ea8a3f0 Binary files /dev/null and b/.yarn/cache/jest-message-util-npm-28.1.3-bee4da4d10-91137a507e.zip differ diff --git a/.yarn/cache/jest-message-util-npm-29.6.2-8bd7bc632e-a0e972367f.zip b/.yarn/cache/jest-message-util-npm-29.6.2-8bd7bc632e-a0e972367f.zip deleted file mode 100644 index 3cfc359fe394..000000000000 Binary files a/.yarn/cache/jest-message-util-npm-29.6.2-8bd7bc632e-a0e972367f.zip and /dev/null differ diff --git a/.yarn/cache/jest-message-util-npm-29.7.0-7f88b6e8d1-31d53c6ed2.zip b/.yarn/cache/jest-message-util-npm-29.7.0-7f88b6e8d1-31d53c6ed2.zip new file mode 100644 index 000000000000..770cff6a1749 Binary files /dev/null and b/.yarn/cache/jest-message-util-npm-29.7.0-7f88b6e8d1-31d53c6ed2.zip differ diff --git a/.yarn/cache/jest-mock-npm-28.1.0-c88527067b-08a47fbcfe.zip b/.yarn/cache/jest-mock-npm-28.1.0-c88527067b-08a47fbcfe.zip deleted file mode 100644 index 2cf065e00fe6..000000000000 Binary files a/.yarn/cache/jest-mock-npm-28.1.0-c88527067b-08a47fbcfe.zip and /dev/null differ diff --git a/.yarn/cache/jest-mock-npm-28.1.3-75849d2dd2-43cbec0ced.zip b/.yarn/cache/jest-mock-npm-28.1.3-75849d2dd2-43cbec0ced.zip new file mode 100644 index 000000000000..b634a612e9b8 Binary files /dev/null and b/.yarn/cache/jest-mock-npm-28.1.3-75849d2dd2-43cbec0ced.zip differ diff --git a/.yarn/cache/jest-npm-28.1.0-3beb54c0f4-8ea51be1fe.zip b/.yarn/cache/jest-npm-28.1.0-3beb54c0f4-8ea51be1fe.zip deleted file mode 100644 index 24baa8249caf..000000000000 Binary files a/.yarn/cache/jest-npm-28.1.0-3beb54c0f4-8ea51be1fe.zip and /dev/null differ diff --git a/.yarn/cache/jest-npm-28.1.3-207c50e059-fb7c93e8a9.zip b/.yarn/cache/jest-npm-28.1.3-207c50e059-fb7c93e8a9.zip new file mode 100644 index 000000000000..8859671ee7c5 Binary files /dev/null and b/.yarn/cache/jest-npm-28.1.3-207c50e059-fb7c93e8a9.zip differ diff --git a/.yarn/cache/jest-pnp-resolver-npm-1.2.2-da20f8bdfe-bd85dcc0e7.zip b/.yarn/cache/jest-pnp-resolver-npm-1.2.2-da20f8bdfe-bd85dcc0e7.zip deleted file mode 100644 index 36125b53009e..000000000000 Binary files a/.yarn/cache/jest-pnp-resolver-npm-1.2.2-da20f8bdfe-bd85dcc0e7.zip and /dev/null differ diff --git a/.yarn/cache/jest-pnp-resolver-npm-1.2.3-70e06bf27c-db1a8ab2cb.zip b/.yarn/cache/jest-pnp-resolver-npm-1.2.3-70e06bf27c-db1a8ab2cb.zip new file mode 100644 index 000000000000..b4c4e50926be Binary files /dev/null and b/.yarn/cache/jest-pnp-resolver-npm-1.2.3-70e06bf27c-db1a8ab2cb.zip differ diff --git a/.yarn/cache/jest-regex-util-npm-29.4.3-defc22c588-96fc7fc28c.zip b/.yarn/cache/jest-regex-util-npm-29.4.3-defc22c588-96fc7fc28c.zip deleted file mode 100644 index c17765b73669..000000000000 Binary files a/.yarn/cache/jest-regex-util-npm-29.4.3-defc22c588-96fc7fc28c.zip and /dev/null differ diff --git a/.yarn/cache/jest-regex-util-npm-29.6.3-568e0094e2-0518beeb9b.zip b/.yarn/cache/jest-regex-util-npm-29.6.3-568e0094e2-0518beeb9b.zip new file mode 100644 index 000000000000..ddf6af34ec97 Binary files /dev/null and b/.yarn/cache/jest-regex-util-npm-29.6.3-568e0094e2-0518beeb9b.zip differ diff --git a/.yarn/cache/jest-resolve-dependencies-npm-28.1.0-6caeb86499-e4a6a9cc0a.zip b/.yarn/cache/jest-resolve-dependencies-npm-28.1.0-6caeb86499-e4a6a9cc0a.zip deleted file mode 100644 index f45fcd84d129..000000000000 Binary files a/.yarn/cache/jest-resolve-dependencies-npm-28.1.0-6caeb86499-e4a6a9cc0a.zip and /dev/null differ diff --git a/.yarn/cache/jest-resolve-dependencies-npm-28.1.3-143d112ae5-5c3128ea5f.zip b/.yarn/cache/jest-resolve-dependencies-npm-28.1.3-143d112ae5-5c3128ea5f.zip new file mode 100644 index 000000000000..17bad840afc8 Binary files /dev/null and b/.yarn/cache/jest-resolve-dependencies-npm-28.1.3-143d112ae5-5c3128ea5f.zip differ diff --git a/.yarn/cache/jest-resolve-npm-28.1.0-dc96e123ba-2fcc19f8cc.zip b/.yarn/cache/jest-resolve-npm-28.1.0-dc96e123ba-2fcc19f8cc.zip deleted file mode 100644 index cc8940c9a062..000000000000 Binary files a/.yarn/cache/jest-resolve-npm-28.1.0-dc96e123ba-2fcc19f8cc.zip and /dev/null differ diff --git a/.yarn/cache/jest-resolve-npm-28.1.3-acd3a0d26b-742b2301a4.zip b/.yarn/cache/jest-resolve-npm-28.1.3-acd3a0d26b-742b2301a4.zip new file mode 100644 index 000000000000..ca02364dcfca Binary files /dev/null and b/.yarn/cache/jest-resolve-npm-28.1.3-acd3a0d26b-742b2301a4.zip differ diff --git a/.yarn/cache/jest-runner-npm-28.1.0-4df27e4224-dd9f9b0788.zip b/.yarn/cache/jest-runner-npm-28.1.0-4df27e4224-dd9f9b0788.zip deleted file mode 100644 index a3915e5bada8..000000000000 Binary files a/.yarn/cache/jest-runner-npm-28.1.0-4df27e4224-dd9f9b0788.zip and /dev/null differ diff --git a/.yarn/cache/jest-runner-npm-28.1.3-b6c86f7ed5-0fb6ed4f62.zip b/.yarn/cache/jest-runner-npm-28.1.3-b6c86f7ed5-0fb6ed4f62.zip new file mode 100644 index 000000000000..14ff991659d1 Binary files /dev/null and b/.yarn/cache/jest-runner-npm-28.1.3-b6c86f7ed5-0fb6ed4f62.zip differ diff --git a/.yarn/cache/jest-runtime-npm-28.1.0-111844adc0-d24913fb5a.zip b/.yarn/cache/jest-runtime-npm-28.1.0-111844adc0-d24913fb5a.zip deleted file mode 100644 index 8c73816603f1..000000000000 Binary files a/.yarn/cache/jest-runtime-npm-28.1.0-111844adc0-d24913fb5a.zip and /dev/null differ diff --git a/.yarn/cache/jest-runtime-npm-28.1.3-15fdfa887e-d3d91b3f10.zip b/.yarn/cache/jest-runtime-npm-28.1.3-15fdfa887e-d3d91b3f10.zip new file mode 100644 index 000000000000..ded32688b321 Binary files /dev/null and b/.yarn/cache/jest-runtime-npm-28.1.3-15fdfa887e-d3d91b3f10.zip differ diff --git a/.yarn/cache/jest-snapshot-npm-28.1.0-77cea43a3f-4e02168ae4.zip b/.yarn/cache/jest-snapshot-npm-28.1.0-77cea43a3f-4e02168ae4.zip deleted file mode 100644 index 9c354f41cc33..000000000000 Binary files a/.yarn/cache/jest-snapshot-npm-28.1.0-77cea43a3f-4e02168ae4.zip and /dev/null differ diff --git a/.yarn/cache/jest-snapshot-npm-28.1.3-b36ae70475-4e1f4e2aa5.zip b/.yarn/cache/jest-snapshot-npm-28.1.3-b36ae70475-4e1f4e2aa5.zip new file mode 100644 index 000000000000..7bcafabfe3aa Binary files /dev/null and b/.yarn/cache/jest-snapshot-npm-28.1.3-b36ae70475-4e1f4e2aa5.zip differ diff --git a/.yarn/cache/jest-util-npm-28.1.0-b265695a65-54ef6014c7.zip b/.yarn/cache/jest-util-npm-28.1.0-b265695a65-54ef6014c7.zip deleted file mode 100644 index 2f6d8f7181ff..000000000000 Binary files a/.yarn/cache/jest-util-npm-28.1.0-b265695a65-54ef6014c7.zip and /dev/null differ diff --git a/.yarn/cache/jest-util-npm-28.1.3-9ae2283a08-92895523d3.zip b/.yarn/cache/jest-util-npm-28.1.3-9ae2283a08-92895523d3.zip new file mode 100644 index 000000000000..0e6bf2ee2a4f Binary files /dev/null and b/.yarn/cache/jest-util-npm-28.1.3-9ae2283a08-92895523d3.zip differ diff --git a/.yarn/cache/jest-util-npm-29.6.2-41bd0e8e02-95d510b7bb.zip b/.yarn/cache/jest-util-npm-29.6.2-41bd0e8e02-95d510b7bb.zip deleted file mode 100644 index 71f5741f6364..000000000000 Binary files a/.yarn/cache/jest-util-npm-29.6.2-41bd0e8e02-95d510b7bb.zip and /dev/null differ diff --git a/.yarn/cache/jest-util-npm-29.7.0-ff1d59714b-30d58af696.zip b/.yarn/cache/jest-util-npm-29.7.0-ff1d59714b-30d58af696.zip new file mode 100644 index 000000000000..af20ef41ff4a Binary files /dev/null and b/.yarn/cache/jest-util-npm-29.7.0-ff1d59714b-30d58af696.zip differ diff --git a/.yarn/cache/jest-validate-npm-28.1.0-aaf7b94ac0-23f52e116b.zip b/.yarn/cache/jest-validate-npm-28.1.0-aaf7b94ac0-23f52e116b.zip deleted file mode 100644 index b2f2e18d24ea..000000000000 Binary files a/.yarn/cache/jest-validate-npm-28.1.0-aaf7b94ac0-23f52e116b.zip and /dev/null differ diff --git a/.yarn/cache/jest-validate-npm-28.1.3-f1a729aeb4-c49c8c64b4.zip b/.yarn/cache/jest-validate-npm-28.1.3-f1a729aeb4-c49c8c64b4.zip new file mode 100644 index 000000000000..aff6209bddc3 Binary files /dev/null and b/.yarn/cache/jest-validate-npm-28.1.3-f1a729aeb4-c49c8c64b4.zip differ diff --git a/.yarn/cache/jest-watcher-npm-28.1.0-8fdb363138-e37e4b6406.zip b/.yarn/cache/jest-watcher-npm-28.1.0-8fdb363138-e37e4b6406.zip deleted file mode 100644 index 8d83f5cc2da9..000000000000 Binary files a/.yarn/cache/jest-watcher-npm-28.1.0-8fdb363138-e37e4b6406.zip and /dev/null differ diff --git a/.yarn/cache/jest-watcher-npm-28.1.3-8da81cc37d-e6d2c099d4.zip b/.yarn/cache/jest-watcher-npm-28.1.3-8da81cc37d-e6d2c099d4.zip new file mode 100644 index 000000000000..9493e7748fce Binary files /dev/null and b/.yarn/cache/jest-watcher-npm-28.1.3-8da81cc37d-e6d2c099d4.zip differ diff --git a/.yarn/cache/jest-watcher-npm-29.6.2-ec5e606774-dbba1872ef.zip b/.yarn/cache/jest-watcher-npm-29.6.2-ec5e606774-dbba1872ef.zip deleted file mode 100644 index db3c95eb18a9..000000000000 Binary files a/.yarn/cache/jest-watcher-npm-29.6.2-ec5e606774-dbba1872ef.zip and /dev/null differ diff --git a/.yarn/cache/jest-watcher-npm-29.7.0-e5372f1629-4f616e0345.zip b/.yarn/cache/jest-watcher-npm-29.7.0-e5372f1629-4f616e0345.zip new file mode 100644 index 000000000000..c81f2441b3e4 Binary files /dev/null and b/.yarn/cache/jest-watcher-npm-29.7.0-e5372f1629-4f616e0345.zip differ diff --git a/.yarn/cache/jest-worker-npm-28.1.0-8aae9a213c-6badb7d8ca.zip b/.yarn/cache/jest-worker-npm-28.1.0-8aae9a213c-6badb7d8ca.zip deleted file mode 100644 index 17554ec42b0d..000000000000 Binary files a/.yarn/cache/jest-worker-npm-28.1.0-8aae9a213c-6badb7d8ca.zip and /dev/null differ diff --git a/.yarn/cache/jest-worker-npm-28.1.3-5d0ff9006c-0b59923082.zip b/.yarn/cache/jest-worker-npm-28.1.3-5d0ff9006c-0b59923082.zip new file mode 100644 index 000000000000..8d8de307e42d Binary files /dev/null and b/.yarn/cache/jest-worker-npm-28.1.3-5d0ff9006c-0b59923082.zip differ diff --git a/.yarn/cache/jiti-npm-1.21.0-baebd5985a-005a0239e5.zip b/.yarn/cache/jiti-npm-1.21.0-baebd5985a-005a0239e5.zip deleted file mode 100644 index 6aeb79f9b4ae..000000000000 Binary files a/.yarn/cache/jiti-npm-1.21.0-baebd5985a-005a0239e5.zip and /dev/null differ diff --git a/.yarn/cache/jiti-npm-1.21.6-0bb76563a3-289b124cea.zip b/.yarn/cache/jiti-npm-1.21.6-0bb76563a3-289b124cea.zip new file mode 100644 index 000000000000..0288b4a5e86e Binary files /dev/null and b/.yarn/cache/jiti-npm-1.21.6-0bb76563a3-289b124cea.zip differ diff --git a/.yarn/cache/js-sdsl-npm-4.3.0-4f51b3ddb2-2734a39296.zip b/.yarn/cache/js-sdsl-npm-4.3.0-4f51b3ddb2-2734a39296.zip deleted file mode 100644 index d56738be1c88..000000000000 Binary files a/.yarn/cache/js-sdsl-npm-4.3.0-4f51b3ddb2-2734a39296.zip and /dev/null differ diff --git a/.yarn/cache/js-sdsl-npm-4.4.2-992f97f34c-806ab7aea3.zip b/.yarn/cache/js-sdsl-npm-4.4.2-992f97f34c-806ab7aea3.zip new file mode 100644 index 000000000000..1c74564c8780 Binary files /dev/null and b/.yarn/cache/js-sdsl-npm-4.4.2-992f97f34c-806ab7aea3.zip differ diff --git a/.yarn/cache/jsbn-npm-1.1.0-1da0181838-bebe7ae829.zip b/.yarn/cache/jsbn-npm-1.1.0-1da0181838-bebe7ae829.zip new file mode 100644 index 000000000000..4e18b228c5fa Binary files /dev/null and b/.yarn/cache/jsbn-npm-1.1.0-1da0181838-bebe7ae829.zip differ diff --git a/.yarn/cache/jsdom-npm-24.1.3-c45b6cf5c7-81e01d092a.zip b/.yarn/cache/jsdom-npm-24.1.3-c45b6cf5c7-81e01d092a.zip new file mode 100644 index 000000000000..d4156e0d455c Binary files /dev/null and b/.yarn/cache/jsdom-npm-24.1.3-c45b6cf5c7-81e01d092a.zip differ diff --git a/.yarn/cache/json-fixer-npm-1.6.15-ae75b6da33-240d6ad7ed.zip b/.yarn/cache/json-fixer-npm-1.6.15-ae75b6da33-240d6ad7ed.zip new file mode 100644 index 000000000000..1b29e8260668 Binary files /dev/null and b/.yarn/cache/json-fixer-npm-1.6.15-ae75b6da33-240d6ad7ed.zip differ diff --git a/.yarn/cache/json-fixer-npm-1.6.5-b060b2f6bb-6014ee070e.zip b/.yarn/cache/json-fixer-npm-1.6.5-b060b2f6bb-6014ee070e.zip deleted file mode 100644 index c2983d9c24f0..000000000000 Binary files a/.yarn/cache/json-fixer-npm-1.6.5-b060b2f6bb-6014ee070e.zip and /dev/null differ diff --git a/.yarn/cache/json-parse-even-better-errors-npm-3.0.0-3675833c0a-f1970b5220.zip b/.yarn/cache/json-parse-even-better-errors-npm-3.0.0-3675833c0a-f1970b5220.zip deleted file mode 100644 index 8aa941bdb8b1..000000000000 Binary files a/.yarn/cache/json-parse-even-better-errors-npm-3.0.0-3675833c0a-f1970b5220.zip and /dev/null differ diff --git a/.yarn/cache/json-parse-even-better-errors-npm-3.0.2-3d985a6781-6f04ea6c9c.zip b/.yarn/cache/json-parse-even-better-errors-npm-3.0.2-3d985a6781-6f04ea6c9c.zip new file mode 100644 index 000000000000..7a5aa103442f Binary files /dev/null and b/.yarn/cache/json-parse-even-better-errors-npm-3.0.2-3d985a6781-6f04ea6c9c.zip differ diff --git a/.yarn/cache/json-stringify-nice-npm-1.1.4-0b0ddb188b-0e02cae900.zip b/.yarn/cache/json-stringify-nice-npm-1.1.4-0b0ddb188b-0e02cae900.zip new file mode 100644 index 000000000000..faaafd11e663 Binary files /dev/null and b/.yarn/cache/json-stringify-nice-npm-1.1.4-0b0ddb188b-0e02cae900.zip differ diff --git a/.yarn/cache/json5-npm-1.0.1-647fc8794b-ecb5ab4e23.zip b/.yarn/cache/json5-npm-1.0.1-647fc8794b-ecb5ab4e23.zip deleted file mode 100644 index 786653340292..000000000000 Binary files a/.yarn/cache/json5-npm-1.0.1-647fc8794b-ecb5ab4e23.zip and /dev/null differ diff --git a/.yarn/cache/json5-npm-1.0.2-9607f93e30-a78d812dbb.zip b/.yarn/cache/json5-npm-1.0.2-9607f93e30-a78d812dbb.zip new file mode 100644 index 000000000000..5e1ec8dcf8e4 Binary files /dev/null and b/.yarn/cache/json5-npm-1.0.2-9607f93e30-a78d812dbb.zip differ diff --git a/.yarn/cache/jsonfile-npm-4.0.0-10ce3aea15-17796f0ab1.zip b/.yarn/cache/jsonfile-npm-4.0.0-10ce3aea15-17796f0ab1.zip new file mode 100644 index 000000000000..215fcb1a8940 Binary files /dev/null and b/.yarn/cache/jsonfile-npm-4.0.0-10ce3aea15-17796f0ab1.zip differ diff --git a/.yarn/cache/jsonfile-npm-6.0.1-989c3a9870-7abeaf3a7e.zip b/.yarn/cache/jsonfile-npm-6.0.1-989c3a9870-7abeaf3a7e.zip deleted file mode 100644 index d5ebc63502a7..000000000000 Binary files a/.yarn/cache/jsonfile-npm-6.0.1-989c3a9870-7abeaf3a7e.zip and /dev/null differ diff --git a/.yarn/cache/jsonfile-npm-6.1.0-20a4796cee-03014769e7.zip b/.yarn/cache/jsonfile-npm-6.1.0-20a4796cee-03014769e7.zip new file mode 100644 index 000000000000..a271b8b0da9a Binary files /dev/null and b/.yarn/cache/jsonfile-npm-6.1.0-20a4796cee-03014769e7.zip differ diff --git a/.yarn/cache/jsx-ast-utils-npm-3.3.3-3d3171e1e4-c85f6f2395.zip b/.yarn/cache/jsx-ast-utils-npm-3.3.3-3d3171e1e4-c85f6f2395.zip deleted file mode 100644 index ac88e2e1b980..000000000000 Binary files a/.yarn/cache/jsx-ast-utils-npm-3.3.3-3d3171e1e4-c85f6f2395.zip and /dev/null differ diff --git a/.yarn/cache/jsx-ast-utils-npm-3.3.5-114c80f97a-b61d446136.zip b/.yarn/cache/jsx-ast-utils-npm-3.3.5-114c80f97a-b61d446136.zip new file mode 100644 index 000000000000..1d4d11d18cb4 Binary files /dev/null and b/.yarn/cache/jsx-ast-utils-npm-3.3.5-114c80f97a-b61d446136.zip differ diff --git a/.yarn/cache/just-diff-apply-npm-5.5.0-04951e29f4-5515c436c8.zip b/.yarn/cache/just-diff-apply-npm-5.5.0-04951e29f4-5515c436c8.zip new file mode 100644 index 000000000000..0a517d69afe6 Binary files /dev/null and b/.yarn/cache/just-diff-apply-npm-5.5.0-04951e29f4-5515c436c8.zip differ diff --git a/.yarn/cache/just-diff-npm-6.0.2-f73771d84e-4c6b14d6be.zip b/.yarn/cache/just-diff-npm-6.0.2-f73771d84e-4c6b14d6be.zip new file mode 100644 index 000000000000..d74191ffc817 Binary files /dev/null and b/.yarn/cache/just-diff-npm-6.0.2-f73771d84e-4c6b14d6be.zip differ diff --git a/.yarn/cache/known-css-properties-npm-0.27.0-e139519b4c-3bb274e0a9.zip b/.yarn/cache/known-css-properties-npm-0.27.0-e139519b4c-3bb274e0a9.zip deleted file mode 100644 index 79e938264435..000000000000 Binary files a/.yarn/cache/known-css-properties-npm-0.27.0-e139519b4c-3bb274e0a9.zip and /dev/null differ diff --git a/.yarn/cache/known-css-properties-npm-0.29.0-6bc491faeb-ab4e1d6bad.zip b/.yarn/cache/known-css-properties-npm-0.29.0-6bc491faeb-ab4e1d6bad.zip new file mode 100644 index 000000000000..dd48e27019dd Binary files /dev/null and b/.yarn/cache/known-css-properties-npm-0.29.0-6bc491faeb-ab4e1d6bad.zip differ diff --git a/.yarn/cache/language-subtag-registry-npm-0.3.21-b2d9abe624-86168f7e90.zip b/.yarn/cache/language-subtag-registry-npm-0.3.21-b2d9abe624-86168f7e90.zip deleted file mode 100644 index 637c6b163478..000000000000 Binary files a/.yarn/cache/language-subtag-registry-npm-0.3.21-b2d9abe624-86168f7e90.zip and /dev/null differ diff --git a/.yarn/cache/language-subtag-registry-npm-0.3.23-06b360f90f-fe13ed74ab.zip b/.yarn/cache/language-subtag-registry-npm-0.3.23-06b360f90f-fe13ed74ab.zip new file mode 100644 index 000000000000..71cdc2f1e883 Binary files /dev/null and b/.yarn/cache/language-subtag-registry-npm-0.3.23-06b360f90f-fe13ed74ab.zip differ diff --git a/.yarn/cache/language-tags-npm-1.0.5-3a50e75c96-2161292dda.zip b/.yarn/cache/language-tags-npm-1.0.5-3a50e75c96-2161292dda.zip deleted file mode 100644 index 256cbfc8dded..000000000000 Binary files a/.yarn/cache/language-tags-npm-1.0.5-3a50e75c96-2161292dda.zip and /dev/null differ diff --git a/.yarn/cache/language-tags-npm-1.0.9-3ea51f204b-d3a7c14b69.zip b/.yarn/cache/language-tags-npm-1.0.9-3ea51f204b-d3a7c14b69.zip new file mode 100644 index 000000000000..8878cf0c0b16 Binary files /dev/null and b/.yarn/cache/language-tags-npm-1.0.9-3ea51f204b-d3a7c14b69.zip differ diff --git a/.yarn/cache/launch-editor-npm-2.8.1-6d18da04cb-69adfc913c.zip b/.yarn/cache/launch-editor-npm-2.8.1-6d18da04cb-69adfc913c.zip deleted file mode 100644 index afb6f76df535..000000000000 Binary files a/.yarn/cache/launch-editor-npm-2.8.1-6d18da04cb-69adfc913c.zip and /dev/null differ diff --git a/.yarn/cache/launch-editor-npm-2.9.1-c31ff4d5d6-69eb1e69db.zip b/.yarn/cache/launch-editor-npm-2.9.1-c31ff4d5d6-69eb1e69db.zip new file mode 100644 index 000000000000..43d4cfc9542c Binary files /dev/null and b/.yarn/cache/launch-editor-npm-2.9.1-c31ff4d5d6-69eb1e69db.zip differ diff --git a/.yarn/cache/lazystream-npm-1.0.0-b2ecb17b90-0ed904c069.zip b/.yarn/cache/lazystream-npm-1.0.0-b2ecb17b90-0ed904c069.zip deleted file mode 100644 index a45255753715..000000000000 Binary files a/.yarn/cache/lazystream-npm-1.0.0-b2ecb17b90-0ed904c069.zip and /dev/null differ diff --git a/.yarn/cache/lazystream-npm-1.0.1-7477e64441-35f8cf8b57.zip b/.yarn/cache/lazystream-npm-1.0.1-7477e64441-35f8cf8b57.zip new file mode 100644 index 000000000000..312ab9c66b0c Binary files /dev/null and b/.yarn/cache/lazystream-npm-1.0.1-7477e64441-35f8cf8b57.zip differ diff --git a/.yarn/cache/lerna-npm-8.0.0-3c219d85d8-c829487c5d.zip b/.yarn/cache/lerna-npm-8.0.0-3c219d85d8-c829487c5d.zip deleted file mode 100644 index 4076015f0bbf..000000000000 Binary files a/.yarn/cache/lerna-npm-8.0.0-3c219d85d8-c829487c5d.zip and /dev/null differ diff --git a/.yarn/cache/lerna-npm-8.1.7-ee96f315eb-8286b0634c.zip b/.yarn/cache/lerna-npm-8.1.7-ee96f315eb-8286b0634c.zip new file mode 100644 index 000000000000..d9b69c5f7234 Binary files /dev/null and b/.yarn/cache/lerna-npm-8.1.7-ee96f315eb-8286b0634c.zip differ diff --git a/.yarn/cache/libnpmaccess-npm-7.0.2-57b91bfda5-73d49f3939.zip b/.yarn/cache/libnpmaccess-npm-7.0.2-57b91bfda5-73d49f3939.zip deleted file mode 100644 index 58e75dbe44b9..000000000000 Binary files a/.yarn/cache/libnpmaccess-npm-7.0.2-57b91bfda5-73d49f3939.zip and /dev/null differ diff --git a/.yarn/cache/libnpmaccess-npm-8.0.6-614305a214-62fa6a4763.zip b/.yarn/cache/libnpmaccess-npm-8.0.6-614305a214-62fa6a4763.zip new file mode 100644 index 000000000000..2c4d05b0a6c5 Binary files /dev/null and b/.yarn/cache/libnpmaccess-npm-8.0.6-614305a214-62fa6a4763.zip differ diff --git a/.yarn/cache/libnpmpublish-npm-7.3.0-006fc4afe8-89c8b88108.zip b/.yarn/cache/libnpmpublish-npm-7.3.0-006fc4afe8-89c8b88108.zip deleted file mode 100644 index b04cc39e5d2b..000000000000 Binary files a/.yarn/cache/libnpmpublish-npm-7.3.0-006fc4afe8-89c8b88108.zip and /dev/null differ diff --git a/.yarn/cache/libnpmpublish-npm-9.0.9-8ce39eed08-ea1064a727.zip b/.yarn/cache/libnpmpublish-npm-9.0.9-8ce39eed08-ea1064a727.zip new file mode 100644 index 000000000000..e1fc31cce1ab Binary files /dev/null and b/.yarn/cache/libnpmpublish-npm-9.0.9-8ce39eed08-ea1064a727.zip differ diff --git a/.yarn/cache/lilconfig-npm-2.1.0-a179261924-b1314a2e55.zip b/.yarn/cache/lilconfig-npm-2.1.0-a179261924-b1314a2e55.zip deleted file mode 100644 index 24d1cd79c055..000000000000 Binary files a/.yarn/cache/lilconfig-npm-2.1.0-a179261924-b1314a2e55.zip and /dev/null differ diff --git a/.yarn/cache/lilconfig-npm-3.1.1-b8cdeef996-c80fbf98ae.zip b/.yarn/cache/lilconfig-npm-3.1.1-b8cdeef996-c80fbf98ae.zip deleted file mode 100644 index ca314c4d19ba..000000000000 Binary files a/.yarn/cache/lilconfig-npm-3.1.1-b8cdeef996-c80fbf98ae.zip and /dev/null differ diff --git a/.yarn/cache/lilconfig-npm-3.1.2-e5b7292949-8058403850.zip b/.yarn/cache/lilconfig-npm-3.1.2-e5b7292949-8058403850.zip new file mode 100644 index 000000000000..6e6a74f62361 Binary files /dev/null and b/.yarn/cache/lilconfig-npm-3.1.2-e5b7292949-8058403850.zip differ diff --git a/.yarn/cache/lines-and-columns-npm-1.1.6-23e74fab67-198a5436b1.zip b/.yarn/cache/lines-and-columns-npm-1.1.6-23e74fab67-198a5436b1.zip deleted file mode 100644 index 7a35cefdf5fc..000000000000 Binary files a/.yarn/cache/lines-and-columns-npm-1.1.6-23e74fab67-198a5436b1.zip and /dev/null differ diff --git a/.yarn/cache/lines-and-columns-npm-1.2.4-d6c7cc5799-0c37f9f7fa.zip b/.yarn/cache/lines-and-columns-npm-1.2.4-d6c7cc5799-0c37f9f7fa.zip new file mode 100644 index 000000000000..273106a73c22 Binary files /dev/null and b/.yarn/cache/lines-and-columns-npm-1.2.4-d6c7cc5799-0c37f9f7fa.zip differ diff --git a/.yarn/cache/lines-and-columns-npm-2.0.3-68ede50723-b5bb0d6ee2.zip b/.yarn/cache/lines-and-columns-npm-2.0.3-68ede50723-b5bb0d6ee2.zip deleted file mode 100644 index 949f3d4ea2ee..000000000000 Binary files a/.yarn/cache/lines-and-columns-npm-2.0.3-68ede50723-b5bb0d6ee2.zip and /dev/null differ diff --git a/.yarn/cache/lines-and-columns-npm-2.0.4-e433f5a96f-81ac2f943f.zip b/.yarn/cache/lines-and-columns-npm-2.0.4-e433f5a96f-81ac2f943f.zip new file mode 100644 index 000000000000..34d96052751f Binary files /dev/null and b/.yarn/cache/lines-and-columns-npm-2.0.4-e433f5a96f-81ac2f943f.zip differ diff --git a/.yarn/cache/lint-staged-npm-15.1.0-b45b212a0d-77aacab303.zip b/.yarn/cache/lint-staged-npm-15.1.0-b45b212a0d-77aacab303.zip deleted file mode 100644 index 0333a4216701..000000000000 Binary files a/.yarn/cache/lint-staged-npm-15.1.0-b45b212a0d-77aacab303.zip and /dev/null differ diff --git a/.yarn/cache/lint-staged-npm-15.2.7-2a90203033-7557bcf4e8.zip b/.yarn/cache/lint-staged-npm-15.2.7-2a90203033-7557bcf4e8.zip new file mode 100644 index 000000000000..80be25ddf19b Binary files /dev/null and b/.yarn/cache/lint-staged-npm-15.2.7-2a90203033-7557bcf4e8.zip differ diff --git a/.yarn/cache/listr2-npm-7.0.2-42ddc71dba-42cda57649.zip b/.yarn/cache/listr2-npm-7.0.2-42ddc71dba-42cda57649.zip deleted file mode 100644 index 9cb098274842..000000000000 Binary files a/.yarn/cache/listr2-npm-7.0.2-42ddc71dba-42cda57649.zip and /dev/null differ diff --git a/.yarn/cache/listr2-npm-8.2.4-d0c10a89e0-344d2397e1.zip b/.yarn/cache/listr2-npm-8.2.4-d0c10a89e0-344d2397e1.zip new file mode 100644 index 000000000000..5067cd6c33b8 Binary files /dev/null and b/.yarn/cache/listr2-npm-8.2.4-d0c10a89e0-344d2397e1.zip differ diff --git a/.yarn/cache/lit-element-npm-4.0.6-bfca4f9870-31b4400fbf.zip b/.yarn/cache/lit-element-npm-4.0.6-bfca4f9870-31b4400fbf.zip new file mode 100644 index 000000000000..7097314e220e Binary files /dev/null and b/.yarn/cache/lit-element-npm-4.0.6-bfca4f9870-31b4400fbf.zip differ diff --git a/.yarn/cache/lit-html-npm-3.1.4-58e56c5010-0f95b7e6fd.zip b/.yarn/cache/lit-html-npm-3.1.4-58e56c5010-0f95b7e6fd.zip new file mode 100644 index 000000000000..d768ba2b0ddc Binary files /dev/null and b/.yarn/cache/lit-html-npm-3.1.4-58e56c5010-0f95b7e6fd.zip differ diff --git a/.yarn/cache/lit-npm-3.1.4-b7dcc2d5a3-5479981882.zip b/.yarn/cache/lit-npm-3.1.4-b7dcc2d5a3-5479981882.zip new file mode 100644 index 000000000000..084d02e2ed13 Binary files /dev/null and b/.yarn/cache/lit-npm-3.1.4-b7dcc2d5a3-5479981882.zip differ diff --git a/.yarn/cache/loader-runner-npm-4.2.0-427f0e7134-89a648e041.zip b/.yarn/cache/loader-runner-npm-4.2.0-427f0e7134-89a648e041.zip deleted file mode 100644 index 29a6e8b6196c..000000000000 Binary files a/.yarn/cache/loader-runner-npm-4.2.0-427f0e7134-89a648e041.zip and /dev/null differ diff --git a/.yarn/cache/loader-runner-npm-4.3.0-9ca67df372-555ae00286.zip b/.yarn/cache/loader-runner-npm-4.3.0-9ca67df372-555ae00286.zip new file mode 100644 index 000000000000..452fc572b406 Binary files /dev/null and b/.yarn/cache/loader-runner-npm-4.3.0-9ca67df372-555ae00286.zip differ diff --git a/.yarn/cache/loader-utils-npm-2.0.4-ba3800585b-28bd9af202.zip b/.yarn/cache/loader-utils-npm-2.0.4-ba3800585b-28bd9af202.zip new file mode 100644 index 000000000000..7f203315bd25 Binary files /dev/null and b/.yarn/cache/loader-utils-npm-2.0.4-ba3800585b-28bd9af202.zip differ diff --git a/.yarn/cache/lodash-es-npm-4.17.21-b45832dfce-03f39878ea.zip b/.yarn/cache/lodash-es-npm-4.17.21-b45832dfce-03f39878ea.zip new file mode 100644 index 000000000000..dc6b4a19e850 Binary files /dev/null and b/.yarn/cache/lodash-es-npm-4.17.21-b45832dfce-03f39878ea.zip differ diff --git a/.yarn/cache/log-update-npm-5.0.1-1e016d7086-0e154e4674.zip b/.yarn/cache/log-update-npm-5.0.1-1e016d7086-0e154e4674.zip deleted file mode 100644 index a7456ec16f6a..000000000000 Binary files a/.yarn/cache/log-update-npm-5.0.1-1e016d7086-0e154e4674.zip and /dev/null differ diff --git a/.yarn/cache/log-update-npm-6.1.0-2ca9435417-5abb4131e3.zip b/.yarn/cache/log-update-npm-6.1.0-2ca9435417-5abb4131e3.zip new file mode 100644 index 000000000000..5576a6b53acd Binary files /dev/null and b/.yarn/cache/log-update-npm-6.1.0-2ca9435417-5abb4131e3.zip differ diff --git a/.yarn/cache/lru-cache-npm-10.2.2-c54b721fc3-ff1a496d30.zip b/.yarn/cache/lru-cache-npm-10.2.2-c54b721fc3-ff1a496d30.zip deleted file mode 100644 index 7e71190c37ee..000000000000 Binary files a/.yarn/cache/lru-cache-npm-10.2.2-c54b721fc3-ff1a496d30.zip and /dev/null differ diff --git a/.yarn/cache/lru-cache-npm-10.4.3-30c10b861a-e6e9026736.zip b/.yarn/cache/lru-cache-npm-10.4.3-30c10b861a-e6e9026736.zip new file mode 100644 index 000000000000..bbfe243d96c8 Binary files /dev/null and b/.yarn/cache/lru-cache-npm-10.4.3-30c10b861a-e6e9026736.zip differ diff --git a/.yarn/cache/lru-cache-npm-7.14.1-d3ba9407b6-f29a86e9eb.zip b/.yarn/cache/lru-cache-npm-7.14.1-d3ba9407b6-f29a86e9eb.zip deleted file mode 100644 index 02f36addae42..000000000000 Binary files a/.yarn/cache/lru-cache-npm-7.14.1-d3ba9407b6-f29a86e9eb.zip and /dev/null differ diff --git a/.yarn/cache/lru-cache-npm-7.18.3-e68be5b11c-6029ca5aba.zip b/.yarn/cache/lru-cache-npm-7.18.3-e68be5b11c-6029ca5aba.zip new file mode 100644 index 000000000000..9fa50d3ff269 Binary files /dev/null and b/.yarn/cache/lru-cache-npm-7.18.3-e68be5b11c-6029ca5aba.zip differ diff --git a/.yarn/cache/magic-string-npm-0.26.7-07281acc06-2bb371d956.zip b/.yarn/cache/magic-string-npm-0.26.7-07281acc06-2bb371d956.zip deleted file mode 100644 index fd6cedd0358b..000000000000 Binary files a/.yarn/cache/magic-string-npm-0.26.7-07281acc06-2bb371d956.zip and /dev/null differ diff --git a/.yarn/cache/magic-string-npm-0.30.5-dffb7e6a73-c8a6b25f81.zip b/.yarn/cache/magic-string-npm-0.30.5-dffb7e6a73-c8a6b25f81.zip new file mode 100644 index 000000000000..aa92f2c7ac3a Binary files /dev/null and b/.yarn/cache/magic-string-npm-0.30.5-dffb7e6a73-c8a6b25f81.zip differ diff --git a/.yarn/cache/make-fetch-happen-npm-10.2.1-f1cc7cd2df-fef5acb865.zip b/.yarn/cache/make-fetch-happen-npm-10.2.1-f1cc7cd2df-fef5acb865.zip deleted file mode 100644 index 36ed8e9c9ad6..000000000000 Binary files a/.yarn/cache/make-fetch-happen-npm-10.2.1-f1cc7cd2df-fef5acb865.zip and /dev/null differ diff --git a/.yarn/cache/make-fetch-happen-npm-11.1.1-f32b79aaaa-b4b442cfaa.zip b/.yarn/cache/make-fetch-happen-npm-11.1.1-f32b79aaaa-b4b442cfaa.zip deleted file mode 100644 index 9866cd387c1b..000000000000 Binary files a/.yarn/cache/make-fetch-happen-npm-11.1.1-f32b79aaaa-b4b442cfaa.zip and /dev/null differ diff --git a/.yarn/cache/make-fetch-happen-npm-13.0.1-4180f2aaa8-11bae5ad6a.zip b/.yarn/cache/make-fetch-happen-npm-13.0.1-4180f2aaa8-11bae5ad6a.zip new file mode 100644 index 000000000000..0a175be131d2 Binary files /dev/null and b/.yarn/cache/make-fetch-happen-npm-13.0.1-4180f2aaa8-11bae5ad6a.zip differ diff --git a/.yarn/cache/markdown-table-npm-2.0.0-a9c10c8e83-8018cd1a17.zip b/.yarn/cache/markdown-table-npm-2.0.0-a9c10c8e83-8018cd1a17.zip new file mode 100644 index 000000000000..f4a7678c275f Binary files /dev/null and b/.yarn/cache/markdown-table-npm-2.0.0-a9c10c8e83-8018cd1a17.zip differ diff --git a/.yarn/cache/mdast-util-find-and-replace-npm-1.1.1-3fa14ec655-e4c9e50d9b.zip b/.yarn/cache/mdast-util-find-and-replace-npm-1.1.1-3fa14ec655-e4c9e50d9b.zip new file mode 100644 index 000000000000..54f684d7a9ad Binary files /dev/null and b/.yarn/cache/mdast-util-find-and-replace-npm-1.1.1-3fa14ec655-e4c9e50d9b.zip differ diff --git a/.yarn/cache/mdast-util-footnote-npm-0.1.7-c5e39e294e-b59d8989d3.zip b/.yarn/cache/mdast-util-footnote-npm-0.1.7-c5e39e294e-b59d8989d3.zip new file mode 100644 index 000000000000..6395739b9a25 Binary files /dev/null and b/.yarn/cache/mdast-util-footnote-npm-0.1.7-c5e39e294e-b59d8989d3.zip differ diff --git a/.yarn/cache/mdast-util-from-markdown-npm-0.8.5-0b8b6dc7ba-f42166eb7a.zip b/.yarn/cache/mdast-util-from-markdown-npm-0.8.5-0b8b6dc7ba-f42166eb7a.zip new file mode 100644 index 000000000000..d188709ea42a Binary files /dev/null and b/.yarn/cache/mdast-util-from-markdown-npm-0.8.5-0b8b6dc7ba-f42166eb7a.zip differ diff --git a/.yarn/cache/mdast-util-frontmatter-npm-0.2.0-c07c93d080-bdef2318cf.zip b/.yarn/cache/mdast-util-frontmatter-npm-0.2.0-c07c93d080-bdef2318cf.zip new file mode 100644 index 000000000000..2a45ef90b162 Binary files /dev/null and b/.yarn/cache/mdast-util-frontmatter-npm-0.2.0-c07c93d080-bdef2318cf.zip differ diff --git a/.yarn/cache/mdast-util-gfm-autolink-literal-npm-0.1.3-0519a9747b-9f7b888678.zip b/.yarn/cache/mdast-util-gfm-autolink-literal-npm-0.1.3-0519a9747b-9f7b888678.zip new file mode 100644 index 000000000000..8134a3be4608 Binary files /dev/null and b/.yarn/cache/mdast-util-gfm-autolink-literal-npm-0.1.3-0519a9747b-9f7b888678.zip differ diff --git a/.yarn/cache/mdast-util-gfm-npm-0.1.2-5d42a31a00-64cd342f70.zip b/.yarn/cache/mdast-util-gfm-npm-0.1.2-5d42a31a00-64cd342f70.zip new file mode 100644 index 000000000000..74ae93a26935 Binary files /dev/null and b/.yarn/cache/mdast-util-gfm-npm-0.1.2-5d42a31a00-64cd342f70.zip differ diff --git a/.yarn/cache/mdast-util-gfm-strikethrough-npm-0.2.3-41f0424f58-51aa11ca8f.zip b/.yarn/cache/mdast-util-gfm-strikethrough-npm-0.2.3-41f0424f58-51aa11ca8f.zip new file mode 100644 index 000000000000..4c3281c58dd2 Binary files /dev/null and b/.yarn/cache/mdast-util-gfm-strikethrough-npm-0.2.3-41f0424f58-51aa11ca8f.zip differ diff --git a/.yarn/cache/mdast-util-gfm-table-npm-0.1.6-399704a3e4-06fe08f74f.zip b/.yarn/cache/mdast-util-gfm-table-npm-0.1.6-399704a3e4-06fe08f74f.zip new file mode 100644 index 000000000000..01a51dbce29d Binary files /dev/null and b/.yarn/cache/mdast-util-gfm-table-npm-0.1.6-399704a3e4-06fe08f74f.zip differ diff --git a/.yarn/cache/mdast-util-gfm-task-list-item-npm-0.1.6-5f9654a3db-da5ae0d621.zip b/.yarn/cache/mdast-util-gfm-task-list-item-npm-0.1.6-5f9654a3db-da5ae0d621.zip new file mode 100644 index 000000000000..50fd501ad833 Binary files /dev/null and b/.yarn/cache/mdast-util-gfm-task-list-item-npm-0.1.6-5f9654a3db-da5ae0d621.zip differ diff --git a/.yarn/cache/mdast-util-to-markdown-npm-0.6.5-6da59c9db9-e1fdb7a75f.zip b/.yarn/cache/mdast-util-to-markdown-npm-0.6.5-6da59c9db9-e1fdb7a75f.zip new file mode 100644 index 000000000000..bd49a2fd2805 Binary files /dev/null and b/.yarn/cache/mdast-util-to-markdown-npm-0.6.5-6da59c9db9-e1fdb7a75f.zip differ diff --git a/.yarn/cache/mdast-util-to-string-npm-2.0.0-3a5d9c4970-0b2113ada1.zip b/.yarn/cache/mdast-util-to-string-npm-2.0.0-3a5d9c4970-0b2113ada1.zip new file mode 100644 index 000000000000..e072583645a3 Binary files /dev/null and b/.yarn/cache/mdast-util-to-string-npm-2.0.0-3a5d9c4970-0b2113ada1.zip differ diff --git a/.yarn/cache/merge-descriptors-npm-1.0.1-615287aaa8-5abc259d2a.zip b/.yarn/cache/merge-descriptors-npm-1.0.1-615287aaa8-5abc259d2a.zip new file mode 100644 index 000000000000..8bba31611bbd Binary files /dev/null and b/.yarn/cache/merge-descriptors-npm-1.0.1-615287aaa8-5abc259d2a.zip differ diff --git a/.yarn/cache/merge-descriptors-npm-1.0.3-10b44ad75c-52117adbe0.zip b/.yarn/cache/merge-descriptors-npm-1.0.3-10b44ad75c-52117adbe0.zip deleted file mode 100644 index ef5ade8f0c27..000000000000 Binary files a/.yarn/cache/merge-descriptors-npm-1.0.3-10b44ad75c-52117adbe0.zip and /dev/null differ diff --git a/.yarn/cache/micromark-extension-footnote-npm-0.3.2-7333bd280e-73cca7fca9.zip b/.yarn/cache/micromark-extension-footnote-npm-0.3.2-7333bd280e-73cca7fca9.zip new file mode 100644 index 000000000000..ca170b7a2338 Binary files /dev/null and b/.yarn/cache/micromark-extension-footnote-npm-0.3.2-7333bd280e-73cca7fca9.zip differ diff --git a/.yarn/cache/micromark-extension-frontmatter-npm-0.2.2-9bd552040c-011a4b1f00.zip b/.yarn/cache/micromark-extension-frontmatter-npm-0.2.2-9bd552040c-011a4b1f00.zip new file mode 100644 index 000000000000..59c6feab3df0 Binary files /dev/null and b/.yarn/cache/micromark-extension-frontmatter-npm-0.2.2-9bd552040c-011a4b1f00.zip differ diff --git a/.yarn/cache/micromark-extension-gfm-autolink-literal-npm-0.5.7-a11254fccb-107e4aa392.zip b/.yarn/cache/micromark-extension-gfm-autolink-literal-npm-0.5.7-a11254fccb-107e4aa392.zip new file mode 100644 index 000000000000..c5b833d413da Binary files /dev/null and b/.yarn/cache/micromark-extension-gfm-autolink-literal-npm-0.5.7-a11254fccb-107e4aa392.zip differ diff --git a/.yarn/cache/micromark-extension-gfm-npm-0.3.3-dd65921af7-653102f7a6.zip b/.yarn/cache/micromark-extension-gfm-npm-0.3.3-dd65921af7-653102f7a6.zip new file mode 100644 index 000000000000..361e70400420 Binary files /dev/null and b/.yarn/cache/micromark-extension-gfm-npm-0.3.3-dd65921af7-653102f7a6.zip differ diff --git a/.yarn/cache/micromark-extension-gfm-strikethrough-npm-0.6.5-5c5773e29d-6771163359.zip b/.yarn/cache/micromark-extension-gfm-strikethrough-npm-0.6.5-5c5773e29d-6771163359.zip new file mode 100644 index 000000000000..0ff34c8ae996 Binary files /dev/null and b/.yarn/cache/micromark-extension-gfm-strikethrough-npm-0.6.5-5c5773e29d-6771163359.zip differ diff --git a/.yarn/cache/micromark-extension-gfm-table-npm-0.4.3-def4c94965-aa1f583966.zip b/.yarn/cache/micromark-extension-gfm-table-npm-0.4.3-def4c94965-aa1f583966.zip new file mode 100644 index 000000000000..fb96a26f2add Binary files /dev/null and b/.yarn/cache/micromark-extension-gfm-table-npm-0.4.3-def4c94965-aa1f583966.zip differ diff --git a/.yarn/cache/micromark-extension-gfm-tagfilter-npm-0.3.0-86cdab9b4e-9369736a20.zip b/.yarn/cache/micromark-extension-gfm-tagfilter-npm-0.3.0-86cdab9b4e-9369736a20.zip new file mode 100644 index 000000000000..2ca7a59f2ff1 Binary files /dev/null and b/.yarn/cache/micromark-extension-gfm-tagfilter-npm-0.3.0-86cdab9b4e-9369736a20.zip differ diff --git a/.yarn/cache/micromark-extension-gfm-task-list-item-npm-0.3.3-72b31dda9a-e4ccbe6b44.zip b/.yarn/cache/micromark-extension-gfm-task-list-item-npm-0.3.3-72b31dda9a-e4ccbe6b44.zip new file mode 100644 index 000000000000..08c773acafed Binary files /dev/null and b/.yarn/cache/micromark-extension-gfm-task-list-item-npm-0.3.3-72b31dda9a-e4ccbe6b44.zip differ diff --git a/.yarn/cache/micromark-npm-2.11.4-f7ec94840a-cd3bcbc4c1.zip b/.yarn/cache/micromark-npm-2.11.4-f7ec94840a-cd3bcbc4c1.zip new file mode 100644 index 000000000000..4b2407cd6535 Binary files /dev/null and b/.yarn/cache/micromark-npm-2.11.4-f7ec94840a-cd3bcbc4c1.zip differ diff --git a/.yarn/cache/micromatch-npm-4.0.5-cfab5d7669-a749888789.zip b/.yarn/cache/micromatch-npm-4.0.5-cfab5d7669-a749888789.zip deleted file mode 100644 index 4af36001b41d..000000000000 Binary files a/.yarn/cache/micromatch-npm-4.0.5-cfab5d7669-a749888789.zip and /dev/null differ diff --git a/.yarn/cache/mime-db-npm-1.53.0-14fcdba2be-82409c568a.zip b/.yarn/cache/mime-db-npm-1.53.0-14fcdba2be-82409c568a.zip new file mode 100644 index 000000000000..fcf3aeada50a Binary files /dev/null and b/.yarn/cache/mime-db-npm-1.53.0-14fcdba2be-82409c568a.zip differ diff --git a/.yarn/cache/mimic-function-npm-5.0.1-5078456e31-eb5893c99e.zip b/.yarn/cache/mimic-function-npm-5.0.1-5078456e31-eb5893c99e.zip new file mode 100644 index 000000000000..034d272ae13d Binary files /dev/null and b/.yarn/cache/mimic-function-npm-5.0.1-5078456e31-eb5893c99e.zip differ diff --git a/.yarn/cache/mini-css-extract-plugin-npm-2.4.5-001e2b144b-abed70be4f.zip b/.yarn/cache/mini-css-extract-plugin-npm-2.4.5-001e2b144b-abed70be4f.zip deleted file mode 100644 index 93535b4f461f..000000000000 Binary files a/.yarn/cache/mini-css-extract-plugin-npm-2.4.5-001e2b144b-abed70be4f.zip and /dev/null differ diff --git a/.yarn/cache/mini-css-extract-plugin-npm-2.9.0-e9682fccac-4c9ee9c0c6.zip b/.yarn/cache/mini-css-extract-plugin-npm-2.9.0-e9682fccac-4c9ee9c0c6.zip new file mode 100644 index 000000000000..c8803f059cd0 Binary files /dev/null and b/.yarn/cache/mini-css-extract-plugin-npm-2.9.0-e9682fccac-4c9ee9c0c6.zip differ diff --git a/.yarn/cache/minimatch-npm-9.0.3-69d7d6fad5-c81b47d281.zip b/.yarn/cache/minimatch-npm-9.0.3-69d7d6fad5-c81b47d281.zip new file mode 100644 index 000000000000..dc6ab1689133 Binary files /dev/null and b/.yarn/cache/minimatch-npm-9.0.3-69d7d6fad5-c81b47d281.zip differ diff --git a/.yarn/cache/minimatch-npm-9.0.4-7be5a33efc-4cdc18d112.zip b/.yarn/cache/minimatch-npm-9.0.4-7be5a33efc-4cdc18d112.zip deleted file mode 100644 index 61a88c7c69db..000000000000 Binary files a/.yarn/cache/minimatch-npm-9.0.4-7be5a33efc-4cdc18d112.zip and /dev/null differ diff --git a/.yarn/cache/minimatch-npm-9.0.5-9aa93d97fa-dd6a8927b0.zip b/.yarn/cache/minimatch-npm-9.0.5-9aa93d97fa-dd6a8927b0.zip new file mode 100644 index 000000000000..4b97afd8310e Binary files /dev/null and b/.yarn/cache/minimatch-npm-9.0.5-9aa93d97fa-dd6a8927b0.zip differ diff --git a/.yarn/cache/minipass-collect-npm-1.0.2-3b4676eab5-14df761028.zip b/.yarn/cache/minipass-collect-npm-1.0.2-3b4676eab5-14df761028.zip deleted file mode 100644 index 582f61ca2a8a..000000000000 Binary files a/.yarn/cache/minipass-collect-npm-1.0.2-3b4676eab5-14df761028.zip and /dev/null differ diff --git a/.yarn/cache/minipass-collect-npm-2.0.1-73d3907e40-b251bceea6.zip b/.yarn/cache/minipass-collect-npm-2.0.1-73d3907e40-b251bceea6.zip new file mode 100644 index 000000000000..96df703423d6 Binary files /dev/null and b/.yarn/cache/minipass-collect-npm-2.0.1-73d3907e40-b251bceea6.zip differ diff --git a/.yarn/cache/minipass-fetch-npm-2.1.2-9b21a5c930-8cfc589563.zip b/.yarn/cache/minipass-fetch-npm-2.1.2-9b21a5c930-8cfc589563.zip deleted file mode 100644 index 4fe0911be6e4..000000000000 Binary files a/.yarn/cache/minipass-fetch-npm-2.1.2-9b21a5c930-8cfc589563.zip and /dev/null differ diff --git a/.yarn/cache/minipass-fetch-npm-3.0.3-2c4966d142-045339fa8f.zip b/.yarn/cache/minipass-fetch-npm-3.0.3-2c4966d142-045339fa8f.zip deleted file mode 100644 index 10b6a4d57516..000000000000 Binary files a/.yarn/cache/minipass-fetch-npm-3.0.3-2c4966d142-045339fa8f.zip and /dev/null differ diff --git a/.yarn/cache/minipass-fetch-npm-3.0.5-ed78529694-c669948bec.zip b/.yarn/cache/minipass-fetch-npm-3.0.5-ed78529694-c669948bec.zip new file mode 100644 index 000000000000..c6e732a9304e Binary files /dev/null and b/.yarn/cache/minipass-fetch-npm-3.0.5-ed78529694-c669948bec.zip differ diff --git a/.yarn/cache/minipass-json-stream-npm-1.0.1-96490706d6-3c65482c63.zip b/.yarn/cache/minipass-json-stream-npm-1.0.1-96490706d6-3c65482c63.zip deleted file mode 100644 index ce35fdf357a0..000000000000 Binary files a/.yarn/cache/minipass-json-stream-npm-1.0.1-96490706d6-3c65482c63.zip and /dev/null differ diff --git a/.yarn/cache/mlly-npm-1.7.1-c00aa0548e-c1ef3989e9.zip b/.yarn/cache/mlly-npm-1.7.1-c00aa0548e-c1ef3989e9.zip new file mode 100644 index 000000000000..4a4267430fec Binary files /dev/null and b/.yarn/cache/mlly-npm-1.7.1-c00aa0548e-c1ef3989e9.zip differ diff --git a/.yarn/cache/mri-npm-1.2.0-8ecee0357d-6775a1d222.zip b/.yarn/cache/mri-npm-1.2.0-8ecee0357d-6775a1d222.zip deleted file mode 100644 index 7521d190f3bd..000000000000 Binary files a/.yarn/cache/mri-npm-1.2.0-8ecee0357d-6775a1d222.zip and /dev/null differ diff --git a/.yarn/cache/netmask-npm-2.0.2-2299510a4d-375cabe898.zip b/.yarn/cache/netmask-npm-2.0.2-2299510a4d-375cabe898.zip new file mode 100644 index 000000000000..2c53ca77a762 Binary files /dev/null and b/.yarn/cache/netmask-npm-2.0.2-2299510a4d-375cabe898.zip differ diff --git a/.yarn/cache/next-npm-14.2.5-ce63d89d89-c107b45ffe.zip b/.yarn/cache/next-npm-14.2.5-ce63d89d89-c107b45ffe.zip new file mode 100644 index 000000000000..85355ea27f39 Binary files /dev/null and b/.yarn/cache/next-npm-14.2.5-ce63d89d89-c107b45ffe.zip differ diff --git a/.yarn/cache/node-fetch-native-npm-1.1.1-8175e7200a-c16a186958.zip b/.yarn/cache/node-fetch-native-npm-1.1.1-8175e7200a-c16a186958.zip deleted file mode 100644 index ac15814b91ac..000000000000 Binary files a/.yarn/cache/node-fetch-native-npm-1.1.1-8175e7200a-c16a186958.zip and /dev/null differ diff --git a/.yarn/cache/node-fetch-native-npm-1.6.4-074aca088e-39c4c6d0c2.zip b/.yarn/cache/node-fetch-native-npm-1.6.4-074aca088e-39c4c6d0c2.zip new file mode 100644 index 000000000000..907759b3e129 Binary files /dev/null and b/.yarn/cache/node-fetch-native-npm-1.6.4-074aca088e-39c4c6d0c2.zip differ diff --git a/.yarn/cache/node-gyp-npm-10.2.0-cad1109948-41773093b1.zip b/.yarn/cache/node-gyp-npm-10.2.0-cad1109948-41773093b1.zip new file mode 100644 index 000000000000..9fb27826be0b Binary files /dev/null and b/.yarn/cache/node-gyp-npm-10.2.0-cad1109948-41773093b1.zip differ diff --git a/.yarn/cache/node-gyp-npm-9.3.1-43540bab9c-e9345b22be.zip b/.yarn/cache/node-gyp-npm-9.3.1-43540bab9c-e9345b22be.zip deleted file mode 100644 index a4795e3e01ce..000000000000 Binary files a/.yarn/cache/node-gyp-npm-9.3.1-43540bab9c-e9345b22be.zip and /dev/null differ diff --git a/.yarn/cache/nopt-npm-6.0.0-5ea8050815-3c1128e07c.zip b/.yarn/cache/nopt-npm-6.0.0-5ea8050815-3c1128e07c.zip deleted file mode 100644 index 6f93e1b21e6e..000000000000 Binary files a/.yarn/cache/nopt-npm-6.0.0-5ea8050815-3c1128e07c.zip and /dev/null differ diff --git a/.yarn/cache/nopt-npm-7.2.1-635b7da949-95a1f6dec8.zip b/.yarn/cache/nopt-npm-7.2.1-635b7da949-95a1f6dec8.zip new file mode 100644 index 000000000000..3923e507ebc1 Binary files /dev/null and b/.yarn/cache/nopt-npm-7.2.1-635b7da949-95a1f6dec8.zip differ diff --git a/.yarn/cache/normalize-package-data-npm-5.0.0-6327e2af68-477344ee99.zip b/.yarn/cache/normalize-package-data-npm-5.0.0-6327e2af68-477344ee99.zip deleted file mode 100644 index df5fdc55adad..000000000000 Binary files a/.yarn/cache/normalize-package-data-npm-5.0.0-6327e2af68-477344ee99.zip and /dev/null differ diff --git a/.yarn/cache/normalize-package-data-npm-6.0.2-dc1f732439-7c4216a242.zip b/.yarn/cache/normalize-package-data-npm-6.0.2-dc1f732439-7c4216a242.zip new file mode 100644 index 000000000000..558f77b1984b Binary files /dev/null and b/.yarn/cache/normalize-package-data-npm-6.0.2-dc1f732439-7c4216a242.zip differ diff --git a/.yarn/cache/normalize-url-npm-4.5.0-14a0c5430f-c70ee89880.zip b/.yarn/cache/normalize-url-npm-4.5.0-14a0c5430f-c70ee89880.zip deleted file mode 100644 index 05ff59cf2f99..000000000000 Binary files a/.yarn/cache/normalize-url-npm-4.5.0-14a0c5430f-c70ee89880.zip and /dev/null differ diff --git a/.yarn/cache/normalize-url-npm-4.5.1-603d40bc18-20ced2845f.zip b/.yarn/cache/normalize-url-npm-4.5.1-603d40bc18-20ced2845f.zip new file mode 100644 index 000000000000..a7687e8278a6 Binary files /dev/null and b/.yarn/cache/normalize-url-npm-4.5.1-603d40bc18-20ced2845f.zip differ diff --git a/.yarn/cache/normalize-url-npm-8.0.0-1f5dc7ece5-4347d6ee39.zip b/.yarn/cache/normalize-url-npm-8.0.0-1f5dc7ece5-4347d6ee39.zip deleted file mode 100644 index a3c3f09ce838..000000000000 Binary files a/.yarn/cache/normalize-url-npm-8.0.0-1f5dc7ece5-4347d6ee39.zip and /dev/null differ diff --git a/.yarn/cache/normalize-url-npm-8.0.1-c87adbf3f1-ae39203758.zip b/.yarn/cache/normalize-url-npm-8.0.1-c87adbf3f1-ae39203758.zip new file mode 100644 index 000000000000..58f9aead9f5a Binary files /dev/null and b/.yarn/cache/normalize-url-npm-8.0.1-c87adbf3f1-ae39203758.zip differ diff --git a/.yarn/cache/npm-bundled-npm-1.1.2-e299e533ef-722154cb5e.zip b/.yarn/cache/npm-bundled-npm-1.1.2-e299e533ef-722154cb5e.zip deleted file mode 100644 index 42f8ccbeb32e..000000000000 Binary files a/.yarn/cache/npm-bundled-npm-1.1.2-e299e533ef-722154cb5e.zip and /dev/null differ diff --git a/.yarn/cache/npm-bundled-npm-3.0.0-0b3c5ee4f3-704fce2011.zip b/.yarn/cache/npm-bundled-npm-3.0.0-0b3c5ee4f3-704fce2011.zip deleted file mode 100644 index a991d51e4f63..000000000000 Binary files a/.yarn/cache/npm-bundled-npm-3.0.0-0b3c5ee4f3-704fce2011.zip and /dev/null differ diff --git a/.yarn/cache/npm-bundled-npm-3.0.1-e98b9846dc-113c9a3552.zip b/.yarn/cache/npm-bundled-npm-3.0.1-e98b9846dc-113c9a3552.zip new file mode 100644 index 000000000000..fb63b788d22d Binary files /dev/null and b/.yarn/cache/npm-bundled-npm-3.0.1-e98b9846dc-113c9a3552.zip differ diff --git a/.yarn/cache/npm-install-checks-npm-6.1.1-e05db36ccf-8fb3ed05cf.zip b/.yarn/cache/npm-install-checks-npm-6.1.1-e05db36ccf-8fb3ed05cf.zip deleted file mode 100644 index 42723c441579..000000000000 Binary files a/.yarn/cache/npm-install-checks-npm-6.1.1-e05db36ccf-8fb3ed05cf.zip and /dev/null differ diff --git a/.yarn/cache/npm-install-checks-npm-6.3.0-d093d4e008-6c20dadb87.zip b/.yarn/cache/npm-install-checks-npm-6.3.0-d093d4e008-6c20dadb87.zip new file mode 100644 index 000000000000..95ac8acffbcd Binary files /dev/null and b/.yarn/cache/npm-install-checks-npm-6.3.0-d093d4e008-6c20dadb87.zip differ diff --git a/.yarn/cache/npm-normalize-package-bin-npm-1.0.1-2cf38a5d95-b61593d1af.zip b/.yarn/cache/npm-normalize-package-bin-npm-1.0.1-2cf38a5d95-b61593d1af.zip deleted file mode 100644 index d1ca212ce5b2..000000000000 Binary files a/.yarn/cache/npm-normalize-package-bin-npm-1.0.1-2cf38a5d95-b61593d1af.zip and /dev/null differ diff --git a/.yarn/cache/npm-package-arg-npm-10.1.0-e9f0aaa69d-3bbb5f0810.zip b/.yarn/cache/npm-package-arg-npm-10.1.0-e9f0aaa69d-3bbb5f0810.zip deleted file mode 100644 index 75172e52b3a4..000000000000 Binary files a/.yarn/cache/npm-package-arg-npm-10.1.0-e9f0aaa69d-3bbb5f0810.zip and /dev/null differ diff --git a/.yarn/cache/npm-package-arg-npm-11.0.2-bd9cd2ed92-ce4c51900a.zip b/.yarn/cache/npm-package-arg-npm-11.0.2-bd9cd2ed92-ce4c51900a.zip new file mode 100644 index 000000000000..6545444d2f8f Binary files /dev/null and b/.yarn/cache/npm-package-arg-npm-11.0.2-bd9cd2ed92-ce4c51900a.zip differ diff --git a/.yarn/cache/npm-package-arg-npm-11.0.3-7ba5df96a1-bacc863907.zip b/.yarn/cache/npm-package-arg-npm-11.0.3-7ba5df96a1-bacc863907.zip new file mode 100644 index 000000000000..fe51bd966b1e Binary files /dev/null and b/.yarn/cache/npm-package-arg-npm-11.0.3-7ba5df96a1-bacc863907.zip differ diff --git a/.yarn/cache/npm-package-arg-npm-8.1.1-044819f446-b50b130680.zip b/.yarn/cache/npm-package-arg-npm-8.1.1-044819f446-b50b130680.zip deleted file mode 100644 index 2fcfb62d3a4d..000000000000 Binary files a/.yarn/cache/npm-package-arg-npm-8.1.1-044819f446-b50b130680.zip and /dev/null differ diff --git a/.yarn/cache/npm-packlist-npm-5.1.1-38389ac20f-938299a48c.zip b/.yarn/cache/npm-packlist-npm-5.1.1-38389ac20f-938299a48c.zip deleted file mode 100644 index 4e8596b8ca5f..000000000000 Binary files a/.yarn/cache/npm-packlist-npm-5.1.1-38389ac20f-938299a48c.zip and /dev/null differ diff --git a/.yarn/cache/npm-packlist-npm-7.0.4-1c0b919056-b24644eefa.zip b/.yarn/cache/npm-packlist-npm-7.0.4-1c0b919056-b24644eefa.zip deleted file mode 100644 index d96f02627277..000000000000 Binary files a/.yarn/cache/npm-packlist-npm-7.0.4-1c0b919056-b24644eefa.zip and /dev/null differ diff --git a/.yarn/cache/npm-packlist-npm-8.0.2-f975a473a6-707206e5c0.zip b/.yarn/cache/npm-packlist-npm-8.0.2-f975a473a6-707206e5c0.zip new file mode 100644 index 000000000000..fd62e1ff68e6 Binary files /dev/null and b/.yarn/cache/npm-packlist-npm-8.0.2-f975a473a6-707206e5c0.zip differ diff --git a/.yarn/cache/npm-pick-manifest-npm-8.0.1-186ce1bec0-ffa69b8629.zip b/.yarn/cache/npm-pick-manifest-npm-8.0.1-186ce1bec0-ffa69b8629.zip deleted file mode 100644 index 7ae6507b1374..000000000000 Binary files a/.yarn/cache/npm-pick-manifest-npm-8.0.1-186ce1bec0-ffa69b8629.zip and /dev/null differ diff --git a/.yarn/cache/npm-pick-manifest-npm-9.1.0-38ecc59c15-e759e4fe40.zip b/.yarn/cache/npm-pick-manifest-npm-9.1.0-38ecc59c15-e759e4fe40.zip new file mode 100644 index 000000000000..3350b8b60e3b Binary files /dev/null and b/.yarn/cache/npm-pick-manifest-npm-9.1.0-38ecc59c15-e759e4fe40.zip differ diff --git a/.yarn/cache/npm-registry-fetch-npm-14.0.5-6b3e6c0dd0-63026b22d6.zip b/.yarn/cache/npm-registry-fetch-npm-14.0.5-6b3e6c0dd0-63026b22d6.zip deleted file mode 100644 index 2f442fedf27e..000000000000 Binary files a/.yarn/cache/npm-registry-fetch-npm-14.0.5-6b3e6c0dd0-63026b22d6.zip and /dev/null differ diff --git a/.yarn/cache/npm-registry-fetch-npm-17.1.0-8eabd327ea-b9b2a73907.zip b/.yarn/cache/npm-registry-fetch-npm-17.1.0-8eabd327ea-b9b2a73907.zip new file mode 100644 index 000000000000..fdf7bf842707 Binary files /dev/null and b/.yarn/cache/npm-registry-fetch-npm-17.1.0-8eabd327ea-b9b2a73907.zip differ diff --git a/.yarn/cache/npm-run-path-npm-5.1.0-79c0668d42-dc184eb5ec.zip b/.yarn/cache/npm-run-path-npm-5.1.0-79c0668d42-dc184eb5ec.zip deleted file mode 100644 index 9b9a307b4380..000000000000 Binary files a/.yarn/cache/npm-run-path-npm-5.1.0-79c0668d42-dc184eb5ec.zip and /dev/null differ diff --git a/.yarn/cache/npm-run-path-npm-5.3.0-193efca236-ae8e7a89da.zip b/.yarn/cache/npm-run-path-npm-5.3.0-193efca236-ae8e7a89da.zip new file mode 100644 index 000000000000..997c8b8874e2 Binary files /dev/null and b/.yarn/cache/npm-run-path-npm-5.3.0-193efca236-ae8e7a89da.zip differ diff --git a/.yarn/cache/npmlog-npm-6.0.2-e0e69455c7-82b123677e.zip b/.yarn/cache/npmlog-npm-6.0.2-e0e69455c7-82b123677e.zip deleted file mode 100644 index 16849f0a97e5..000000000000 Binary files a/.yarn/cache/npmlog-npm-6.0.2-e0e69455c7-82b123677e.zip and /dev/null differ diff --git a/.yarn/cache/null-loader-npm-4.0.1-02276c1f77-eeb4c4dd2f.zip b/.yarn/cache/null-loader-npm-4.0.1-02276c1f77-eeb4c4dd2f.zip new file mode 100644 index 000000000000..b1638aeff5b0 Binary files /dev/null and b/.yarn/cache/null-loader-npm-4.0.1-02276c1f77-eeb4c4dd2f.zip differ diff --git a/.yarn/cache/nwsapi-npm-2.2.0-8f05590043-d278126549.zip b/.yarn/cache/nwsapi-npm-2.2.0-8f05590043-d278126549.zip deleted file mode 100644 index 4f16e70ad1e1..000000000000 Binary files a/.yarn/cache/nwsapi-npm-2.2.0-8f05590043-d278126549.zip and /dev/null differ diff --git a/.yarn/cache/nwsapi-npm-2.2.12-a8463ea0e6-172119e9ef.zip b/.yarn/cache/nwsapi-npm-2.2.12-a8463ea0e6-172119e9ef.zip new file mode 100644 index 000000000000..3b587b1af756 Binary files /dev/null and b/.yarn/cache/nwsapi-npm-2.2.12-a8463ea0e6-172119e9ef.zip differ diff --git a/.yarn/cache/nx-npm-17.1.3-a5c724412b-08ce651847.zip b/.yarn/cache/nx-npm-17.1.3-a5c724412b-08ce651847.zip deleted file mode 100644 index dacc39cba200..000000000000 Binary files a/.yarn/cache/nx-npm-17.1.3-a5c724412b-08ce651847.zip and /dev/null differ diff --git a/.yarn/cache/nx-npm-19.5.3-8310b5ed9e-5c0c774aaf.zip b/.yarn/cache/nx-npm-19.5.3-8310b5ed9e-5c0c774aaf.zip new file mode 100644 index 000000000000..437a3250dfb8 Binary files /dev/null and b/.yarn/cache/nx-npm-19.5.3-8310b5ed9e-5c0c774aaf.zip differ diff --git a/.yarn/cache/nypm-npm-0.3.9-1cd7b5618c-fd884f4465.zip b/.yarn/cache/nypm-npm-0.3.9-1cd7b5618c-fd884f4465.zip new file mode 100644 index 000000000000..f9e1fa44197f Binary files /dev/null and b/.yarn/cache/nypm-npm-0.3.9-1cd7b5618c-fd884f4465.zip differ diff --git a/.yarn/cache/object-is-npm-1.1.5-48a862602b-75365aff5d.zip b/.yarn/cache/object-is-npm-1.1.5-48a862602b-75365aff5d.zip deleted file mode 100644 index 252fed467d96..000000000000 Binary files a/.yarn/cache/object-is-npm-1.1.5-48a862602b-75365aff5d.zip and /dev/null differ diff --git a/.yarn/cache/object-is-npm-1.1.6-bfafd361ee-4f6f544773.zip b/.yarn/cache/object-is-npm-1.1.6-bfafd361ee-4f6f544773.zip new file mode 100644 index 000000000000..f9ebd4a9a1cc Binary files /dev/null and b/.yarn/cache/object-is-npm-1.1.6-bfafd361ee-4f6f544773.zip differ diff --git a/.yarn/cache/object.assign-npm-4.1.4-fb3deb1c3a-fd82d45289.zip b/.yarn/cache/object.assign-npm-4.1.4-fb3deb1c3a-fd82d45289.zip deleted file mode 100644 index 8682dec07d25..000000000000 Binary files a/.yarn/cache/object.assign-npm-4.1.4-fb3deb1c3a-fd82d45289.zip and /dev/null differ diff --git a/.yarn/cache/object.assign-npm-4.1.5-aa3b2260ba-dbb22da4cd.zip b/.yarn/cache/object.assign-npm-4.1.5-aa3b2260ba-dbb22da4cd.zip new file mode 100644 index 000000000000..19807bda08cf Binary files /dev/null and b/.yarn/cache/object.assign-npm-4.1.5-aa3b2260ba-dbb22da4cd.zip differ diff --git a/.yarn/cache/object.entries-npm-1.1.6-5f9ba14b46-08a09ff839.zip b/.yarn/cache/object.entries-npm-1.1.6-5f9ba14b46-08a09ff839.zip deleted file mode 100644 index ef7ca5e01730..000000000000 Binary files a/.yarn/cache/object.entries-npm-1.1.6-5f9ba14b46-08a09ff839.zip and /dev/null differ diff --git a/.yarn/cache/object.entries-npm-1.1.8-386f7451b8-2301918fbd.zip b/.yarn/cache/object.entries-npm-1.1.8-386f7451b8-2301918fbd.zip new file mode 100644 index 000000000000..3723e9d4faa9 Binary files /dev/null and b/.yarn/cache/object.entries-npm-1.1.8-386f7451b8-2301918fbd.zip differ diff --git a/.yarn/cache/object.fromentries-npm-2.0.6-424cf4cd3c-e8b813647c.zip b/.yarn/cache/object.fromentries-npm-2.0.6-424cf4cd3c-e8b813647c.zip deleted file mode 100644 index 417e61a35182..000000000000 Binary files a/.yarn/cache/object.fromentries-npm-2.0.6-424cf4cd3c-e8b813647c.zip and /dev/null differ diff --git a/.yarn/cache/object.fromentries-npm-2.0.8-8f6e2db04a-5b2e80f7af.zip b/.yarn/cache/object.fromentries-npm-2.0.8-8f6e2db04a-5b2e80f7af.zip new file mode 100644 index 000000000000..3d8e3e7ddb42 Binary files /dev/null and b/.yarn/cache/object.fromentries-npm-2.0.8-8f6e2db04a-5b2e80f7af.zip differ diff --git a/.yarn/cache/object.getownpropertydescriptors-npm-2.1.0-a6ef3a16c2-ec6b4b3d0c.zip b/.yarn/cache/object.getownpropertydescriptors-npm-2.1.0-a6ef3a16c2-ec6b4b3d0c.zip deleted file mode 100644 index 82a4dc108883..000000000000 Binary files a/.yarn/cache/object.getownpropertydescriptors-npm-2.1.0-a6ef3a16c2-ec6b4b3d0c.zip and /dev/null differ diff --git a/.yarn/cache/object.getownpropertydescriptors-npm-2.1.8-f52ebbf149-8c50f52e0d.zip b/.yarn/cache/object.getownpropertydescriptors-npm-2.1.8-f52ebbf149-8c50f52e0d.zip new file mode 100644 index 000000000000..29d0df3b6206 Binary files /dev/null and b/.yarn/cache/object.getownpropertydescriptors-npm-2.1.8-f52ebbf149-8c50f52e0d.zip differ diff --git a/.yarn/cache/object.groupby-npm-1.0.3-d5feb41454-44cb86dd2c.zip b/.yarn/cache/object.groupby-npm-1.0.3-d5feb41454-44cb86dd2c.zip new file mode 100644 index 000000000000..7e6e04bf5c52 Binary files /dev/null and b/.yarn/cache/object.groupby-npm-1.0.3-d5feb41454-44cb86dd2c.zip differ diff --git a/.yarn/cache/object.hasown-npm-1.1.2-db9bbc7f97-94031022a2.zip b/.yarn/cache/object.hasown-npm-1.1.2-db9bbc7f97-94031022a2.zip deleted file mode 100644 index 7915e81d9bce..000000000000 Binary files a/.yarn/cache/object.hasown-npm-1.1.2-db9bbc7f97-94031022a2.zip and /dev/null differ diff --git a/.yarn/cache/object.values-npm-1.1.6-ab9b67ccd3-adea807c90.zip b/.yarn/cache/object.values-npm-1.1.6-ab9b67ccd3-adea807c90.zip deleted file mode 100644 index d379b720987d..000000000000 Binary files a/.yarn/cache/object.values-npm-1.1.6-ab9b67ccd3-adea807c90.zip and /dev/null differ diff --git a/.yarn/cache/object.values-npm-1.2.0-5112376fc7-db2e498019.zip b/.yarn/cache/object.values-npm-1.2.0-5112376fc7-db2e498019.zip new file mode 100644 index 000000000000..7d11781bb547 Binary files /dev/null and b/.yarn/cache/object.values-npm-1.2.0-5112376fc7-db2e498019.zip differ diff --git a/.yarn/cache/ohash-npm-1.1.3-3deaf8b6af-80a3528285.zip b/.yarn/cache/ohash-npm-1.1.3-3deaf8b6af-80a3528285.zip new file mode 100644 index 000000000000..ba0fc1d7f891 Binary files /dev/null and b/.yarn/cache/ohash-npm-1.1.3-3deaf8b6af-80a3528285.zip differ diff --git a/.yarn/cache/omit-deep-npm-0.3.0-f8bf373735-37ab363f1a.zip b/.yarn/cache/omit-deep-npm-0.3.0-f8bf373735-37ab363f1a.zip deleted file mode 100644 index 59a4e8087afb..000000000000 Binary files a/.yarn/cache/omit-deep-npm-0.3.0-f8bf373735-37ab363f1a.zip and /dev/null differ diff --git a/.yarn/cache/onetime-npm-7.0.0-cfdd2a579d-eb08d2da93.zip b/.yarn/cache/onetime-npm-7.0.0-cfdd2a579d-eb08d2da93.zip new file mode 100644 index 000000000000..91656f9d7152 Binary files /dev/null and b/.yarn/cache/onetime-npm-7.0.0-cfdd2a579d-eb08d2da93.zip differ diff --git a/.yarn/cache/open-npm-9.1.0-d104a17ec5-b45bcc7a67.zip b/.yarn/cache/open-npm-9.1.0-d104a17ec5-b45bcc7a67.zip deleted file mode 100644 index ee8d964bfeda..000000000000 Binary files a/.yarn/cache/open-npm-9.1.0-d104a17ec5-b45bcc7a67.zip and /dev/null differ diff --git a/.yarn/cache/ora-npm-5.3.0-bb3e7178be-989a075b59.zip b/.yarn/cache/ora-npm-5.3.0-bb3e7178be-989a075b59.zip new file mode 100644 index 000000000000..482fdcb6a6a0 Binary files /dev/null and b/.yarn/cache/ora-npm-5.3.0-bb3e7178be-989a075b59.zip differ diff --git a/.yarn/cache/pac-proxy-agent-npm-7.0.2-74826508c7-bb9b53b32b.zip b/.yarn/cache/pac-proxy-agent-npm-7.0.2-74826508c7-bb9b53b32b.zip new file mode 100644 index 000000000000..c6dd812bfa17 Binary files /dev/null and b/.yarn/cache/pac-proxy-agent-npm-7.0.2-74826508c7-bb9b53b32b.zip differ diff --git a/.yarn/cache/pac-resolver-npm-7.0.1-73af0cb8f1-8391343287.zip b/.yarn/cache/pac-resolver-npm-7.0.1-73af0cb8f1-8391343287.zip new file mode 100644 index 000000000000..7ba92cc9b236 Binary files /dev/null and b/.yarn/cache/pac-resolver-npm-7.0.1-73af0cb8f1-8391343287.zip differ diff --git a/.yarn/cache/pacote-npm-15.2.0-b9ed3321e9-57e18f4f96.zip b/.yarn/cache/pacote-npm-15.2.0-b9ed3321e9-57e18f4f96.zip deleted file mode 100644 index 65509c0cb6c7..000000000000 Binary files a/.yarn/cache/pacote-npm-15.2.0-b9ed3321e9-57e18f4f96.zip and /dev/null differ diff --git a/.yarn/cache/pacote-npm-18.0.6-42b2ba9f9c-48cbcb3c20.zip b/.yarn/cache/pacote-npm-18.0.6-42b2ba9f9c-48cbcb3c20.zip new file mode 100644 index 000000000000..a25cd7a9bff9 Binary files /dev/null and b/.yarn/cache/pacote-npm-18.0.6-42b2ba9f9c-48cbcb3c20.zip differ diff --git a/.yarn/cache/pako-npm-1.0.10-7385fe2fcf-f8efb4014e.zip b/.yarn/cache/pako-npm-1.0.10-7385fe2fcf-f8efb4014e.zip deleted file mode 100644 index 8157cca7d1c1..000000000000 Binary files a/.yarn/cache/pako-npm-1.0.10-7385fe2fcf-f8efb4014e.zip and /dev/null differ diff --git a/.yarn/cache/pako-npm-1.0.11-b8f1b69d3e-1ad07210e8.zip b/.yarn/cache/pako-npm-1.0.11-b8f1b69d3e-1ad07210e8.zip new file mode 100644 index 000000000000..c2a311f25870 Binary files /dev/null and b/.yarn/cache/pako-npm-1.0.11-b8f1b69d3e-1ad07210e8.zip differ diff --git a/.yarn/cache/parse-conflict-json-npm-3.0.1-9455a1ad04-ceb13ca90b.zip b/.yarn/cache/parse-conflict-json-npm-3.0.1-9455a1ad04-ceb13ca90b.zip new file mode 100644 index 000000000000..e1b724e64456 Binary files /dev/null and b/.yarn/cache/parse-conflict-json-npm-3.0.1-9455a1ad04-ceb13ca90b.zip differ diff --git a/.yarn/cache/parse-entities-npm-2.0.0-b7b4f46ff6-feb46b5167.zip b/.yarn/cache/parse-entities-npm-2.0.0-b7b4f46ff6-feb46b5167.zip new file mode 100644 index 000000000000..50840ab8a156 Binary files /dev/null and b/.yarn/cache/parse-entities-npm-2.0.0-b7b4f46ff6-feb46b5167.zip differ diff --git a/.yarn/cache/parse-json-npm-8.1.0-3bb3720119-efc4256c91.zip b/.yarn/cache/parse-json-npm-8.1.0-3bb3720119-efc4256c91.zip new file mode 100644 index 000000000000..7b6cf34102c1 Binary files /dev/null and b/.yarn/cache/parse-json-npm-8.1.0-3bb3720119-efc4256c91.zip differ diff --git a/.yarn/cache/parse5-htmlparser2-tree-adapter-npm-7.0.0-38e1b3a974-23dbe45fdd.zip b/.yarn/cache/parse5-htmlparser2-tree-adapter-npm-7.0.0-38e1b3a974-23dbe45fdd.zip new file mode 100644 index 000000000000..52ab38778849 Binary files /dev/null and b/.yarn/cache/parse5-htmlparser2-tree-adapter-npm-7.0.0-38e1b3a974-23dbe45fdd.zip differ diff --git a/.yarn/cache/parse5-npm-7.1.2-aa9a92c270-3c86806bb0.zip b/.yarn/cache/parse5-npm-7.1.2-aa9a92c270-3c86806bb0.zip new file mode 100644 index 000000000000..9f7319cbf0ae Binary files /dev/null and b/.yarn/cache/parse5-npm-7.1.2-aa9a92c270-3c86806bb0.zip differ diff --git a/.yarn/cache/path-to-regexp-npm-0.1.10-63516149e0-894e31f1b2.zip b/.yarn/cache/path-to-regexp-npm-0.1.10-63516149e0-894e31f1b2.zip deleted file mode 100644 index 487026af8a19..000000000000 Binary files a/.yarn/cache/path-to-regexp-npm-0.1.10-63516149e0-894e31f1b2.zip and /dev/null differ diff --git a/.yarn/cache/path-to-regexp-npm-0.1.7-2605347373-701c99e1f0.zip b/.yarn/cache/path-to-regexp-npm-0.1.7-2605347373-701c99e1f0.zip new file mode 100644 index 000000000000..cc4fcf84bf42 Binary files /dev/null and b/.yarn/cache/path-to-regexp-npm-0.1.7-2605347373-701c99e1f0.zip differ diff --git a/.yarn/cache/path-to-regexp-npm-6.2.0-efbac3c1ff-330ad50d40.zip b/.yarn/cache/path-to-regexp-npm-6.2.0-efbac3c1ff-330ad50d40.zip deleted file mode 100644 index 94cf833335b1..000000000000 Binary files a/.yarn/cache/path-to-regexp-npm-6.2.0-efbac3c1ff-330ad50d40.zip and /dev/null differ diff --git a/.yarn/cache/path-to-regexp-npm-6.2.2-0bf7f6805c-f7d11c1a9e.zip b/.yarn/cache/path-to-regexp-npm-6.2.2-0bf7f6805c-f7d11c1a9e.zip new file mode 100644 index 000000000000..7d276a021f07 Binary files /dev/null and b/.yarn/cache/path-to-regexp-npm-6.2.2-0bf7f6805c-f7d11c1a9e.zip differ diff --git a/.yarn/cache/pathe-npm-1.1.0-2f6ca9875a-7cd4e00d99.zip b/.yarn/cache/pathe-npm-1.1.0-2f6ca9875a-7cd4e00d99.zip deleted file mode 100644 index 82ae5428ce0e..000000000000 Binary files a/.yarn/cache/pathe-npm-1.1.0-2f6ca9875a-7cd4e00d99.zip and /dev/null differ diff --git a/.yarn/cache/pathe-npm-1.1.2-b80d94db55-f201d79635.zip b/.yarn/cache/pathe-npm-1.1.2-b80d94db55-f201d79635.zip new file mode 100644 index 000000000000..1597e85edb92 Binary files /dev/null and b/.yarn/cache/pathe-npm-1.1.2-b80d94db55-f201d79635.zip differ diff --git a/.yarn/cache/pkg-types-npm-1.1.3-66aff08ed8-06c03ca679.zip b/.yarn/cache/pkg-types-npm-1.1.3-66aff08ed8-06c03ca679.zip new file mode 100644 index 000000000000..4dbbd51c7a0d Binary files /dev/null and b/.yarn/cache/pkg-types-npm-1.1.3-66aff08ed8-06c03ca679.zip differ diff --git a/.yarn/cache/polished-npm-4.2.2-eb3d423b8d-da71b15c1e.zip b/.yarn/cache/polished-npm-4.2.2-eb3d423b8d-da71b15c1e.zip deleted file mode 100644 index aa29241ac04c..000000000000 Binary files a/.yarn/cache/polished-npm-4.2.2-eb3d423b8d-da71b15c1e.zip and /dev/null differ diff --git a/.yarn/cache/polished-npm-4.3.1-96b1782f82-0902fe2eb1.zip b/.yarn/cache/polished-npm-4.3.1-96b1782f82-0902fe2eb1.zip new file mode 100644 index 000000000000..2b854c5c5d6d Binary files /dev/null and b/.yarn/cache/polished-npm-4.3.1-96b1782f82-0902fe2eb1.zip differ diff --git a/.yarn/cache/possible-typed-array-names-npm-1.0.0-3a8176348a-8ed3e96dfe.zip b/.yarn/cache/possible-typed-array-names-npm-1.0.0-3a8176348a-8ed3e96dfe.zip new file mode 100644 index 000000000000..728187fbc59f Binary files /dev/null and b/.yarn/cache/possible-typed-array-names-npm-1.0.0-3a8176348a-8ed3e96dfe.zip differ diff --git a/.yarn/cache/postcss-colormin-npm-7.0.0-e3e057a212-34baf724c1.zip b/.yarn/cache/postcss-colormin-npm-7.0.0-e3e057a212-34baf724c1.zip deleted file mode 100644 index 5e3a579154aa..000000000000 Binary files a/.yarn/cache/postcss-colormin-npm-7.0.0-e3e057a212-34baf724c1.zip and /dev/null differ diff --git a/.yarn/cache/postcss-colormin-npm-7.0.1-a9ab2839d7-00fd1554d4.zip b/.yarn/cache/postcss-colormin-npm-7.0.1-a9ab2839d7-00fd1554d4.zip new file mode 100644 index 000000000000..6c9c589a98e1 Binary files /dev/null and b/.yarn/cache/postcss-colormin-npm-7.0.1-a9ab2839d7-00fd1554d4.zip differ diff --git a/.yarn/cache/postcss-convert-values-npm-7.0.0-4679f46137-1196bdcdc8.zip b/.yarn/cache/postcss-convert-values-npm-7.0.0-4679f46137-1196bdcdc8.zip deleted file mode 100644 index b218b174432f..000000000000 Binary files a/.yarn/cache/postcss-convert-values-npm-7.0.0-4679f46137-1196bdcdc8.zip and /dev/null differ diff --git a/.yarn/cache/postcss-convert-values-npm-7.0.2-c2586d232c-15e0a804f4.zip b/.yarn/cache/postcss-convert-values-npm-7.0.2-c2586d232c-15e0a804f4.zip new file mode 100644 index 000000000000..28d801f19078 Binary files /dev/null and b/.yarn/cache/postcss-convert-values-npm-7.0.2-c2586d232c-15e0a804f4.zip differ diff --git a/.yarn/cache/postcss-discard-comments-npm-7.0.0-ac48feda08-2db53331e3.zip b/.yarn/cache/postcss-discard-comments-npm-7.0.0-ac48feda08-2db53331e3.zip deleted file mode 100644 index 80d9d8be8f55..000000000000 Binary files a/.yarn/cache/postcss-discard-comments-npm-7.0.0-ac48feda08-2db53331e3.zip and /dev/null differ diff --git a/.yarn/cache/postcss-discard-comments-npm-7.0.1-9a5ed17f1f-170ab2f73a.zip b/.yarn/cache/postcss-discard-comments-npm-7.0.1-9a5ed17f1f-170ab2f73a.zip new file mode 100644 index 000000000000..f7904cd2d897 Binary files /dev/null and b/.yarn/cache/postcss-discard-comments-npm-7.0.1-9a5ed17f1f-170ab2f73a.zip differ diff --git a/.yarn/cache/postcss-loader-npm-8.0.0-195ad96888-efbb59d2b7.zip b/.yarn/cache/postcss-loader-npm-8.0.0-195ad96888-efbb59d2b7.zip deleted file mode 100644 index aa6abd99f964..000000000000 Binary files a/.yarn/cache/postcss-loader-npm-8.0.0-195ad96888-efbb59d2b7.zip and /dev/null differ diff --git a/.yarn/cache/postcss-loader-npm-8.1.1-20cf547c92-7ae38e6351.zip b/.yarn/cache/postcss-loader-npm-8.1.1-20cf547c92-7ae38e6351.zip new file mode 100644 index 000000000000..cf2e7c6b6e92 Binary files /dev/null and b/.yarn/cache/postcss-loader-npm-8.1.1-20cf547c92-7ae38e6351.zip differ diff --git a/.yarn/cache/postcss-merge-longhand-npm-7.0.0-907c8a8ab1-031bb5f089.zip b/.yarn/cache/postcss-merge-longhand-npm-7.0.0-907c8a8ab1-031bb5f089.zip deleted file mode 100644 index 68ebe9ed819b..000000000000 Binary files a/.yarn/cache/postcss-merge-longhand-npm-7.0.0-907c8a8ab1-031bb5f089.zip and /dev/null differ diff --git a/.yarn/cache/postcss-merge-longhand-npm-7.0.2-c3168a7d17-028631bb3f.zip b/.yarn/cache/postcss-merge-longhand-npm-7.0.2-c3168a7d17-028631bb3f.zip new file mode 100644 index 000000000000..34e0dea1c9ce Binary files /dev/null and b/.yarn/cache/postcss-merge-longhand-npm-7.0.2-c3168a7d17-028631bb3f.zip differ diff --git a/.yarn/cache/postcss-merge-rules-npm-7.0.0-7f9314dc61-79d80b2d80.zip b/.yarn/cache/postcss-merge-rules-npm-7.0.0-7f9314dc61-79d80b2d80.zip deleted file mode 100644 index c6c761dd118b..000000000000 Binary files a/.yarn/cache/postcss-merge-rules-npm-7.0.0-7f9314dc61-79d80b2d80.zip and /dev/null differ diff --git a/.yarn/cache/postcss-merge-rules-npm-7.0.2-cf1c8105b1-1c4d2a022f.zip b/.yarn/cache/postcss-merge-rules-npm-7.0.2-cf1c8105b1-1c4d2a022f.zip new file mode 100644 index 000000000000..b8a1d8dded17 Binary files /dev/null and b/.yarn/cache/postcss-merge-rules-npm-7.0.2-cf1c8105b1-1c4d2a022f.zip differ diff --git a/.yarn/cache/postcss-minify-params-npm-7.0.0-9829f70c56-4093d6033f.zip b/.yarn/cache/postcss-minify-params-npm-7.0.0-9829f70c56-4093d6033f.zip deleted file mode 100644 index a6f8963d085e..000000000000 Binary files a/.yarn/cache/postcss-minify-params-npm-7.0.0-9829f70c56-4093d6033f.zip and /dev/null differ diff --git a/.yarn/cache/postcss-minify-params-npm-7.0.1-b12d938a08-6bcb3b830e.zip b/.yarn/cache/postcss-minify-params-npm-7.0.1-b12d938a08-6bcb3b830e.zip new file mode 100644 index 000000000000..fb2a58c204d3 Binary files /dev/null and b/.yarn/cache/postcss-minify-params-npm-7.0.1-b12d938a08-6bcb3b830e.zip differ diff --git a/.yarn/cache/postcss-minify-selectors-npm-7.0.0-25f2e97118-6b00ff0363.zip b/.yarn/cache/postcss-minify-selectors-npm-7.0.0-25f2e97118-6b00ff0363.zip deleted file mode 100644 index f690efd7101f..000000000000 Binary files a/.yarn/cache/postcss-minify-selectors-npm-7.0.0-25f2e97118-6b00ff0363.zip and /dev/null differ diff --git a/.yarn/cache/postcss-minify-selectors-npm-7.0.2-875f06b95f-6f8b3cb766.zip b/.yarn/cache/postcss-minify-selectors-npm-7.0.2-875f06b95f-6f8b3cb766.zip new file mode 100644 index 000000000000..79f81bcda8b3 Binary files /dev/null and b/.yarn/cache/postcss-minify-selectors-npm-7.0.2-875f06b95f-6f8b3cb766.zip differ diff --git a/.yarn/cache/postcss-normalize-unicode-npm-7.0.0-db049069eb-4efb35c394.zip b/.yarn/cache/postcss-normalize-unicode-npm-7.0.0-db049069eb-4efb35c394.zip deleted file mode 100644 index bf32fab170ee..000000000000 Binary files a/.yarn/cache/postcss-normalize-unicode-npm-7.0.0-db049069eb-4efb35c394.zip and /dev/null differ diff --git a/.yarn/cache/postcss-normalize-unicode-npm-7.0.1-50e0055adf-2b155d99c5.zip b/.yarn/cache/postcss-normalize-unicode-npm-7.0.1-50e0055adf-2b155d99c5.zip new file mode 100644 index 000000000000..86e4d184a2a7 Binary files /dev/null and b/.yarn/cache/postcss-normalize-unicode-npm-7.0.1-50e0055adf-2b155d99c5.zip differ diff --git a/.yarn/cache/postcss-npm-8.4.38-495621b279-6e44a7ed83.zip b/.yarn/cache/postcss-npm-8.4.38-495621b279-6e44a7ed83.zip deleted file mode 100644 index a89b0e8a646e..000000000000 Binary files a/.yarn/cache/postcss-npm-8.4.38-495621b279-6e44a7ed83.zip and /dev/null differ diff --git a/.yarn/cache/postcss-npm-8.4.41-1607021b28-6e6176c240.zip b/.yarn/cache/postcss-npm-8.4.41-1607021b28-6e6176c240.zip new file mode 100644 index 000000000000..3c603cc77cb1 Binary files /dev/null and b/.yarn/cache/postcss-npm-8.4.41-1607021b28-6e6176c240.zip differ diff --git a/.yarn/cache/postcss-ordered-values-npm-7.0.0-e89ace471c-c4c1136672.zip b/.yarn/cache/postcss-ordered-values-npm-7.0.0-e89ace471c-c4c1136672.zip deleted file mode 100644 index b4201312d446..000000000000 Binary files a/.yarn/cache/postcss-ordered-values-npm-7.0.0-e89ace471c-c4c1136672.zip and /dev/null differ diff --git a/.yarn/cache/postcss-ordered-values-npm-7.0.1-f37f91ed1f-048082c09e.zip b/.yarn/cache/postcss-ordered-values-npm-7.0.1-f37f91ed1f-048082c09e.zip new file mode 100644 index 000000000000..da54df0b90bf Binary files /dev/null and b/.yarn/cache/postcss-ordered-values-npm-7.0.1-f37f91ed1f-048082c09e.zip differ diff --git a/.yarn/cache/postcss-reduce-initial-npm-7.0.0-5ea632b56d-4710e10324.zip b/.yarn/cache/postcss-reduce-initial-npm-7.0.0-5ea632b56d-4710e10324.zip deleted file mode 100644 index 79c2b1a606d7..000000000000 Binary files a/.yarn/cache/postcss-reduce-initial-npm-7.0.0-5ea632b56d-4710e10324.zip and /dev/null differ diff --git a/.yarn/cache/postcss-reduce-initial-npm-7.0.1-77824fcf13-9c44080173.zip b/.yarn/cache/postcss-reduce-initial-npm-7.0.1-77824fcf13-9c44080173.zip new file mode 100644 index 000000000000..3431a6eea94e Binary files /dev/null and b/.yarn/cache/postcss-reduce-initial-npm-7.0.1-77824fcf13-9c44080173.zip differ diff --git a/.yarn/cache/postcss-resolve-nested-selector-npm-0.1.1-7067e0fef7-b08fb76ab0.zip b/.yarn/cache/postcss-resolve-nested-selector-npm-0.1.1-7067e0fef7-b08fb76ab0.zip deleted file mode 100644 index c8c771163bbc..000000000000 Binary files a/.yarn/cache/postcss-resolve-nested-selector-npm-0.1.1-7067e0fef7-b08fb76ab0.zip and /dev/null differ diff --git a/.yarn/cache/postcss-resolve-nested-selector-npm-0.1.4-076e7b1ec3-c53a1aa453.zip b/.yarn/cache/postcss-resolve-nested-selector-npm-0.1.4-076e7b1ec3-c53a1aa453.zip new file mode 100644 index 000000000000..b26210775699 Binary files /dev/null and b/.yarn/cache/postcss-resolve-nested-selector-npm-0.1.4-076e7b1ec3-c53a1aa453.zip differ diff --git a/.yarn/cache/postcss-scss-npm-4.0.8-358bb8ff7d-0d2e47fb02.zip b/.yarn/cache/postcss-scss-npm-4.0.8-358bb8ff7d-0d2e47fb02.zip deleted file mode 100644 index 1336dfcb0055..000000000000 Binary files a/.yarn/cache/postcss-scss-npm-4.0.8-358bb8ff7d-0d2e47fb02.zip and /dev/null differ diff --git a/.yarn/cache/postcss-scss-npm-4.0.9-b492c55307-d191c77134.zip b/.yarn/cache/postcss-scss-npm-4.0.9-b492c55307-d191c77134.zip new file mode 100644 index 000000000000..81c4941bc5aa Binary files /dev/null and b/.yarn/cache/postcss-scss-npm-4.0.9-b492c55307-d191c77134.zip differ diff --git a/.yarn/cache/postcss-selector-parser-npm-6.0.16-a6448fd7e1-9324f63992.zip b/.yarn/cache/postcss-selector-parser-npm-6.0.16-a6448fd7e1-9324f63992.zip deleted file mode 100644 index a573e4a6e400..000000000000 Binary files a/.yarn/cache/postcss-selector-parser-npm-6.0.16-a6448fd7e1-9324f63992.zip and /dev/null differ diff --git a/.yarn/cache/postcss-selector-parser-npm-6.1.1-ba452aaaa9-ce2af36b56.zip b/.yarn/cache/postcss-selector-parser-npm-6.1.1-ba452aaaa9-ce2af36b56.zip new file mode 100644 index 000000000000..01ec18854e98 Binary files /dev/null and b/.yarn/cache/postcss-selector-parser-npm-6.1.1-ba452aaaa9-ce2af36b56.zip differ diff --git a/.yarn/cache/postcss-svgo-npm-7.0.0-28232bdc9c-e4a0ba3963.zip b/.yarn/cache/postcss-svgo-npm-7.0.0-28232bdc9c-e4a0ba3963.zip deleted file mode 100644 index 8bae726c1689..000000000000 Binary files a/.yarn/cache/postcss-svgo-npm-7.0.0-28232bdc9c-e4a0ba3963.zip and /dev/null differ diff --git a/.yarn/cache/postcss-svgo-npm-7.0.1-22674c6627-4196d9b7ec.zip b/.yarn/cache/postcss-svgo-npm-7.0.1-22674c6627-4196d9b7ec.zip new file mode 100644 index 000000000000..c0e458b3c2d1 Binary files /dev/null and b/.yarn/cache/postcss-svgo-npm-7.0.1-22674c6627-4196d9b7ec.zip differ diff --git a/.yarn/cache/postcss-unique-selectors-npm-7.0.0-f65fa7a26b-7f7c817c6b.zip b/.yarn/cache/postcss-unique-selectors-npm-7.0.0-f65fa7a26b-7f7c817c6b.zip deleted file mode 100644 index 0180cb99c9c0..000000000000 Binary files a/.yarn/cache/postcss-unique-selectors-npm-7.0.0-f65fa7a26b-7f7c817c6b.zip and /dev/null differ diff --git a/.yarn/cache/postcss-unique-selectors-npm-7.0.1-d1b0ff37b1-01ceef7b27.zip b/.yarn/cache/postcss-unique-selectors-npm-7.0.1-d1b0ff37b1-01ceef7b27.zip new file mode 100644 index 000000000000..1e52063f191a Binary files /dev/null and b/.yarn/cache/postcss-unique-selectors-npm-7.0.1-d1b0ff37b1-01ceef7b27.zip differ diff --git a/.yarn/cache/pretty-format-npm-28.1.0-d36b244e24-7d4dc4690c.zip b/.yarn/cache/pretty-format-npm-28.1.0-d36b244e24-7d4dc4690c.zip deleted file mode 100644 index 9d6ca2f71935..000000000000 Binary files a/.yarn/cache/pretty-format-npm-28.1.0-d36b244e24-7d4dc4690c.zip and /dev/null differ diff --git a/.yarn/cache/pretty-format-npm-28.1.3-fdf56e33bc-26626d33e2.zip b/.yarn/cache/pretty-format-npm-28.1.3-fdf56e33bc-26626d33e2.zip new file mode 100644 index 000000000000..c883c5c0eb68 Binary files /dev/null and b/.yarn/cache/pretty-format-npm-28.1.3-fdf56e33bc-26626d33e2.zip differ diff --git a/.yarn/cache/proc-log-npm-3.0.0-a8c21c2f0f-02b64e1b39.zip b/.yarn/cache/proc-log-npm-3.0.0-a8c21c2f0f-02b64e1b39.zip deleted file mode 100644 index 0436b17634bd..000000000000 Binary files a/.yarn/cache/proc-log-npm-3.0.0-a8c21c2f0f-02b64e1b39.zip and /dev/null differ diff --git a/.yarn/cache/proc-log-npm-4.2.0-4d65296a9d-4e1394491b.zip b/.yarn/cache/proc-log-npm-4.2.0-4d65296a9d-4e1394491b.zip new file mode 100644 index 000000000000..da03ba869224 Binary files /dev/null and b/.yarn/cache/proc-log-npm-4.2.0-4d65296a9d-4e1394491b.zip differ diff --git a/.yarn/cache/proggy-npm-2.0.0-be7a9905d6-9c96830d30.zip b/.yarn/cache/proggy-npm-2.0.0-be7a9905d6-9c96830d30.zip new file mode 100644 index 000000000000..327903c7ac96 Binary files /dev/null and b/.yarn/cache/proggy-npm-2.0.0-be7a9905d6-9c96830d30.zip differ diff --git a/.yarn/cache/progress-estimator-npm-0.3.0-5983e1cdd5-ab22c0180d.zip b/.yarn/cache/progress-estimator-npm-0.3.0-5983e1cdd5-ab22c0180d.zip deleted file mode 100644 index 879cbed22159..000000000000 Binary files a/.yarn/cache/progress-estimator-npm-0.3.0-5983e1cdd5-ab22c0180d.zip and /dev/null differ diff --git a/.yarn/cache/progress-estimator-npm-0.3.1-767e959233-d191e88af7.zip b/.yarn/cache/progress-estimator-npm-0.3.1-767e959233-d191e88af7.zip new file mode 100644 index 000000000000..d262a3f140e4 Binary files /dev/null and b/.yarn/cache/progress-estimator-npm-0.3.1-767e959233-d191e88af7.zip differ diff --git a/.yarn/cache/promise-all-reject-late-npm-1.0.1-19ba0dce9c-f5e5c1bfed.zip b/.yarn/cache/promise-all-reject-late-npm-1.0.1-19ba0dce9c-f5e5c1bfed.zip new file mode 100644 index 000000000000..4ec32f157c65 Binary files /dev/null and b/.yarn/cache/promise-all-reject-late-npm-1.0.1-19ba0dce9c-f5e5c1bfed.zip differ diff --git a/.yarn/cache/promise-call-limit-npm-3.0.1-a7188a35c3-f1b3c4d3a9.zip b/.yarn/cache/promise-call-limit-npm-3.0.1-a7188a35c3-f1b3c4d3a9.zip new file mode 100644 index 000000000000..17cba94a9cf6 Binary files /dev/null and b/.yarn/cache/promise-call-limit-npm-3.0.1-a7188a35c3-f1b3c4d3a9.zip differ diff --git a/.yarn/cache/promzard-npm-1.0.0-a0d17e2d53-c069488271.zip b/.yarn/cache/promzard-npm-1.0.0-a0d17e2d53-c069488271.zip deleted file mode 100644 index 55ceade35905..000000000000 Binary files a/.yarn/cache/promzard-npm-1.0.0-a0d17e2d53-c069488271.zip and /dev/null differ diff --git a/.yarn/cache/promzard-npm-1.0.2-13dff04db0-08dee9179e.zip b/.yarn/cache/promzard-npm-1.0.2-13dff04db0-08dee9179e.zip new file mode 100644 index 000000000000..a1ea22c50584 Binary files /dev/null and b/.yarn/cache/promzard-npm-1.0.2-13dff04db0-08dee9179e.zip differ diff --git a/.yarn/cache/proxy-agent-npm-6.4.0-21d2d38035-a22f202b74.zip b/.yarn/cache/proxy-agent-npm-6.4.0-21d2d38035-a22f202b74.zip new file mode 100644 index 000000000000..f10570757c72 Binary files /dev/null and b/.yarn/cache/proxy-agent-npm-6.4.0-21d2d38035-a22f202b74.zip differ diff --git a/.yarn/cache/psl-npm-1.8.0-226099d70e-5f62a8eca0.zip b/.yarn/cache/psl-npm-1.8.0-226099d70e-5f62a8eca0.zip deleted file mode 100644 index 426d501136b9..000000000000 Binary files a/.yarn/cache/psl-npm-1.8.0-226099d70e-5f62a8eca0.zip and /dev/null differ diff --git a/.yarn/cache/psl-npm-1.9.0-a546edad1a-d07879d4bf.zip b/.yarn/cache/psl-npm-1.9.0-a546edad1a-d07879d4bf.zip new file mode 100644 index 000000000000..d66a389a52d6 Binary files /dev/null and b/.yarn/cache/psl-npm-1.9.0-a546edad1a-d07879d4bf.zip differ diff --git a/.yarn/cache/punycode-npm-2.1.1-26eb3e15cf-939daa010c.zip b/.yarn/cache/punycode-npm-2.1.1-26eb3e15cf-939daa010c.zip deleted file mode 100644 index 211cf447471f..000000000000 Binary files a/.yarn/cache/punycode-npm-2.1.1-26eb3e15cf-939daa010c.zip and /dev/null differ diff --git a/.yarn/cache/punycode-npm-2.3.1-97543c420d-febdc4362b.zip b/.yarn/cache/punycode-npm-2.3.1-97543c420d-febdc4362b.zip new file mode 100644 index 000000000000..399baa6756e4 Binary files /dev/null and b/.yarn/cache/punycode-npm-2.3.1-97543c420d-febdc4362b.zip differ diff --git a/.yarn/cache/qs-npm-6.12.3-d296002fbb-486d80cfa5.zip b/.yarn/cache/qs-npm-6.12.3-d296002fbb-486d80cfa5.zip new file mode 100644 index 000000000000..4a109849124d Binary files /dev/null and b/.yarn/cache/qs-npm-6.12.3-d296002fbb-486d80cfa5.zip differ diff --git a/.yarn/cache/qs-npm-6.13.0-53676ddc84-f548b376e6.zip b/.yarn/cache/qs-npm-6.13.0-53676ddc84-f548b376e6.zip deleted file mode 100644 index cb37e6aa9937..000000000000 Binary files a/.yarn/cache/qs-npm-6.13.0-53676ddc84-f548b376e6.zip and /dev/null differ diff --git a/.yarn/cache/querystring-npm-0.2.0-421b870c92-37b91720be.zip b/.yarn/cache/querystring-npm-0.2.0-421b870c92-37b91720be.zip deleted file mode 100644 index 8920094a2417..000000000000 Binary files a/.yarn/cache/querystring-npm-0.2.0-421b870c92-37b91720be.zip and /dev/null differ diff --git a/.yarn/cache/querystringify-npm-2.2.0-4e77c9f606-46ab16f252.zip b/.yarn/cache/querystringify-npm-2.2.0-4e77c9f606-46ab16f252.zip new file mode 100644 index 000000000000..6437e1346654 Binary files /dev/null and b/.yarn/cache/querystringify-npm-2.2.0-4e77c9f606-46ab16f252.zip differ diff --git a/.yarn/cache/queue-microtask-npm-1.2.3-fcc98e4e2d-72900df061.zip b/.yarn/cache/queue-microtask-npm-1.2.3-fcc98e4e2d-72900df061.zip new file mode 100644 index 000000000000..6ebde3fc13a3 Binary files /dev/null and b/.yarn/cache/queue-microtask-npm-1.2.3-fcc98e4e2d-72900df061.zip differ diff --git a/.yarn/cache/react-refresh-npm-0.14.0-78ef5eeb73-75941262ce.zip b/.yarn/cache/react-refresh-npm-0.14.0-78ef5eeb73-75941262ce.zip deleted file mode 100644 index 93f4d1fd131e..000000000000 Binary files a/.yarn/cache/react-refresh-npm-0.14.0-78ef5eeb73-75941262ce.zip and /dev/null differ diff --git a/.yarn/cache/react-refresh-npm-0.14.2-95df341b4d-512abf9727.zip b/.yarn/cache/react-refresh-npm-0.14.2-95df341b4d-512abf9727.zip new file mode 100644 index 000000000000..4a6273c1d672 Binary files /dev/null and b/.yarn/cache/react-refresh-npm-0.14.2-95df341b4d-512abf9727.zip differ diff --git a/.yarn/cache/react-remove-scroll-bar-npm-2.3.4-7d25bbed45-ac028b3ed1.zip b/.yarn/cache/react-remove-scroll-bar-npm-2.3.4-7d25bbed45-ac028b3ed1.zip deleted file mode 100644 index 28857eaa077f..000000000000 Binary files a/.yarn/cache/react-remove-scroll-bar-npm-2.3.4-7d25bbed45-ac028b3ed1.zip and /dev/null differ diff --git a/.yarn/cache/react-remove-scroll-bar-npm-2.3.6-92aacd8517-5ab8eda61d.zip b/.yarn/cache/react-remove-scroll-bar-npm-2.3.6-92aacd8517-5ab8eda61d.zip new file mode 100644 index 000000000000..d9e5f947c610 Binary files /dev/null and b/.yarn/cache/react-remove-scroll-bar-npm-2.3.6-92aacd8517-5ab8eda61d.zip differ diff --git a/.yarn/cache/read-npm-2.1.0-0e0cb8a375-90a525c761.zip b/.yarn/cache/read-npm-2.1.0-0e0cb8a375-90a525c761.zip deleted file mode 100644 index 011aaf954e23..000000000000 Binary files a/.yarn/cache/read-npm-2.1.0-0e0cb8a375-90a525c761.zip and /dev/null differ diff --git a/.yarn/cache/read-npm-3.0.1-895fc96715-446b463d04.zip b/.yarn/cache/read-npm-3.0.1-895fc96715-446b463d04.zip new file mode 100644 index 000000000000..4a0d023f8fbc Binary files /dev/null and b/.yarn/cache/read-npm-3.0.1-895fc96715-446b463d04.zip differ diff --git a/.yarn/cache/read-package-json-npm-6.0.4-bf5c705b94-2c72fc8674.zip b/.yarn/cache/read-package-json-npm-6.0.4-bf5c705b94-2c72fc8674.zip deleted file mode 100644 index bcb59e923cb9..000000000000 Binary files a/.yarn/cache/read-package-json-npm-6.0.4-bf5c705b94-2c72fc8674.zip and /dev/null differ diff --git a/.yarn/cache/read-package-up-npm-11.0.0-e39aefc766-535b7554d4.zip b/.yarn/cache/read-package-up-npm-11.0.0-e39aefc766-535b7554d4.zip new file mode 100644 index 000000000000..f3e422f819f0 Binary files /dev/null and b/.yarn/cache/read-package-up-npm-11.0.0-e39aefc766-535b7554d4.zip differ diff --git a/.yarn/cache/read-pkg-npm-9.0.1-a6051ad95a-5544bea2a5.zip b/.yarn/cache/read-pkg-npm-9.0.1-a6051ad95a-5544bea2a5.zip new file mode 100644 index 000000000000..5fbad09c0861 Binary files /dev/null and b/.yarn/cache/read-pkg-npm-9.0.1-a6051ad95a-5544bea2a5.zip differ diff --git a/.yarn/cache/readable-stream-npm-2.3.7-77b22a9818-d04c677c17.zip b/.yarn/cache/readable-stream-npm-2.3.7-77b22a9818-d04c677c17.zip deleted file mode 100644 index 80ed5fbbe3bf..000000000000 Binary files a/.yarn/cache/readable-stream-npm-2.3.7-77b22a9818-d04c677c17.zip and /dev/null differ diff --git a/.yarn/cache/readable-stream-npm-2.3.8-67a94c2cb1-8500dd3a90.zip b/.yarn/cache/readable-stream-npm-2.3.8-67a94c2cb1-8500dd3a90.zip new file mode 100644 index 000000000000..9ef71c9cbe34 Binary files /dev/null and b/.yarn/cache/readable-stream-npm-2.3.8-67a94c2cb1-8500dd3a90.zip differ diff --git a/.yarn/cache/readable-stream-npm-3.6.0-23a4a5eb56-b80b3e6a7f.zip b/.yarn/cache/readable-stream-npm-3.6.0-23a4a5eb56-b80b3e6a7f.zip deleted file mode 100644 index 57b8b2b964ed..000000000000 Binary files a/.yarn/cache/readable-stream-npm-3.6.0-23a4a5eb56-b80b3e6a7f.zip and /dev/null differ diff --git a/.yarn/cache/readable-stream-npm-3.6.2-d2a6069158-d9e3e53193.zip b/.yarn/cache/readable-stream-npm-3.6.2-d2a6069158-d9e3e53193.zip new file mode 100644 index 000000000000..1e44a541ecbe Binary files /dev/null and b/.yarn/cache/readable-stream-npm-3.6.2-d2a6069158-d9e3e53193.zip differ diff --git a/.yarn/cache/reflect.getprototypeof-npm-1.0.6-b33819c756-518f6457e4.zip b/.yarn/cache/reflect.getprototypeof-npm-1.0.6-b33819c756-518f6457e4.zip new file mode 100644 index 000000000000..1b9115102ca4 Binary files /dev/null and b/.yarn/cache/reflect.getprototypeof-npm-1.0.6-b33819c756-518f6457e4.zip differ diff --git a/.yarn/cache/regenerate-unicode-properties-npm-10.1.0-f0d5adf0df-25b2686598.zip b/.yarn/cache/regenerate-unicode-properties-npm-10.1.0-f0d5adf0df-25b2686598.zip deleted file mode 100644 index d15495405a99..000000000000 Binary files a/.yarn/cache/regenerate-unicode-properties-npm-10.1.0-f0d5adf0df-25b2686598.zip and /dev/null differ diff --git a/.yarn/cache/regenerate-unicode-properties-npm-10.1.1-07b52ba05f-b855152efd.zip b/.yarn/cache/regenerate-unicode-properties-npm-10.1.1-07b52ba05f-b855152efd.zip new file mode 100644 index 000000000000..d1c960e9111b Binary files /dev/null and b/.yarn/cache/regenerate-unicode-properties-npm-10.1.1-07b52ba05f-b855152efd.zip differ diff --git a/.yarn/cache/regenerator-runtime-npm-0.14.0-e060897cf7-6c19495bae.zip b/.yarn/cache/regenerator-runtime-npm-0.14.0-e060897cf7-6c19495bae.zip deleted file mode 100644 index c44c1d62bc45..000000000000 Binary files a/.yarn/cache/regenerator-runtime-npm-0.14.0-e060897cf7-6c19495bae.zip and /dev/null differ diff --git a/.yarn/cache/regenerator-runtime-npm-0.14.1-a6c97c609a-5db3161abb.zip b/.yarn/cache/regenerator-runtime-npm-0.14.1-a6c97c609a-5db3161abb.zip new file mode 100644 index 000000000000..176e7550766a Binary files /dev/null and b/.yarn/cache/regenerator-runtime-npm-0.14.1-a6c97c609a-5db3161abb.zip differ diff --git a/.yarn/cache/regexp.prototype.flags-npm-1.4.3-df1c08b65d-3cde7cd22f.zip b/.yarn/cache/regexp.prototype.flags-npm-1.4.3-df1c08b65d-3cde7cd22f.zip deleted file mode 100644 index f841d7b38ca3..000000000000 Binary files a/.yarn/cache/regexp.prototype.flags-npm-1.4.3-df1c08b65d-3cde7cd22f.zip and /dev/null differ diff --git a/.yarn/cache/regexp.prototype.flags-npm-1.5.2-a44e05d7d9-9fffc01da9.zip b/.yarn/cache/regexp.prototype.flags-npm-1.5.2-a44e05d7d9-9fffc01da9.zip new file mode 100644 index 000000000000..eb330049cb6d Binary files /dev/null and b/.yarn/cache/regexp.prototype.flags-npm-1.5.2-a44e05d7d9-9fffc01da9.zip differ diff --git a/.yarn/cache/registry-auth-token-npm-4.2.1-200e2be697-d1a5c28c0b.zip b/.yarn/cache/registry-auth-token-npm-4.2.1-200e2be697-d1a5c28c0b.zip deleted file mode 100644 index fcd418c40031..000000000000 Binary files a/.yarn/cache/registry-auth-token-npm-4.2.1-200e2be697-d1a5c28c0b.zip and /dev/null differ diff --git a/.yarn/cache/registry-auth-token-npm-4.2.2-ffd70a9849-00d1b1c69f.zip b/.yarn/cache/registry-auth-token-npm-4.2.2-ffd70a9849-00d1b1c69f.zip new file mode 100644 index 000000000000..2ebe9a94f6f7 Binary files /dev/null and b/.yarn/cache/registry-auth-token-npm-4.2.2-ffd70a9849-00d1b1c69f.zip differ diff --git a/.yarn/cache/remark-footnotes-npm-3.0.0-b9e76a5f48-d784e52b27.zip b/.yarn/cache/remark-footnotes-npm-3.0.0-b9e76a5f48-d784e52b27.zip new file mode 100644 index 000000000000..12e9087fa171 Binary files /dev/null and b/.yarn/cache/remark-footnotes-npm-3.0.0-b9e76a5f48-d784e52b27.zip differ diff --git a/.yarn/cache/remark-frontmatter-npm-1.3.2-66fdd584ff-6dcf401977.zip b/.yarn/cache/remark-frontmatter-npm-1.3.2-66fdd584ff-6dcf401977.zip deleted file mode 100644 index 2e1ee33c3a6e..000000000000 Binary files a/.yarn/cache/remark-frontmatter-npm-1.3.2-66fdd584ff-6dcf401977.zip and /dev/null differ diff --git a/.yarn/cache/remark-frontmatter-npm-3.0.0-2f35238031-33bbcf36a5.zip b/.yarn/cache/remark-frontmatter-npm-3.0.0-2f35238031-33bbcf36a5.zip new file mode 100644 index 000000000000..87b6cc8cf57b Binary files /dev/null and b/.yarn/cache/remark-frontmatter-npm-3.0.0-2f35238031-33bbcf36a5.zip differ diff --git a/.yarn/cache/remark-gfm-npm-1.0.0-d4e589186b-a37823a762.zip b/.yarn/cache/remark-gfm-npm-1.0.0-d4e589186b-a37823a762.zip new file mode 100644 index 000000000000..55a5dcba9041 Binary files /dev/null and b/.yarn/cache/remark-gfm-npm-1.0.0-d4e589186b-a37823a762.zip differ diff --git a/.yarn/cache/remark-parse-npm-5.0.0-12afcecf81-4b53efff16.zip b/.yarn/cache/remark-parse-npm-5.0.0-12afcecf81-4b53efff16.zip deleted file mode 100644 index d530ba1ed677..000000000000 Binary files a/.yarn/cache/remark-parse-npm-5.0.0-12afcecf81-4b53efff16.zip and /dev/null differ diff --git a/.yarn/cache/remark-parse-npm-9.0.0-da1fe74019-67c22c29f6.zip b/.yarn/cache/remark-parse-npm-9.0.0-da1fe74019-67c22c29f6.zip new file mode 100644 index 000000000000..e443776b81b8 Binary files /dev/null and b/.yarn/cache/remark-parse-npm-9.0.0-da1fe74019-67c22c29f6.zip differ diff --git a/.yarn/cache/repeat-element-npm-1.1.3-a9dee226b4-0743a136b4.zip b/.yarn/cache/repeat-element-npm-1.1.3-a9dee226b4-0743a136b4.zip deleted file mode 100644 index a630addf6957..000000000000 Binary files a/.yarn/cache/repeat-element-npm-1.1.3-a9dee226b4-0743a136b4.zip and /dev/null differ diff --git a/.yarn/cache/repeat-element-npm-1.1.4-7e649ab5b1-1edd0301b7.zip b/.yarn/cache/repeat-element-npm-1.1.4-7e649ab5b1-1edd0301b7.zip new file mode 100644 index 000000000000..2b5c244705cb Binary files /dev/null and b/.yarn/cache/repeat-element-npm-1.1.4-7e649ab5b1-1edd0301b7.zip differ diff --git a/.yarn/cache/replace-ext-npm-1.0.1-ab0bac6614-4994ea1aaa.zip b/.yarn/cache/replace-ext-npm-1.0.1-ab0bac6614-4994ea1aaa.zip new file mode 100644 index 000000000000..74a8b72530d1 Binary files /dev/null and b/.yarn/cache/replace-ext-npm-1.0.1-ab0bac6614-4994ea1aaa.zip differ diff --git a/.yarn/cache/replace-in-file-npm-7.0.1-85b120225d-41c5f5b2ac.zip b/.yarn/cache/replace-in-file-npm-7.0.1-85b120225d-41c5f5b2ac.zip deleted file mode 100644 index 36a5557706ac..000000000000 Binary files a/.yarn/cache/replace-in-file-npm-7.0.1-85b120225d-41c5f5b2ac.zip and /dev/null differ diff --git a/.yarn/cache/replace-in-file-npm-7.2.0-e56362dd88-9d08fc6c65.zip b/.yarn/cache/replace-in-file-npm-7.2.0-e56362dd88-9d08fc6c65.zip new file mode 100644 index 000000000000..b3bcf8a77166 Binary files /dev/null and b/.yarn/cache/replace-in-file-npm-7.2.0-e56362dd88-9d08fc6c65.zip differ diff --git a/.yarn/cache/resolve-npm-2.0.0-next.4-3d0bd8621e-20d5293f50.zip b/.yarn/cache/resolve-npm-2.0.0-next.4-3d0bd8621e-20d5293f50.zip deleted file mode 100644 index deec16c5d968..000000000000 Binary files a/.yarn/cache/resolve-npm-2.0.0-next.4-3d0bd8621e-20d5293f50.zip and /dev/null differ diff --git a/.yarn/cache/resolve-npm-2.0.0-next.5-0e83bf26ee-2d6fd28699.zip b/.yarn/cache/resolve-npm-2.0.0-next.5-0e83bf26ee-2d6fd28699.zip new file mode 100644 index 000000000000..97bc54c8dec0 Binary files /dev/null and b/.yarn/cache/resolve-npm-2.0.0-next.5-0e83bf26ee-2d6fd28699.zip differ diff --git a/.yarn/cache/resolve-patch-95f8f5d302-05fa778de9.zip b/.yarn/cache/resolve-patch-95f8f5d302-05fa778de9.zip new file mode 100644 index 000000000000..bedfa85b0888 Binary files /dev/null and b/.yarn/cache/resolve-patch-95f8f5d302-05fa778de9.zip differ diff --git a/.yarn/cache/resolve-patch-aa9ecc3603-27bff19d82.zip b/.yarn/cache/resolve-patch-aa9ecc3603-27bff19d82.zip deleted file mode 100644 index 2ae03d6f125e..000000000000 Binary files a/.yarn/cache/resolve-patch-aa9ecc3603-27bff19d82.zip and /dev/null differ diff --git a/.yarn/cache/resolve.exports-npm-1.1.0-81756e03ba-6286de2285.zip b/.yarn/cache/resolve.exports-npm-1.1.0-81756e03ba-6286de2285.zip deleted file mode 100644 index 0ebe42ef0b81..000000000000 Binary files a/.yarn/cache/resolve.exports-npm-1.1.0-81756e03ba-6286de2285.zip and /dev/null differ diff --git a/.yarn/cache/resolve.exports-npm-1.1.1-26b48a30b5-de58c30aca.zip b/.yarn/cache/resolve.exports-npm-1.1.1-26b48a30b5-de58c30aca.zip new file mode 100644 index 000000000000..573fb3fa31cc Binary files /dev/null and b/.yarn/cache/resolve.exports-npm-1.1.1-26b48a30b5-de58c30aca.zip differ diff --git a/.yarn/cache/restore-cursor-npm-4.0.0-d42254f39d-5b675c5a59.zip b/.yarn/cache/restore-cursor-npm-4.0.0-d42254f39d-5b675c5a59.zip deleted file mode 100644 index f1f163709384..000000000000 Binary files a/.yarn/cache/restore-cursor-npm-4.0.0-d42254f39d-5b675c5a59.zip and /dev/null differ diff --git a/.yarn/cache/restore-cursor-npm-5.1.0-b8fd1128bf-838dd54e45.zip b/.yarn/cache/restore-cursor-npm-5.1.0-b8fd1128bf-838dd54e45.zip new file mode 100644 index 000000000000..80620acb8388 Binary files /dev/null and b/.yarn/cache/restore-cursor-npm-5.1.0-b8fd1128bf-838dd54e45.zip differ diff --git a/.yarn/cache/rfdc-npm-1.3.0-272f288ad8-76dedd9700.zip b/.yarn/cache/rfdc-npm-1.3.0-272f288ad8-76dedd9700.zip deleted file mode 100644 index 7c75825fb504..000000000000 Binary files a/.yarn/cache/rfdc-npm-1.3.0-272f288ad8-76dedd9700.zip and /dev/null differ diff --git a/.yarn/cache/rfdc-npm-1.4.1-1a1c63d052-2f3d11d3d8.zip b/.yarn/cache/rfdc-npm-1.4.1-1a1c63d052-2f3d11d3d8.zip new file mode 100644 index 000000000000..1b5a66983612 Binary files /dev/null and b/.yarn/cache/rfdc-npm-1.4.1-1a1c63d052-2f3d11d3d8.zip differ diff --git a/.yarn/cache/rimraf-npm-5.0.10-d0c6647697-f3b8ce81ee.zip b/.yarn/cache/rimraf-npm-5.0.10-d0c6647697-f3b8ce81ee.zip deleted file mode 100644 index 29944e8dd254..000000000000 Binary files a/.yarn/cache/rimraf-npm-5.0.10-d0c6647697-f3b8ce81ee.zip and /dev/null differ diff --git a/.yarn/cache/rimraf-npm-5.0.9-a8231bd2f9-443669809c.zip b/.yarn/cache/rimraf-npm-5.0.9-a8231bd2f9-443669809c.zip new file mode 100644 index 000000000000..5471a533b124 Binary files /dev/null and b/.yarn/cache/rimraf-npm-5.0.9-a8231bd2f9-443669809c.zip differ diff --git a/.yarn/cache/rollup-npm-3.22.0-9f29f42b1d-e6b71b9e8b.zip b/.yarn/cache/rollup-npm-3.22.0-9f29f42b1d-e6b71b9e8b.zip deleted file mode 100644 index 20a8e7d66429..000000000000 Binary files a/.yarn/cache/rollup-npm-3.22.0-9f29f42b1d-e6b71b9e8b.zip and /dev/null differ diff --git a/.yarn/cache/rollup-npm-3.29.4-5e5e5f2087-9e39d54e23.zip b/.yarn/cache/rollup-npm-3.29.4-5e5e5f2087-9e39d54e23.zip new file mode 100644 index 000000000000..936b6ed55640 Binary files /dev/null and b/.yarn/cache/rollup-npm-3.29.4-5e5e5f2087-9e39d54e23.zip differ diff --git a/.yarn/cache/rollup-npm-4.19.1-ff34ce3b0b-4e46275cb2.zip b/.yarn/cache/rollup-npm-4.19.1-ff34ce3b0b-4e46275cb2.zip new file mode 100644 index 000000000000..24102f7addb1 Binary files /dev/null and b/.yarn/cache/rollup-npm-4.19.1-ff34ce3b0b-4e46275cb2.zip differ diff --git a/.yarn/cache/rollup-plugin-copy-npm-3.5.0-a5e02864e9-706ba6bd20.zip b/.yarn/cache/rollup-plugin-copy-npm-3.5.0-a5e02864e9-706ba6bd20.zip new file mode 100644 index 000000000000..1ad78b79958f Binary files /dev/null and b/.yarn/cache/rollup-plugin-copy-npm-3.5.0-a5e02864e9-706ba6bd20.zip differ diff --git a/.yarn/cache/rollup-plugin-multi-input-npm-1.5.0-a3a011b425-9752c25cd4.zip b/.yarn/cache/rollup-plugin-multi-input-npm-1.5.0-a3a011b425-9752c25cd4.zip new file mode 100644 index 000000000000..2ccbbbf69046 Binary files /dev/null and b/.yarn/cache/rollup-plugin-multi-input-npm-1.5.0-a3a011b425-9752c25cd4.zip differ diff --git a/.yarn/cache/rollup-plugin-strip-banner-npm-3.0.0-2a6ebec442-d1799342db.zip b/.yarn/cache/rollup-plugin-strip-banner-npm-3.0.0-2a6ebec442-d1799342db.zip deleted file mode 100644 index 1387c7b9d4da..000000000000 Binary files a/.yarn/cache/rollup-plugin-strip-banner-npm-3.0.0-2a6ebec442-d1799342db.zip and /dev/null differ diff --git a/.yarn/cache/rollup-plugin-strip-banner-npm-3.1.0-4c7144d2e7-116161602d.zip b/.yarn/cache/rollup-plugin-strip-banner-npm-3.1.0-4c7144d2e7-116161602d.zip new file mode 100644 index 000000000000..f8a92969c6a1 Binary files /dev/null and b/.yarn/cache/rollup-plugin-strip-banner-npm-3.1.0-4c7144d2e7-116161602d.zip differ diff --git a/.yarn/cache/rollup-pluginutils-npm-2.8.2-f554dd6ac5-f3dc20a873.zip b/.yarn/cache/rollup-pluginutils-npm-2.8.2-f554dd6ac5-f3dc20a873.zip deleted file mode 100644 index 1987ed35d772..000000000000 Binary files a/.yarn/cache/rollup-pluginutils-npm-2.8.2-f554dd6ac5-f3dc20a873.zip and /dev/null differ diff --git a/.yarn/cache/rrweb-cssom-npm-0.7.1-fbf1786bb7-e80cf25c22.zip b/.yarn/cache/rrweb-cssom-npm-0.7.1-fbf1786bb7-e80cf25c22.zip new file mode 100644 index 000000000000..6699870d6799 Binary files /dev/null and b/.yarn/cache/rrweb-cssom-npm-0.7.1-fbf1786bb7-e80cf25c22.zip differ diff --git a/.yarn/cache/run-applescript-npm-5.0.0-ea4b8840dd-d00c2dbfa5.zip b/.yarn/cache/run-applescript-npm-5.0.0-ea4b8840dd-d00c2dbfa5.zip deleted file mode 100644 index 16b3a1cdb817..000000000000 Binary files a/.yarn/cache/run-applescript-npm-5.0.0-ea4b8840dd-d00c2dbfa5.zip and /dev/null differ diff --git a/.yarn/cache/run-parallel-npm-1.1.9-83c6b2d620-8bbeda89c2.zip b/.yarn/cache/run-parallel-npm-1.1.9-83c6b2d620-8bbeda89c2.zip deleted file mode 100644 index 19230ec90046..000000000000 Binary files a/.yarn/cache/run-parallel-npm-1.1.9-83c6b2d620-8bbeda89c2.zip and /dev/null differ diff --git a/.yarn/cache/run-parallel-npm-1.2.0-3f47ff2034-cb4f97ad25.zip b/.yarn/cache/run-parallel-npm-1.2.0-3f47ff2034-cb4f97ad25.zip new file mode 100644 index 000000000000..fefbad56f947 Binary files /dev/null and b/.yarn/cache/run-parallel-npm-1.2.0-3f47ff2034-cb4f97ad25.zip differ diff --git a/.yarn/cache/rxjs-npm-7.5.5-d0546b1ccb-9c8af134bc.zip b/.yarn/cache/rxjs-npm-7.5.5-d0546b1ccb-9c8af134bc.zip deleted file mode 100644 index 117791833f14..000000000000 Binary files a/.yarn/cache/rxjs-npm-7.5.5-d0546b1ccb-9c8af134bc.zip and /dev/null differ diff --git a/.yarn/cache/rxjs-npm-7.8.1-41c443a75b-b10cac1a52.zip b/.yarn/cache/rxjs-npm-7.8.1-41c443a75b-b10cac1a52.zip new file mode 100644 index 000000000000..55b7321ed309 Binary files /dev/null and b/.yarn/cache/rxjs-npm-7.8.1-41c443a75b-b10cac1a52.zip differ diff --git a/.yarn/cache/safe-array-concat-npm-1.1.2-f9c09c1a31-a54f8040d7.zip b/.yarn/cache/safe-array-concat-npm-1.1.2-f9c09c1a31-a54f8040d7.zip new file mode 100644 index 000000000000..08c5613ec1be Binary files /dev/null and b/.yarn/cache/safe-array-concat-npm-1.1.2-f9c09c1a31-a54f8040d7.zip differ diff --git a/.yarn/cache/safe-regex-test-npm-1.0.0-e94a09b84e-c7248dfa07.zip b/.yarn/cache/safe-regex-test-npm-1.0.0-e94a09b84e-c7248dfa07.zip deleted file mode 100644 index 2c4747754f51..000000000000 Binary files a/.yarn/cache/safe-regex-test-npm-1.0.0-e94a09b84e-c7248dfa07.zip and /dev/null differ diff --git a/.yarn/cache/safe-regex-test-npm-1.0.3-97fe5cc608-b04de61114.zip b/.yarn/cache/safe-regex-test-npm-1.0.3-97fe5cc608-b04de61114.zip new file mode 100644 index 000000000000..d246e11f6fb7 Binary files /dev/null and b/.yarn/cache/safe-regex-test-npm-1.0.3-97fe5cc608-b04de61114.zip differ diff --git a/.yarn/cache/sassdoc-npm-2.7.3-63f15ed79b-dc4be09899.zip b/.yarn/cache/sassdoc-npm-2.7.3-63f15ed79b-dc4be09899.zip deleted file mode 100644 index e49d473a48e1..000000000000 Binary files a/.yarn/cache/sassdoc-npm-2.7.3-63f15ed79b-dc4be09899.zip and /dev/null differ diff --git a/.yarn/cache/sassdoc-npm-2.7.4-1c7d69980f-484ea386fe.zip b/.yarn/cache/sassdoc-npm-2.7.4-1c7d69980f-484ea386fe.zip new file mode 100644 index 000000000000..217cd0bd19c3 Binary files /dev/null and b/.yarn/cache/sassdoc-npm-2.7.4-1c7d69980f-484ea386fe.zip differ diff --git a/.yarn/cache/sassdoc-theme-default-npm-2.8.3-fd0ba1c8c4-c0ca83a01c.zip b/.yarn/cache/sassdoc-theme-default-npm-2.8.3-fd0ba1c8c4-c0ca83a01c.zip deleted file mode 100644 index 50b2c8332196..000000000000 Binary files a/.yarn/cache/sassdoc-theme-default-npm-2.8.3-fd0ba1c8c4-c0ca83a01c.zip and /dev/null differ diff --git a/.yarn/cache/sassdoc-theme-default-npm-2.8.6-f3b453be8c-34ed6ccabc.zip b/.yarn/cache/sassdoc-theme-default-npm-2.8.6-f3b453be8c-34ed6ccabc.zip new file mode 100644 index 000000000000..33a5951fba4d Binary files /dev/null and b/.yarn/cache/sassdoc-theme-default-npm-2.8.6-f3b453be8c-34ed6ccabc.zip differ diff --git a/.yarn/cache/saxes-npm-6.0.0-31558949f5-97b50daf6c.zip b/.yarn/cache/saxes-npm-6.0.0-31558949f5-97b50daf6c.zip new file mode 100644 index 000000000000..f0966da3d796 Binary files /dev/null and b/.yarn/cache/saxes-npm-6.0.0-31558949f5-97b50daf6c.zip differ diff --git a/.yarn/cache/schema-utils-npm-2.7.1-f84d18c473-86c3038798.zip b/.yarn/cache/schema-utils-npm-2.7.1-f84d18c473-86c3038798.zip new file mode 100644 index 000000000000..5decad742838 Binary files /dev/null and b/.yarn/cache/schema-utils-npm-2.7.1-f84d18c473-86c3038798.zip differ diff --git a/.yarn/cache/semver-npm-5.7.1-40bcea106b-fbc71cf007.zip b/.yarn/cache/semver-npm-5.7.1-40bcea106b-fbc71cf007.zip deleted file mode 100644 index f5b889320f31..000000000000 Binary files a/.yarn/cache/semver-npm-5.7.1-40bcea106b-fbc71cf007.zip and /dev/null differ diff --git a/.yarn/cache/semver-npm-5.7.2-938ee91eaa-fca14418a1.zip b/.yarn/cache/semver-npm-5.7.2-938ee91eaa-fca14418a1.zip new file mode 100644 index 000000000000..4f3e96aff295 Binary files /dev/null and b/.yarn/cache/semver-npm-5.7.2-938ee91eaa-fca14418a1.zip differ diff --git a/.yarn/cache/semver-npm-7.5.3-275095dbf3-80b4b3784a.zip b/.yarn/cache/semver-npm-7.5.3-275095dbf3-80b4b3784a.zip deleted file mode 100644 index 54286cb2d0de..000000000000 Binary files a/.yarn/cache/semver-npm-7.5.3-275095dbf3-80b4b3784a.zip and /dev/null differ diff --git a/.yarn/cache/semver-npm-7.5.4-c4ad957fcd-985dec0d37.zip b/.yarn/cache/semver-npm-7.5.4-c4ad957fcd-985dec0d37.zip deleted file mode 100644 index ac8c8ea5b851..000000000000 Binary files a/.yarn/cache/semver-npm-7.5.4-c4ad957fcd-985dec0d37.zip and /dev/null differ diff --git a/.yarn/cache/semver-npm-7.6.0-f4630729f6-1b41018df2.zip b/.yarn/cache/semver-npm-7.6.0-f4630729f6-1b41018df2.zip new file mode 100644 index 000000000000..42e5f79620e0 Binary files /dev/null and b/.yarn/cache/semver-npm-7.6.0-f4630729f6-1b41018df2.zip differ diff --git a/.yarn/cache/send-npm-0.19.0-4297594770-1f6064dea0.zip b/.yarn/cache/send-npm-0.19.0-4297594770-1f6064dea0.zip deleted file mode 100644 index 34d76d093c47..000000000000 Binary files a/.yarn/cache/send-npm-0.19.0-4297594770-1f6064dea0.zip and /dev/null differ diff --git a/.yarn/cache/serialize-javascript-npm-6.0.1-fac87289ed-f756b1ff34.zip b/.yarn/cache/serialize-javascript-npm-6.0.1-fac87289ed-f756b1ff34.zip deleted file mode 100644 index 3aac5970c019..000000000000 Binary files a/.yarn/cache/serialize-javascript-npm-6.0.1-fac87289ed-f756b1ff34.zip and /dev/null differ diff --git a/.yarn/cache/serialize-javascript-npm-6.0.2-cc09461d45-445a420a6f.zip b/.yarn/cache/serialize-javascript-npm-6.0.2-cc09461d45-445a420a6f.zip new file mode 100644 index 000000000000..7478beee20f8 Binary files /dev/null and b/.yarn/cache/serialize-javascript-npm-6.0.2-cc09461d45-445a420a6f.zip differ diff --git a/.yarn/cache/serve-static-npm-1.15.0-86c81879f5-699b2d4c29.zip b/.yarn/cache/serve-static-npm-1.15.0-86c81879f5-699b2d4c29.zip new file mode 100644 index 000000000000..2f632d0e6f2b Binary files /dev/null and b/.yarn/cache/serve-static-npm-1.15.0-86c81879f5-699b2d4c29.zip differ diff --git a/.yarn/cache/serve-static-npm-1.16.0-88462a5f62-29a01f67e8.zip b/.yarn/cache/serve-static-npm-1.16.0-88462a5f62-29a01f67e8.zip deleted file mode 100644 index 4084ab653b87..000000000000 Binary files a/.yarn/cache/serve-static-npm-1.16.0-88462a5f62-29a01f67e8.zip and /dev/null differ diff --git a/.yarn/cache/set-function-name-npm-2.0.2-3d9a2d8899-c7614154a5.zip b/.yarn/cache/set-function-name-npm-2.0.2-3d9a2d8899-c7614154a5.zip new file mode 100644 index 000000000000..7a64e14695f3 Binary files /dev/null and b/.yarn/cache/set-function-name-npm-2.0.2-3d9a2d8899-c7614154a5.zip differ diff --git a/.yarn/cache/set-getter-npm-0.1.0-9664f89372-00b9cd529b.zip b/.yarn/cache/set-getter-npm-0.1.0-9664f89372-00b9cd529b.zip deleted file mode 100644 index 59c1b9fa4a99..000000000000 Binary files a/.yarn/cache/set-getter-npm-0.1.0-9664f89372-00b9cd529b.zip and /dev/null differ diff --git a/.yarn/cache/set-getter-npm-0.1.1-85070f31a6-04bc8ffff2.zip b/.yarn/cache/set-getter-npm-0.1.1-85070f31a6-04bc8ffff2.zip new file mode 100644 index 000000000000..ae9ed9763580 Binary files /dev/null and b/.yarn/cache/set-getter-npm-0.1.1-85070f31a6-04bc8ffff2.zip differ diff --git a/.yarn/cache/sigstore-npm-1.6.0-fc786d3026-75143e79e1.zip b/.yarn/cache/sigstore-npm-1.6.0-fc786d3026-75143e79e1.zip deleted file mode 100644 index ec656c91a2ca..000000000000 Binary files a/.yarn/cache/sigstore-npm-1.6.0-fc786d3026-75143e79e1.zip and /dev/null differ diff --git a/.yarn/cache/sigstore-npm-2.3.1-7ab15fe238-4e0a82338d.zip b/.yarn/cache/sigstore-npm-2.3.1-7ab15fe238-4e0a82338d.zip new file mode 100644 index 000000000000..9a31531afadd Binary files /dev/null and b/.yarn/cache/sigstore-npm-2.3.1-7ab15fe238-4e0a82338d.zip differ diff --git a/.yarn/cache/slice-ansi-npm-7.1.0-ecf63701b8-10313dd3cf.zip b/.yarn/cache/slice-ansi-npm-7.1.0-ecf63701b8-10313dd3cf.zip new file mode 100644 index 000000000000..23ea19ad8e8f Binary files /dev/null and b/.yarn/cache/slice-ansi-npm-7.1.0-ecf63701b8-10313dd3cf.zip differ diff --git a/.yarn/cache/smob-npm-1.5.0-acdaaf382d-a1ea453bce.zip b/.yarn/cache/smob-npm-1.5.0-acdaaf382d-a1ea453bce.zip new file mode 100644 index 000000000000..4a65fc40df88 Binary files /dev/null and b/.yarn/cache/smob-npm-1.5.0-acdaaf382d-a1ea453bce.zip differ diff --git a/.yarn/cache/socks-npm-2.7.1-17f2b53052-5074f7d6a1.zip b/.yarn/cache/socks-npm-2.7.1-17f2b53052-5074f7d6a1.zip deleted file mode 100644 index 51cba2db5b16..000000000000 Binary files a/.yarn/cache/socks-npm-2.7.1-17f2b53052-5074f7d6a1.zip and /dev/null differ diff --git a/.yarn/cache/socks-npm-2.8.3-3532b59899-ffcb622c22.zip b/.yarn/cache/socks-npm-2.8.3-3532b59899-ffcb622c22.zip new file mode 100644 index 000000000000..95c8964f1f76 Binary files /dev/null and b/.yarn/cache/socks-npm-2.8.3-3532b59899-ffcb622c22.zip differ diff --git a/.yarn/cache/socks-proxy-agent-npm-7.0.0-7aacf32ea0-26c75d9c62.zip b/.yarn/cache/socks-proxy-agent-npm-7.0.0-7aacf32ea0-26c75d9c62.zip deleted file mode 100644 index 5a88871785ec..000000000000 Binary files a/.yarn/cache/socks-proxy-agent-npm-7.0.0-7aacf32ea0-26c75d9c62.zip and /dev/null differ diff --git a/.yarn/cache/socks-proxy-agent-npm-8.0.4-991722041a-c8e7c2b398.zip b/.yarn/cache/socks-proxy-agent-npm-8.0.4-991722041a-c8e7c2b398.zip new file mode 100644 index 000000000000..ded8e84cab3e Binary files /dev/null and b/.yarn/cache/socks-proxy-agent-npm-8.0.4-991722041a-c8e7c2b398.zip differ diff --git a/.yarn/cache/sourcemap-codec-npm-1.4.8-3a1a9e60b1-6fc57a151e.zip b/.yarn/cache/sourcemap-codec-npm-1.4.8-3a1a9e60b1-6fc57a151e.zip deleted file mode 100644 index c22656c1a565..000000000000 Binary files a/.yarn/cache/sourcemap-codec-npm-1.4.8-3a1a9e60b1-6fc57a151e.zip and /dev/null differ diff --git a/.yarn/cache/spdx-correct-npm-3.1.0-9ad640b3ef-7638519f17.zip b/.yarn/cache/spdx-correct-npm-3.1.0-9ad640b3ef-7638519f17.zip deleted file mode 100644 index eae7c495289c..000000000000 Binary files a/.yarn/cache/spdx-correct-npm-3.1.0-9ad640b3ef-7638519f17.zip and /dev/null differ diff --git a/.yarn/cache/spdx-correct-npm-3.2.0-ffae008484-cc2e4dbef8.zip b/.yarn/cache/spdx-correct-npm-3.2.0-ffae008484-cc2e4dbef8.zip new file mode 100644 index 000000000000..c4377538770b Binary files /dev/null and b/.yarn/cache/spdx-correct-npm-3.2.0-ffae008484-cc2e4dbef8.zip differ diff --git a/.yarn/cache/spdx-exceptions-npm-2.2.0-a19a6b5050-29189de3f6.zip b/.yarn/cache/spdx-exceptions-npm-2.2.0-a19a6b5050-29189de3f6.zip deleted file mode 100644 index 95ec329c60d2..000000000000 Binary files a/.yarn/cache/spdx-exceptions-npm-2.2.0-a19a6b5050-29189de3f6.zip and /dev/null differ diff --git a/.yarn/cache/spdx-exceptions-npm-2.5.0-718ed4b7d6-bb127d6e25.zip b/.yarn/cache/spdx-exceptions-npm-2.5.0-718ed4b7d6-bb127d6e25.zip new file mode 100644 index 000000000000..e278a7eaee72 Binary files /dev/null and b/.yarn/cache/spdx-exceptions-npm-2.5.0-718ed4b7d6-bb127d6e25.zip differ diff --git a/.yarn/cache/spdx-license-ids-npm-3.0.18-08d695a78d-45fdbb50c4.zip b/.yarn/cache/spdx-license-ids-npm-3.0.18-08d695a78d-45fdbb50c4.zip new file mode 100644 index 000000000000..ce89b1784179 Binary files /dev/null and b/.yarn/cache/spdx-license-ids-npm-3.0.18-08d695a78d-45fdbb50c4.zip differ diff --git a/.yarn/cache/spdx-license-ids-npm-3.0.5-cb028e9441-a5b78b6765.zip b/.yarn/cache/spdx-license-ids-npm-3.0.5-cb028e9441-a5b78b6765.zip deleted file mode 100644 index d1ad2da1556c..000000000000 Binary files a/.yarn/cache/spdx-license-ids-npm-3.0.5-cb028e9441-a5b78b6765.zip and /dev/null differ diff --git a/.yarn/cache/sprintf-js-npm-1.1.3-b99efd75b2-e7587128c4.zip b/.yarn/cache/sprintf-js-npm-1.1.3-b99efd75b2-e7587128c4.zip new file mode 100644 index 000000000000..3e6b96b97df9 Binary files /dev/null and b/.yarn/cache/sprintf-js-npm-1.1.3-b99efd75b2-e7587128c4.zip differ diff --git a/.yarn/cache/ssri-npm-10.0.4-f583dafaf3-3f3dc4a0bb.zip b/.yarn/cache/ssri-npm-10.0.4-f583dafaf3-3f3dc4a0bb.zip deleted file mode 100644 index 6aa034628276..000000000000 Binary files a/.yarn/cache/ssri-npm-10.0.4-f583dafaf3-3f3dc4a0bb.zip and /dev/null differ diff --git a/.yarn/cache/ssri-npm-10.0.6-6b8eaec5ce-f92c1b3cc9.zip b/.yarn/cache/ssri-npm-10.0.6-6b8eaec5ce-f92c1b3cc9.zip new file mode 100644 index 000000000000..5b1d495992b6 Binary files /dev/null and b/.yarn/cache/ssri-npm-10.0.6-6b8eaec5ce-f92c1b3cc9.zip differ diff --git a/.yarn/cache/ssri-npm-9.0.1-33ce27f4f8-7638a61e91.zip b/.yarn/cache/ssri-npm-9.0.1-33ce27f4f8-7638a61e91.zip deleted file mode 100644 index a02119ef60e8..000000000000 Binary files a/.yarn/cache/ssri-npm-9.0.1-33ce27f4f8-7638a61e91.zip and /dev/null differ diff --git a/.yarn/cache/stack-utils-npm-2.0.5-e0438f409a-a6d64e5dd2.zip b/.yarn/cache/stack-utils-npm-2.0.5-e0438f409a-a6d64e5dd2.zip deleted file mode 100644 index 80f88759658d..000000000000 Binary files a/.yarn/cache/stack-utils-npm-2.0.5-e0438f409a-a6d64e5dd2.zip and /dev/null differ diff --git a/.yarn/cache/stack-utils-npm-2.0.6-2be1099696-cdc988acbc.zip b/.yarn/cache/stack-utils-npm-2.0.6-2be1099696-cdc988acbc.zip new file mode 100644 index 000000000000..43074d11b282 Binary files /dev/null and b/.yarn/cache/stack-utils-npm-2.0.6-2be1099696-cdc988acbc.zip differ diff --git a/.yarn/cache/state-toggle-npm-1.0.2-011fd812d1-8082196088.zip b/.yarn/cache/state-toggle-npm-1.0.2-011fd812d1-8082196088.zip deleted file mode 100644 index cb136f634f8f..000000000000 Binary files a/.yarn/cache/state-toggle-npm-1.0.2-011fd812d1-8082196088.zip and /dev/null differ diff --git a/.yarn/cache/state-toggle-npm-1.0.3-dd096f8bd0-17398af928.zip b/.yarn/cache/state-toggle-npm-1.0.3-dd096f8bd0-17398af928.zip new file mode 100644 index 000000000000..be673a8ff62d Binary files /dev/null and b/.yarn/cache/state-toggle-npm-1.0.3-dd096f8bd0-17398af928.zip differ diff --git a/.yarn/cache/store2-npm-2.14.2-c286d27e4f-896cb4c75b.zip b/.yarn/cache/store2-npm-2.14.2-c286d27e4f-896cb4c75b.zip deleted file mode 100644 index ca9cb73881dd..000000000000 Binary files a/.yarn/cache/store2-npm-2.14.2-c286d27e4f-896cb4c75b.zip and /dev/null differ diff --git a/.yarn/cache/store2-npm-2.14.3-64e9376f31-f95f6fbacf.zip b/.yarn/cache/store2-npm-2.14.3-64e9376f31-f95f6fbacf.zip new file mode 100644 index 000000000000..9b560da1fea8 Binary files /dev/null and b/.yarn/cache/store2-npm-2.14.3-64e9376f31-f95f6fbacf.zip differ diff --git a/.yarn/cache/stream-shift-npm-1.0.1-9526210fa7-59b82b44b2.zip b/.yarn/cache/stream-shift-npm-1.0.1-9526210fa7-59b82b44b2.zip deleted file mode 100644 index 9d7aa27638aa..000000000000 Binary files a/.yarn/cache/stream-shift-npm-1.0.1-9526210fa7-59b82b44b2.zip and /dev/null differ diff --git a/.yarn/cache/stream-shift-npm-1.0.3-c1c29210c7-a24c0a3f66.zip b/.yarn/cache/stream-shift-npm-1.0.3-c1c29210c7-a24c0a3f66.zip new file mode 100644 index 000000000000..0c61cf24e290 Binary files /dev/null and b/.yarn/cache/stream-shift-npm-1.0.3-c1c29210c7-a24c0a3f66.zip differ diff --git a/.yarn/cache/string-length-npm-4.0.1-f4a493417a-7bd3191668.zip b/.yarn/cache/string-length-npm-4.0.1-f4a493417a-7bd3191668.zip deleted file mode 100644 index 363635c82bdb..000000000000 Binary files a/.yarn/cache/string-length-npm-4.0.1-f4a493417a-7bd3191668.zip and /dev/null differ diff --git a/.yarn/cache/string-length-npm-4.0.2-675173c7a2-ce85533ef5.zip b/.yarn/cache/string-length-npm-4.0.2-675173c7a2-ce85533ef5.zip new file mode 100644 index 000000000000..fd9f62fc86e4 Binary files /dev/null and b/.yarn/cache/string-length-npm-4.0.2-675173c7a2-ce85533ef5.zip differ diff --git a/.yarn/cache/string-width-npm-3.1.0-e031bfa4e0-57f7ca73d2.zip b/.yarn/cache/string-width-npm-3.1.0-e031bfa4e0-57f7ca73d2.zip deleted file mode 100644 index 706d03c8c70f..000000000000 Binary files a/.yarn/cache/string-width-npm-3.1.0-e031bfa4e0-57f7ca73d2.zip and /dev/null differ diff --git a/.yarn/cache/string-width-npm-7.2.0-93572222c9-42f9e82f61.zip b/.yarn/cache/string-width-npm-7.2.0-93572222c9-42f9e82f61.zip new file mode 100644 index 000000000000..e5138f840420 Binary files /dev/null and b/.yarn/cache/string-width-npm-7.2.0-93572222c9-42f9e82f61.zip differ diff --git a/.yarn/cache/string.prototype.includes-npm-2.0.0-05193653bf-34c1e71ac5.zip b/.yarn/cache/string.prototype.includes-npm-2.0.0-05193653bf-34c1e71ac5.zip new file mode 100644 index 000000000000..667b45131980 Binary files /dev/null and b/.yarn/cache/string.prototype.includes-npm-2.0.0-05193653bf-34c1e71ac5.zip differ diff --git a/.yarn/cache/string.prototype.matchall-npm-4.0.11-a18d0665a1-a902ff4500.zip b/.yarn/cache/string.prototype.matchall-npm-4.0.11-a18d0665a1-a902ff4500.zip new file mode 100644 index 000000000000..e5488ac81cca Binary files /dev/null and b/.yarn/cache/string.prototype.matchall-npm-4.0.11-a18d0665a1-a902ff4500.zip differ diff --git a/.yarn/cache/string.prototype.matchall-npm-4.0.8-1feb1531b6-9de2e9e333.zip b/.yarn/cache/string.prototype.matchall-npm-4.0.8-1feb1531b6-9de2e9e333.zip deleted file mode 100644 index 2a4725f30e77..000000000000 Binary files a/.yarn/cache/string.prototype.matchall-npm-4.0.8-1feb1531b6-9de2e9e333.zip and /dev/null differ diff --git a/.yarn/cache/string.prototype.repeat-npm-1.0.0-3f87f5fd9e-4b1bd91b75.zip b/.yarn/cache/string.prototype.repeat-npm-1.0.0-3f87f5fd9e-4b1bd91b75.zip new file mode 100644 index 000000000000..004c48324c94 Binary files /dev/null and b/.yarn/cache/string.prototype.repeat-npm-1.0.0-3f87f5fd9e-4b1bd91b75.zip differ diff --git a/.yarn/cache/string.prototype.trim-npm-1.2.9-7b24b35971-b2170903de.zip b/.yarn/cache/string.prototype.trim-npm-1.2.9-7b24b35971-b2170903de.zip new file mode 100644 index 000000000000..cda0958629fb Binary files /dev/null and b/.yarn/cache/string.prototype.trim-npm-1.2.9-7b24b35971-b2170903de.zip differ diff --git a/.yarn/cache/string.prototype.trimend-npm-1.0.6-304246ecc1-3893db9267.zip b/.yarn/cache/string.prototype.trimend-npm-1.0.6-304246ecc1-3893db9267.zip deleted file mode 100644 index c8b07fbc771d..000000000000 Binary files a/.yarn/cache/string.prototype.trimend-npm-1.0.6-304246ecc1-3893db9267.zip and /dev/null differ diff --git a/.yarn/cache/string.prototype.trimend-npm-1.0.8-9c0ed19266-c2e862ae72.zip b/.yarn/cache/string.prototype.trimend-npm-1.0.8-9c0ed19266-c2e862ae72.zip new file mode 100644 index 000000000000..ad8f4e128fd6 Binary files /dev/null and b/.yarn/cache/string.prototype.trimend-npm-1.0.8-9c0ed19266-c2e862ae72.zip differ diff --git a/.yarn/cache/string.prototype.trimstart-npm-1.0.6-0926caea6c-05e2cd06fa.zip b/.yarn/cache/string.prototype.trimstart-npm-1.0.6-0926caea6c-05e2cd06fa.zip deleted file mode 100644 index 0fb7c079b822..000000000000 Binary files a/.yarn/cache/string.prototype.trimstart-npm-1.0.6-0926caea6c-05e2cd06fa.zip and /dev/null differ diff --git a/.yarn/cache/string.prototype.trimstart-npm-1.0.8-8c6b16ba6e-160167dfbd.zip b/.yarn/cache/string.prototype.trimstart-npm-1.0.8-8c6b16ba6e-160167dfbd.zip new file mode 100644 index 000000000000..8f20c76a68b4 Binary files /dev/null and b/.yarn/cache/string.prototype.trimstart-npm-1.0.8-8c6b16ba6e-160167dfbd.zip differ diff --git a/.yarn/cache/strip-ansi-npm-7.0.1-668c121204-07b3142f51.zip b/.yarn/cache/strip-ansi-npm-7.0.1-668c121204-07b3142f51.zip deleted file mode 100644 index 9c1a35e21fef..000000000000 Binary files a/.yarn/cache/strip-ansi-npm-7.0.1-668c121204-07b3142f51.zip and /dev/null differ diff --git a/.yarn/cache/strip-ansi-npm-7.1.0-7453b80b79-475f53e9c4.zip b/.yarn/cache/strip-ansi-npm-7.1.0-7453b80b79-475f53e9c4.zip new file mode 100644 index 000000000000..41be46932f73 Binary files /dev/null and b/.yarn/cache/strip-ansi-npm-7.1.0-7453b80b79-475f53e9c4.zip differ diff --git a/.yarn/cache/structured-source-npm-3.0.2-3ccec56521-9002109d0d.zip b/.yarn/cache/structured-source-npm-3.0.2-3ccec56521-9002109d0d.zip deleted file mode 100644 index 3f15d2e71c8f..000000000000 Binary files a/.yarn/cache/structured-source-npm-3.0.2-3ccec56521-9002109d0d.zip and /dev/null differ diff --git a/.yarn/cache/style-loader-npm-3.3.1-4bbb6ec77f-8807445469.zip b/.yarn/cache/style-loader-npm-3.3.1-4bbb6ec77f-8807445469.zip deleted file mode 100644 index f3e3c5c31cc1..000000000000 Binary files a/.yarn/cache/style-loader-npm-3.3.1-4bbb6ec77f-8807445469.zip and /dev/null differ diff --git a/.yarn/cache/style-loader-npm-3.3.4-e2ff5c12be-2dd2a77d4f.zip b/.yarn/cache/style-loader-npm-3.3.4-e2ff5c12be-2dd2a77d4f.zip new file mode 100644 index 000000000000..f9ad42bdf741 Binary files /dev/null and b/.yarn/cache/style-loader-npm-3.3.4-e2ff5c12be-2dd2a77d4f.zip differ diff --git a/.yarn/cache/stylehacks-npm-7.0.0-9c71ba2395-b3e3d6b895.zip b/.yarn/cache/stylehacks-npm-7.0.0-9c71ba2395-b3e3d6b895.zip deleted file mode 100644 index 72b0858c4745..000000000000 Binary files a/.yarn/cache/stylehacks-npm-7.0.0-9c71ba2395-b3e3d6b895.zip and /dev/null differ diff --git a/.yarn/cache/stylehacks-npm-7.0.2-bb9f4b8912-987b35c5af.zip b/.yarn/cache/stylehacks-npm-7.0.2-bb9f4b8912-987b35c5af.zip new file mode 100644 index 000000000000..b3d3dfeeb725 Binary files /dev/null and b/.yarn/cache/stylehacks-npm-7.0.2-bb9f4b8912-987b35c5af.zip differ diff --git a/.yarn/cache/stylelint-config-prettier-npm-9.0.3-9e96da5ef3-dc3be203cf.zip b/.yarn/cache/stylelint-config-prettier-npm-9.0.3-9e96da5ef3-dc3be203cf.zip deleted file mode 100644 index 61c1d2f594b1..000000000000 Binary files a/.yarn/cache/stylelint-config-prettier-npm-9.0.3-9e96da5ef3-dc3be203cf.zip and /dev/null differ diff --git a/.yarn/cache/stylelint-config-prettier-npm-9.0.5-5af0cbb34b-f00665801f.zip b/.yarn/cache/stylelint-config-prettier-npm-9.0.5-5af0cbb34b-f00665801f.zip new file mode 100644 index 000000000000..1dec2e2b65d8 Binary files /dev/null and b/.yarn/cache/stylelint-config-prettier-npm-9.0.5-5af0cbb34b-f00665801f.zip differ diff --git a/.yarn/cache/stylelint-config-recommended-scss-npm-13.0.0-ec2f9157e9-5cbb771d75.zip b/.yarn/cache/stylelint-config-recommended-scss-npm-13.0.0-ec2f9157e9-5cbb771d75.zip deleted file mode 100644 index d40963febe0d..000000000000 Binary files a/.yarn/cache/stylelint-config-recommended-scss-npm-13.0.0-ec2f9157e9-5cbb771d75.zip and /dev/null differ diff --git a/.yarn/cache/stylelint-config-recommended-scss-npm-13.1.0-0aa13983d4-249cc47057.zip b/.yarn/cache/stylelint-config-recommended-scss-npm-13.1.0-0aa13983d4-249cc47057.zip new file mode 100644 index 000000000000..95576fca63fe Binary files /dev/null and b/.yarn/cache/stylelint-config-recommended-scss-npm-13.1.0-0aa13983d4-249cc47057.zip differ diff --git a/.yarn/cache/stylelint-config-standard-scss-npm-11.0.0-cb2a19851f-b51102419a.zip b/.yarn/cache/stylelint-config-standard-scss-npm-11.0.0-cb2a19851f-b51102419a.zip deleted file mode 100644 index 801dcdb232ab..000000000000 Binary files a/.yarn/cache/stylelint-config-standard-scss-npm-11.0.0-cb2a19851f-b51102419a.zip and /dev/null differ diff --git a/.yarn/cache/stylelint-config-standard-scss-npm-11.1.0-fb14eb3d7a-fdeb533e19.zip b/.yarn/cache/stylelint-config-standard-scss-npm-11.1.0-fb14eb3d7a-fdeb533e19.zip new file mode 100644 index 000000000000..f15a843a779e Binary files /dev/null and b/.yarn/cache/stylelint-config-standard-scss-npm-11.1.0-fb14eb3d7a-fdeb533e19.zip differ diff --git a/.yarn/cache/stylelint-npm-15.10.1-868cc2cb80-bcab1ae700.zip b/.yarn/cache/stylelint-npm-15.10.1-868cc2cb80-bcab1ae700.zip deleted file mode 100644 index 15e45464d359..000000000000 Binary files a/.yarn/cache/stylelint-npm-15.10.1-868cc2cb80-bcab1ae700.zip and /dev/null differ diff --git a/.yarn/cache/stylelint-npm-15.11.0-6dc193bb48-34b9242b8a.zip b/.yarn/cache/stylelint-npm-15.11.0-6dc193bb48-34b9242b8a.zip new file mode 100644 index 000000000000..7929356fdb09 Binary files /dev/null and b/.yarn/cache/stylelint-npm-15.11.0-6dc193bb48-34b9242b8a.zip differ diff --git a/.yarn/cache/stylelint-scss-npm-4.1.0-dea750842a-cf71cfb363.zip b/.yarn/cache/stylelint-scss-npm-4.1.0-dea750842a-cf71cfb363.zip deleted file mode 100644 index bf0c8ef6205b..000000000000 Binary files a/.yarn/cache/stylelint-scss-npm-4.1.0-dea750842a-cf71cfb363.zip and /dev/null differ diff --git a/.yarn/cache/stylelint-scss-npm-4.7.0-e9df7622f7-6a49f1f193.zip b/.yarn/cache/stylelint-scss-npm-4.7.0-e9df7622f7-6a49f1f193.zip new file mode 100644 index 000000000000..fa302881c340 Binary files /dev/null and b/.yarn/cache/stylelint-scss-npm-4.7.0-e9df7622f7-6a49f1f193.zip differ diff --git a/.yarn/cache/stylelint-scss-npm-5.1.0-99c0b1dab4-4d9488acde.zip b/.yarn/cache/stylelint-scss-npm-5.1.0-99c0b1dab4-4d9488acde.zip deleted file mode 100644 index c4a738d9c9d8..000000000000 Binary files a/.yarn/cache/stylelint-scss-npm-5.1.0-99c0b1dab4-4d9488acde.zip and /dev/null differ diff --git a/.yarn/cache/stylelint-scss-npm-5.3.2-ff07be35e5-1b8406bdb3.zip b/.yarn/cache/stylelint-scss-npm-5.3.2-ff07be35e5-1b8406bdb3.zip new file mode 100644 index 000000000000..6eca6cff707a Binary files /dev/null and b/.yarn/cache/stylelint-scss-npm-5.3.2-ff07be35e5-1b8406bdb3.zip differ diff --git a/.yarn/cache/stylelint-use-logical-npm-2.1.0-3c4853dd7e-91109a2d65.zip b/.yarn/cache/stylelint-use-logical-npm-2.1.0-3c4853dd7e-91109a2d65.zip deleted file mode 100644 index aa7840fada53..000000000000 Binary files a/.yarn/cache/stylelint-use-logical-npm-2.1.0-3c4853dd7e-91109a2d65.zip and /dev/null differ diff --git a/.yarn/cache/stylelint-use-logical-npm-2.1.2-37770a3485-8e96ffa085.zip b/.yarn/cache/stylelint-use-logical-npm-2.1.2-37770a3485-8e96ffa085.zip new file mode 100644 index 000000000000..f08eec4aa93e Binary files /dev/null and b/.yarn/cache/stylelint-use-logical-npm-2.1.2-37770a3485-8e96ffa085.zip differ diff --git a/.yarn/cache/supports-color-npm-7.1.0-df2ba1e338-f5b2df5336.zip b/.yarn/cache/supports-color-npm-7.1.0-df2ba1e338-f5b2df5336.zip deleted file mode 100644 index f98e5301de65..000000000000 Binary files a/.yarn/cache/supports-color-npm-7.1.0-df2ba1e338-f5b2df5336.zip and /dev/null differ diff --git a/.yarn/cache/supports-color-npm-7.2.0-606bfcf7da-c8bb7afd56.zip b/.yarn/cache/supports-color-npm-7.2.0-606bfcf7da-c8bb7afd56.zip new file mode 100644 index 000000000000..7ee64222e6da Binary files /dev/null and b/.yarn/cache/supports-color-npm-7.2.0-606bfcf7da-c8bb7afd56.zip differ diff --git a/.yarn/cache/supports-hyperlinks-npm-2.2.0-9b22a6271b-a63f2acba5.zip b/.yarn/cache/supports-hyperlinks-npm-2.2.0-9b22a6271b-a63f2acba5.zip deleted file mode 100644 index ae491693d14a..000000000000 Binary files a/.yarn/cache/supports-hyperlinks-npm-2.2.0-9b22a6271b-a63f2acba5.zip and /dev/null differ diff --git a/.yarn/cache/supports-hyperlinks-npm-2.3.0-d19176eba2-3e7df6e9ea.zip b/.yarn/cache/supports-hyperlinks-npm-2.3.0-d19176eba2-3e7df6e9ea.zip new file mode 100644 index 000000000000..13f311e50818 Binary files /dev/null and b/.yarn/cache/supports-hyperlinks-npm-2.3.0-d19176eba2-3e7df6e9ea.zip differ diff --git a/.yarn/cache/svgo-npm-3.2.0-3ad9c97efb-2fdf3f2090.zip b/.yarn/cache/svgo-npm-3.2.0-3ad9c97efb-2fdf3f2090.zip deleted file mode 100644 index cb63994c1bb9..000000000000 Binary files a/.yarn/cache/svgo-npm-3.2.0-3ad9c97efb-2fdf3f2090.zip and /dev/null differ diff --git a/.yarn/cache/svgo-npm-3.3.2-69e1d32944-82fdea9b93.zip b/.yarn/cache/svgo-npm-3.3.2-69e1d32944-82fdea9b93.zip new file mode 100644 index 000000000000..d88dbd02c646 Binary files /dev/null and b/.yarn/cache/svgo-npm-3.3.2-69e1d32944-82fdea9b93.zip differ diff --git a/.yarn/cache/svgson-npm-5.2.1-48e9fe6c8b-de0fe963b4.zip b/.yarn/cache/svgson-npm-5.2.1-48e9fe6c8b-de0fe963b4.zip deleted file mode 100644 index 8216afefa787..000000000000 Binary files a/.yarn/cache/svgson-npm-5.2.1-48e9fe6c8b-de0fe963b4.zip and /dev/null differ diff --git a/.yarn/cache/svgson-npm-5.3.1-27a05df429-c0affdf54c.zip b/.yarn/cache/svgson-npm-5.3.1-27a05df429-c0affdf54c.zip new file mode 100644 index 000000000000..e9ed2eb0495e Binary files /dev/null and b/.yarn/cache/svgson-npm-5.3.1-27a05df429-c0affdf54c.zip differ diff --git a/.yarn/cache/synchronous-promise-npm-2.0.15-5311c7e3c6-fbd4cfe53a.zip b/.yarn/cache/synchronous-promise-npm-2.0.15-5311c7e3c6-fbd4cfe53a.zip deleted file mode 100644 index ce7c003656be..000000000000 Binary files a/.yarn/cache/synchronous-promise-npm-2.0.15-5311c7e3c6-fbd4cfe53a.zip and /dev/null differ diff --git a/.yarn/cache/synchronous-promise-npm-2.0.17-949e3e408d-dd74b1c05c.zip b/.yarn/cache/synchronous-promise-npm-2.0.17-949e3e408d-dd74b1c05c.zip new file mode 100644 index 000000000000..0f76d507ece5 Binary files /dev/null and b/.yarn/cache/synchronous-promise-npm-2.0.17-949e3e408d-dd74b1c05c.zip differ diff --git a/.yarn/cache/synckit-npm-0.8.5-40a594eb38-fb6798a2db.zip b/.yarn/cache/synckit-npm-0.8.5-40a594eb38-fb6798a2db.zip deleted file mode 100644 index 6030253962ea..000000000000 Binary files a/.yarn/cache/synckit-npm-0.8.5-40a594eb38-fb6798a2db.zip and /dev/null differ diff --git a/.yarn/cache/table-npm-6.8.1-83abb79e20-512c4f2bfb.zip b/.yarn/cache/table-npm-6.8.1-83abb79e20-512c4f2bfb.zip deleted file mode 100644 index 0dfea359708a..000000000000 Binary files a/.yarn/cache/table-npm-6.8.1-83abb79e20-512c4f2bfb.zip and /dev/null differ diff --git a/.yarn/cache/table-npm-6.8.2-e33ecc3c54-2946162eb8.zip b/.yarn/cache/table-npm-6.8.2-e33ecc3c54-2946162eb8.zip new file mode 100644 index 000000000000..82d57d0d69fc Binary files /dev/null and b/.yarn/cache/table-npm-6.8.2-e33ecc3c54-2946162eb8.zip differ diff --git a/.yarn/cache/tar-npm-6.1.11-e6ac3cba9c-0e6789e664.zip b/.yarn/cache/tar-npm-6.1.11-e6ac3cba9c-0e6789e664.zip deleted file mode 100644 index d7f57a7b2f8e..000000000000 Binary files a/.yarn/cache/tar-npm-6.1.11-e6ac3cba9c-0e6789e664.zip and /dev/null differ diff --git a/.yarn/cache/tar-npm-6.1.15-44c3e71720-4848b92da8.zip b/.yarn/cache/tar-npm-6.1.15-44c3e71720-4848b92da8.zip deleted file mode 100644 index 25d3eb07d620..000000000000 Binary files a/.yarn/cache/tar-npm-6.1.15-44c3e71720-4848b92da8.zip and /dev/null differ diff --git a/.yarn/cache/tar-npm-6.2.1-237800bb20-bfbfbb2861.zip b/.yarn/cache/tar-npm-6.2.1-237800bb20-bfbfbb2861.zip new file mode 100644 index 000000000000..066f404767f0 Binary files /dev/null and b/.yarn/cache/tar-npm-6.2.1-237800bb20-bfbfbb2861.zip differ diff --git a/.yarn/cache/tcp-port-used-npm-1.0.1-606137b443-7e7be88a5b.zip b/.yarn/cache/tcp-port-used-npm-1.0.1-606137b443-7e7be88a5b.zip deleted file mode 100644 index b9929a1bc961..000000000000 Binary files a/.yarn/cache/tcp-port-used-npm-1.0.1-606137b443-7e7be88a5b.zip and /dev/null differ diff --git a/.yarn/cache/tcp-port-used-npm-1.0.2-538a2b9319-bbacbcbe15.zip b/.yarn/cache/tcp-port-used-npm-1.0.2-538a2b9319-bbacbcbe15.zip new file mode 100644 index 000000000000..6c0df035deec Binary files /dev/null and b/.yarn/cache/tcp-port-used-npm-1.0.2-538a2b9319-bbacbcbe15.zip differ diff --git a/.yarn/cache/term-size-npm-2.1.1-cc33072583-4f6d2fd77e.zip b/.yarn/cache/term-size-npm-2.1.1-cc33072583-4f6d2fd77e.zip deleted file mode 100644 index 4a35d8147ede..000000000000 Binary files a/.yarn/cache/term-size-npm-2.1.1-cc33072583-4f6d2fd77e.zip and /dev/null differ diff --git a/.yarn/cache/term-size-npm-2.2.1-77ce7141d0-f96aca2d41.zip b/.yarn/cache/term-size-npm-2.2.1-77ce7141d0-f96aca2d41.zip new file mode 100644 index 000000000000..0d0d0dc3bc9e Binary files /dev/null and b/.yarn/cache/term-size-npm-2.2.1-77ce7141d0-f96aca2d41.zip differ diff --git a/.yarn/cache/throat-npm-6.0.1-1308a37a10-b4788024c1.zip b/.yarn/cache/throat-npm-6.0.1-1308a37a10-b4788024c1.zip deleted file mode 100644 index d987f39ba777..000000000000 Binary files a/.yarn/cache/throat-npm-6.0.1-1308a37a10-b4788024c1.zip and /dev/null differ diff --git a/.yarn/cache/titleize-npm-3.0.0-7deac2f3a3-71fbbeabbf.zip b/.yarn/cache/titleize-npm-3.0.0-7deac2f3a3-71fbbeabbf.zip deleted file mode 100644 index e63061ae7598..000000000000 Binary files a/.yarn/cache/titleize-npm-3.0.0-7deac2f3a3-71fbbeabbf.zip and /dev/null differ diff --git a/.yarn/cache/tmp-npm-0.2.1-a9c8d9c0ca-445148d72d.zip b/.yarn/cache/tmp-npm-0.2.1-a9c8d9c0ca-445148d72d.zip deleted file mode 100644 index ffa02cc792d5..000000000000 Binary files a/.yarn/cache/tmp-npm-0.2.1-a9c8d9c0ca-445148d72d.zip and /dev/null differ diff --git a/.yarn/cache/tmp-npm-0.2.3-ac2a701365-7b13696787.zip b/.yarn/cache/tmp-npm-0.2.3-ac2a701365-7b13696787.zip new file mode 100644 index 000000000000..c641fd08536e Binary files /dev/null and b/.yarn/cache/tmp-npm-0.2.3-ac2a701365-7b13696787.zip differ diff --git a/.yarn/cache/tough-cookie-npm-4.0.0-7c5f3086af-1c9764cbe1.zip b/.yarn/cache/tough-cookie-npm-4.0.0-7c5f3086af-1c9764cbe1.zip deleted file mode 100644 index 6a4139f933e3..000000000000 Binary files a/.yarn/cache/tough-cookie-npm-4.0.0-7c5f3086af-1c9764cbe1.zip and /dev/null differ diff --git a/.yarn/cache/tough-cookie-npm-4.1.4-8293cc8bd5-75663f4e2c.zip b/.yarn/cache/tough-cookie-npm-4.1.4-8293cc8bd5-75663f4e2c.zip new file mode 100644 index 000000000000..663ceb00483f Binary files /dev/null and b/.yarn/cache/tough-cookie-npm-4.1.4-8293cc8bd5-75663f4e2c.zip differ diff --git a/.yarn/cache/tr46-npm-5.0.0-d15754040d-29155adb16.zip b/.yarn/cache/tr46-npm-5.0.0-d15754040d-29155adb16.zip new file mode 100644 index 000000000000..dd0ef5e65c3c Binary files /dev/null and b/.yarn/cache/tr46-npm-5.0.0-d15754040d-29155adb16.zip differ diff --git a/.yarn/cache/traverse-npm-0.6.6-584cfa4b5f-8c300c9d15.zip b/.yarn/cache/traverse-npm-0.6.6-584cfa4b5f-8c300c9d15.zip deleted file mode 100644 index 0efaea4fbd7f..000000000000 Binary files a/.yarn/cache/traverse-npm-0.6.6-584cfa4b5f-8c300c9d15.zip and /dev/null differ diff --git a/.yarn/cache/traverse-npm-0.6.9-1eef6e6615-7f42c2fa34.zip b/.yarn/cache/traverse-npm-0.6.9-1eef6e6615-7f42c2fa34.zip new file mode 100644 index 000000000000..4cefc0344495 Binary files /dev/null and b/.yarn/cache/traverse-npm-0.6.9-1eef6e6615-7f42c2fa34.zip differ diff --git a/.yarn/cache/treeverse-npm-3.0.0-6c6d119afd-a053ad73f8.zip b/.yarn/cache/treeverse-npm-3.0.0-6c6d119afd-a053ad73f8.zip new file mode 100644 index 000000000000..b595fb57a804 Binary files /dev/null and b/.yarn/cache/treeverse-npm-3.0.0-6c6d119afd-a053ad73f8.zip differ diff --git a/.yarn/cache/trim-newlines-npm-3.0.0-ccf666d8fc-ad99b771e7.zip b/.yarn/cache/trim-newlines-npm-3.0.0-ccf666d8fc-ad99b771e7.zip deleted file mode 100644 index e1f7dff0a461..000000000000 Binary files a/.yarn/cache/trim-newlines-npm-3.0.0-ccf666d8fc-ad99b771e7.zip and /dev/null differ diff --git a/.yarn/cache/trim-newlines-npm-3.0.1-22f1f216de-b530f3fadf.zip b/.yarn/cache/trim-newlines-npm-3.0.1-22f1f216de-b530f3fadf.zip new file mode 100644 index 000000000000..78830598d8b5 Binary files /dev/null and b/.yarn/cache/trim-newlines-npm-3.0.1-22f1f216de-b530f3fadf.zip differ diff --git a/.yarn/cache/trim-trailing-lines-npm-1.1.3-4ce3bbeef5-7eb4ac5407.zip b/.yarn/cache/trim-trailing-lines-npm-1.1.3-4ce3bbeef5-7eb4ac5407.zip deleted file mode 100644 index f87ea9f0bde7..000000000000 Binary files a/.yarn/cache/trim-trailing-lines-npm-1.1.3-4ce3bbeef5-7eb4ac5407.zip and /dev/null differ diff --git a/.yarn/cache/trim-trailing-lines-npm-1.1.4-4bf3b2c576-5d39d21c0d.zip b/.yarn/cache/trim-trailing-lines-npm-1.1.4-4bf3b2c576-5d39d21c0d.zip new file mode 100644 index 000000000000..6edc8a0095c8 Binary files /dev/null and b/.yarn/cache/trim-trailing-lines-npm-1.1.4-4bf3b2c576-5d39d21c0d.zip differ diff --git a/.yarn/cache/trough-npm-2.1.0-20e92f46fc-6ca8a545d0.zip b/.yarn/cache/trough-npm-2.1.0-20e92f46fc-6ca8a545d0.zip deleted file mode 100644 index c760142bef96..000000000000 Binary files a/.yarn/cache/trough-npm-2.1.0-20e92f46fc-6ca8a545d0.zip and /dev/null differ diff --git a/.yarn/cache/trough-npm-2.2.0-270c93d515-999c1cb3db.zip b/.yarn/cache/trough-npm-2.2.0-270c93d515-999c1cb3db.zip new file mode 100644 index 000000000000..3c719e1cee12 Binary files /dev/null and b/.yarn/cache/trough-npm-2.2.0-270c93d515-999c1cb3db.zip differ diff --git a/.yarn/cache/ts-simple-type-npm-2.0.0-next.0-dea8517f23-af58c76024.zip b/.yarn/cache/ts-simple-type-npm-2.0.0-next.0-dea8517f23-af58c76024.zip new file mode 100644 index 000000000000..9fa5278aafd7 Binary files /dev/null and b/.yarn/cache/ts-simple-type-npm-2.0.0-next.0-dea8517f23-af58c76024.zip differ diff --git a/.yarn/cache/tsconfig-paths-npm-3.14.1-17a815b5c5-51be8bd8f9.zip b/.yarn/cache/tsconfig-paths-npm-3.14.1-17a815b5c5-51be8bd8f9.zip deleted file mode 100644 index 813304e5a22d..000000000000 Binary files a/.yarn/cache/tsconfig-paths-npm-3.14.1-17a815b5c5-51be8bd8f9.zip and /dev/null differ diff --git a/.yarn/cache/tsconfig-paths-npm-3.15.0-ff68930e0e-2041beaedc.zip b/.yarn/cache/tsconfig-paths-npm-3.15.0-ff68930e0e-2041beaedc.zip new file mode 100644 index 000000000000..bde94ef95212 Binary files /dev/null and b/.yarn/cache/tsconfig-paths-npm-3.15.0-ff68930e0e-2041beaedc.zip differ diff --git a/.yarn/cache/tslib-npm-2.6.2-4fc8c068d9-bd26c22d36.zip b/.yarn/cache/tslib-npm-2.6.2-4fc8c068d9-bd26c22d36.zip deleted file mode 100644 index 9df1e1a94446..000000000000 Binary files a/.yarn/cache/tslib-npm-2.6.2-4fc8c068d9-bd26c22d36.zip and /dev/null differ diff --git a/.yarn/cache/tslib-npm-2.6.3-0fd136b3be-52109bb681.zip b/.yarn/cache/tslib-npm-2.6.3-0fd136b3be-52109bb681.zip new file mode 100644 index 000000000000..a62a327b9cc1 Binary files /dev/null and b/.yarn/cache/tslib-npm-2.6.3-0fd136b3be-52109bb681.zip differ diff --git a/.yarn/cache/tuf-js-npm-1.1.6-976a3cf45a-515df28005.zip b/.yarn/cache/tuf-js-npm-1.1.6-976a3cf45a-515df28005.zip deleted file mode 100644 index e49be425e37c..000000000000 Binary files a/.yarn/cache/tuf-js-npm-1.1.6-976a3cf45a-515df28005.zip and /dev/null differ diff --git a/.yarn/cache/tuf-js-npm-2.2.1-3baf642bf9-4c057f4f0c.zip b/.yarn/cache/tuf-js-npm-2.2.1-3baf642bf9-4c057f4f0c.zip new file mode 100644 index 000000000000..577e491f6b11 Binary files /dev/null and b/.yarn/cache/tuf-js-npm-2.2.1-3baf642bf9-4c057f4f0c.zip differ diff --git a/.yarn/cache/type-fest-npm-3.13.1-4bd562882d-9a8a2359ad.zip b/.yarn/cache/type-fest-npm-3.13.1-4bd562882d-9a8a2359ad.zip deleted file mode 100644 index a833df7a12c4..000000000000 Binary files a/.yarn/cache/type-fest-npm-3.13.1-4bd562882d-9a8a2359ad.zip and /dev/null differ diff --git a/.yarn/cache/type-fest-npm-4.23.0-cea2c34bb1-c411dea832.zip b/.yarn/cache/type-fest-npm-4.23.0-cea2c34bb1-c411dea832.zip new file mode 100644 index 000000000000..098133a67a1d Binary files /dev/null and b/.yarn/cache/type-fest-npm-4.23.0-cea2c34bb1-c411dea832.zip differ diff --git a/.yarn/cache/typed-array-buffer-npm-1.0.2-31e458f38d-02ffc185d2.zip b/.yarn/cache/typed-array-buffer-npm-1.0.2-31e458f38d-02ffc185d2.zip new file mode 100644 index 000000000000..8d9408043ed7 Binary files /dev/null and b/.yarn/cache/typed-array-buffer-npm-1.0.2-31e458f38d-02ffc185d2.zip differ diff --git a/.yarn/cache/typed-array-byte-length-npm-1.0.1-9ab0891fb8-e4a3832973.zip b/.yarn/cache/typed-array-byte-length-npm-1.0.1-9ab0891fb8-e4a3832973.zip new file mode 100644 index 000000000000..9843e08c03b9 Binary files /dev/null and b/.yarn/cache/typed-array-byte-length-npm-1.0.1-9ab0891fb8-e4a3832973.zip differ diff --git a/.yarn/cache/typed-array-byte-offset-npm-1.0.2-14b64ee0e1-ac26d720eb.zip b/.yarn/cache/typed-array-byte-offset-npm-1.0.2-14b64ee0e1-ac26d720eb.zip new file mode 100644 index 000000000000..9ed84411279d Binary files /dev/null and b/.yarn/cache/typed-array-byte-offset-npm-1.0.2-14b64ee0e1-ac26d720eb.zip differ diff --git a/.yarn/cache/typed-array-length-npm-1.0.4-92771b81fc-0444658acc.zip b/.yarn/cache/typed-array-length-npm-1.0.4-92771b81fc-0444658acc.zip deleted file mode 100644 index 5f4dc17c3440..000000000000 Binary files a/.yarn/cache/typed-array-length-npm-1.0.4-92771b81fc-0444658acc.zip and /dev/null differ diff --git a/.yarn/cache/typed-array-length-npm-1.0.6-867a36a1ac-05e96cf4ff.zip b/.yarn/cache/typed-array-length-npm-1.0.6-867a36a1ac-05e96cf4ff.zip new file mode 100644 index 000000000000..e30231a4aa97 Binary files /dev/null and b/.yarn/cache/typed-array-length-npm-1.0.6-867a36a1ac-05e96cf4ff.zip differ diff --git a/.yarn/cache/typedarray.prototype.slice-npm-1.0.3-658646c112-07bfebdfb7.zip b/.yarn/cache/typedarray.prototype.slice-npm-1.0.3-658646c112-07bfebdfb7.zip new file mode 100644 index 000000000000..c3f9541fd777 Binary files /dev/null and b/.yarn/cache/typedarray.prototype.slice-npm-1.0.3-658646c112-07bfebdfb7.zip differ diff --git a/.yarn/cache/typescript-config-carbon-npm-0.2.1-c0f39febdf-74adc73b35.zip b/.yarn/cache/typescript-config-carbon-npm-0.2.1-c0f39febdf-74adc73b35.zip new file mode 100644 index 000000000000..9417a66a196a Binary files /dev/null and b/.yarn/cache/typescript-config-carbon-npm-0.2.1-c0f39febdf-74adc73b35.zip differ diff --git a/.yarn/cache/typescript-npm-4.9.4-51bdca3293-1f2cc85edc.zip b/.yarn/cache/typescript-npm-4.9.4-51bdca3293-1f2cc85edc.zip deleted file mode 100644 index fba65bf8a661..000000000000 Binary files a/.yarn/cache/typescript-npm-4.9.4-51bdca3293-1f2cc85edc.zip and /dev/null differ diff --git a/.yarn/cache/typescript-npm-4.9.5-6427b65ee6-458f7220ab.zip b/.yarn/cache/typescript-npm-4.9.5-6427b65ee6-458f7220ab.zip new file mode 100644 index 000000000000..670d35857e17 Binary files /dev/null and b/.yarn/cache/typescript-npm-4.9.5-6427b65ee6-458f7220ab.zip differ diff --git a/.yarn/cache/typescript-npm-5.2.2-01717e9f84-d65e50eb84.zip b/.yarn/cache/typescript-npm-5.2.2-01717e9f84-d65e50eb84.zip new file mode 100644 index 000000000000..8efb9db3c893 Binary files /dev/null and b/.yarn/cache/typescript-npm-5.2.2-01717e9f84-d65e50eb84.zip differ diff --git a/.yarn/cache/typescript-npm-5.5.4-79ce5f60f7-1689ccafef.zip b/.yarn/cache/typescript-npm-5.5.4-79ce5f60f7-1689ccafef.zip new file mode 100644 index 000000000000..0f260d381694 Binary files /dev/null and b/.yarn/cache/typescript-npm-5.5.4-79ce5f60f7-1689ccafef.zip differ diff --git a/.yarn/cache/typescript-patch-2cdf849ef5-ba4a4e1758.zip b/.yarn/cache/typescript-patch-2cdf849ef5-ba4a4e1758.zip deleted file mode 100644 index 0f450bfeea8f..000000000000 Binary files a/.yarn/cache/typescript-patch-2cdf849ef5-ba4a4e1758.zip and /dev/null differ diff --git a/.yarn/cache/typescript-patch-32ada147aa-5659316360.zip b/.yarn/cache/typescript-patch-32ada147aa-5659316360.zip new file mode 100644 index 000000000000..22620463facb Binary files /dev/null and b/.yarn/cache/typescript-patch-32ada147aa-5659316360.zip differ diff --git a/.yarn/cache/typescript-patch-3914634c3a-f79cc2ba80.zip b/.yarn/cache/typescript-patch-3914634c3a-f79cc2ba80.zip new file mode 100644 index 000000000000..91e1304cf7d3 Binary files /dev/null and b/.yarn/cache/typescript-patch-3914634c3a-f79cc2ba80.zip differ diff --git a/.yarn/cache/typescript-patch-fe43cd9db9-746fdd0865.zip b/.yarn/cache/typescript-patch-fe43cd9db9-746fdd0865.zip new file mode 100644 index 000000000000..1c79d5116c45 Binary files /dev/null and b/.yarn/cache/typescript-patch-fe43cd9db9-746fdd0865.zip differ diff --git a/.yarn/cache/ufo-npm-1.5.4-42a56e96d8-a885ed421e.zip b/.yarn/cache/ufo-npm-1.5.4-42a56e96d8-a885ed421e.zip new file mode 100644 index 000000000000..61f35db7a4da Binary files /dev/null and b/.yarn/cache/ufo-npm-1.5.4-42a56e96d8-a885ed421e.zip differ diff --git a/.yarn/cache/uglify-js-npm-3.19.1-43e61650b6-c24658b514.zip b/.yarn/cache/uglify-js-npm-3.19.1-43e61650b6-c24658b514.zip new file mode 100644 index 000000000000..590971d4f28c Binary files /dev/null and b/.yarn/cache/uglify-js-npm-3.19.1-43e61650b6-c24658b514.zip differ diff --git a/.yarn/cache/uglify-js-npm-3.7.6-60bad59a13-36a0602e63.zip b/.yarn/cache/uglify-js-npm-3.7.6-60bad59a13-36a0602e63.zip deleted file mode 100644 index e4bf67bbee6b..000000000000 Binary files a/.yarn/cache/uglify-js-npm-3.7.6-60bad59a13-36a0602e63.zip and /dev/null differ diff --git a/.yarn/cache/underscore-npm-1.12.1-f5ca0889f5-c3bb50c61e.zip b/.yarn/cache/underscore-npm-1.12.1-f5ca0889f5-c3bb50c61e.zip deleted file mode 100644 index 1f0ef0a1d9dc..000000000000 Binary files a/.yarn/cache/underscore-npm-1.12.1-f5ca0889f5-c3bb50c61e.zip and /dev/null differ diff --git a/.yarn/cache/underscore-npm-1.13.7-f57feeae48-1ce3368dbe.zip b/.yarn/cache/underscore-npm-1.13.7-f57feeae48-1ce3368dbe.zip new file mode 100644 index 000000000000..e8fc108fd655 Binary files /dev/null and b/.yarn/cache/underscore-npm-1.13.7-f57feeae48-1ce3368dbe.zip differ diff --git a/.yarn/cache/unherit-npm-1.1.2-b37f2c6f5e-b5d55cf2ea.zip b/.yarn/cache/unherit-npm-1.1.2-b37f2c6f5e-b5d55cf2ea.zip deleted file mode 100644 index c2416164146f..000000000000 Binary files a/.yarn/cache/unherit-npm-1.1.2-b37f2c6f5e-b5d55cf2ea.zip and /dev/null differ diff --git a/.yarn/cache/unherit-npm-1.1.3-14f0bf5f12-fd7922f84f.zip b/.yarn/cache/unherit-npm-1.1.3-14f0bf5f12-fd7922f84f.zip new file mode 100644 index 000000000000..0cfadce5b659 Binary files /dev/null and b/.yarn/cache/unherit-npm-1.1.3-14f0bf5f12-fd7922f84f.zip differ diff --git a/.yarn/cache/unicode-property-aliases-ecmascript-npm-2.0.0-1636cb7768-dda4d39128.zip b/.yarn/cache/unicode-property-aliases-ecmascript-npm-2.0.0-1636cb7768-dda4d39128.zip deleted file mode 100644 index cdaff76639d7..000000000000 Binary files a/.yarn/cache/unicode-property-aliases-ecmascript-npm-2.0.0-1636cb7768-dda4d39128.zip and /dev/null differ diff --git a/.yarn/cache/unicode-property-aliases-ecmascript-npm-2.1.0-46779595f4-2435244318.zip b/.yarn/cache/unicode-property-aliases-ecmascript-npm-2.1.0-46779595f4-2435244318.zip new file mode 100644 index 000000000000..be89e75a78bd Binary files /dev/null and b/.yarn/cache/unicode-property-aliases-ecmascript-npm-2.1.0-46779595f4-2435244318.zip differ diff --git a/.yarn/cache/unified-npm-6.2.0-824644bed4-78c73ccd35.zip b/.yarn/cache/unified-npm-6.2.0-824644bed4-78c73ccd35.zip deleted file mode 100644 index ec1fa7276af0..000000000000 Binary files a/.yarn/cache/unified-npm-6.2.0-824644bed4-78c73ccd35.zip and /dev/null differ diff --git a/.yarn/cache/unified-npm-9.2.2-65676eec78-871bb5fb0c.zip b/.yarn/cache/unified-npm-9.2.2-65676eec78-871bb5fb0c.zip new file mode 100644 index 000000000000..fa9fbf1a05af Binary files /dev/null and b/.yarn/cache/unified-npm-9.2.2-65676eec78-871bb5fb0c.zip differ diff --git a/.yarn/cache/unique-filename-npm-2.0.1-183c6c7c2b-807acf3381.zip b/.yarn/cache/unique-filename-npm-2.0.1-183c6c7c2b-807acf3381.zip deleted file mode 100644 index 1d4f41956f60..000000000000 Binary files a/.yarn/cache/unique-filename-npm-2.0.1-183c6c7c2b-807acf3381.zip and /dev/null differ diff --git a/.yarn/cache/unique-slug-npm-3.0.0-0b82e51577-26fc5bc209.zip b/.yarn/cache/unique-slug-npm-3.0.0-0b82e51577-26fc5bc209.zip deleted file mode 100644 index c734894b29ea..000000000000 Binary files a/.yarn/cache/unique-slug-npm-3.0.0-0b82e51577-26fc5bc209.zip and /dev/null differ diff --git a/.yarn/cache/unist-util-is-npm-4.1.0-16bbd97383-c046cc87c0.zip b/.yarn/cache/unist-util-is-npm-4.1.0-16bbd97383-c046cc87c0.zip new file mode 100644 index 000000000000..2e6eafc22ca7 Binary files /dev/null and b/.yarn/cache/unist-util-is-npm-4.1.0-16bbd97383-c046cc87c0.zip differ diff --git a/.yarn/cache/unist-util-stringify-position-npm-2.0.3-abaa9bf961-affbfd151f.zip b/.yarn/cache/unist-util-stringify-position-npm-2.0.3-abaa9bf961-affbfd151f.zip new file mode 100644 index 000000000000..12a9d1284493 Binary files /dev/null and b/.yarn/cache/unist-util-stringify-position-npm-2.0.3-abaa9bf961-affbfd151f.zip differ diff --git a/.yarn/cache/unist-util-visit-parents-npm-3.1.1-a4bb258148-1b18343d88.zip b/.yarn/cache/unist-util-visit-parents-npm-3.1.1-a4bb258148-1b18343d88.zip new file mode 100644 index 000000000000..7c1171eb98d3 Binary files /dev/null and b/.yarn/cache/unist-util-visit-parents-npm-3.1.1-a4bb258148-1b18343d88.zip differ diff --git a/.yarn/cache/universal-user-agent-npm-6.0.0-b148fb997a-5092bbc80d.zip b/.yarn/cache/universal-user-agent-npm-6.0.0-b148fb997a-5092bbc80d.zip deleted file mode 100644 index 8a41a76f877b..000000000000 Binary files a/.yarn/cache/universal-user-agent-npm-6.0.0-b148fb997a-5092bbc80d.zip and /dev/null differ diff --git a/.yarn/cache/universal-user-agent-npm-6.0.1-0388aac597-fdc8e1ae48.zip b/.yarn/cache/universal-user-agent-npm-6.0.1-0388aac597-fdc8e1ae48.zip new file mode 100644 index 000000000000..363fb28542ab Binary files /dev/null and b/.yarn/cache/universal-user-agent-npm-6.0.1-0388aac597-fdc8e1ae48.zip differ diff --git a/.yarn/cache/universalify-npm-0.2.0-9984e61c10-e86134cb12.zip b/.yarn/cache/universalify-npm-0.2.0-9984e61c10-e86134cb12.zip new file mode 100644 index 000000000000..7f1d80c194d8 Binary files /dev/null and b/.yarn/cache/universalify-npm-0.2.0-9984e61c10-e86134cb12.zip differ diff --git a/.yarn/cache/universalify-npm-1.0.0-eff81409f3-095a808f2b.zip b/.yarn/cache/universalify-npm-1.0.0-eff81409f3-095a808f2b.zip deleted file mode 100644 index 8b929f6b3a67..000000000000 Binary files a/.yarn/cache/universalify-npm-1.0.0-eff81409f3-095a808f2b.zip and /dev/null differ diff --git a/.yarn/cache/universalify-npm-2.0.0-03b8b418a8-2406a4edf4.zip b/.yarn/cache/universalify-npm-2.0.0-03b8b418a8-2406a4edf4.zip deleted file mode 100644 index fa6b36b077ad..000000000000 Binary files a/.yarn/cache/universalify-npm-2.0.0-03b8b418a8-2406a4edf4.zip and /dev/null differ diff --git a/.yarn/cache/universalify-npm-2.0.1-040ba5a21e-ecd8469fe0.zip b/.yarn/cache/universalify-npm-2.0.1-040ba5a21e-ecd8469fe0.zip new file mode 100644 index 000000000000..510873c2656f Binary files /dev/null and b/.yarn/cache/universalify-npm-2.0.1-040ba5a21e-ecd8469fe0.zip differ diff --git a/.yarn/cache/unplugin-npm-1.12.0-113f1c2265-abbc3eeb71.zip b/.yarn/cache/unplugin-npm-1.12.0-113f1c2265-abbc3eeb71.zip new file mode 100644 index 000000000000..2a02bc5d9d3f Binary files /dev/null and b/.yarn/cache/unplugin-npm-1.12.0-113f1c2265-abbc3eeb71.zip differ diff --git a/.yarn/cache/unplugin-npm-1.4.0-4cad140f03-26eec445eb.zip b/.yarn/cache/unplugin-npm-1.4.0-4cad140f03-26eec445eb.zip deleted file mode 100644 index 886a2eb9d9eb..000000000000 Binary files a/.yarn/cache/unplugin-npm-1.4.0-4cad140f03-26eec445eb.zip and /dev/null differ diff --git a/.yarn/cache/unset-value-npm-0.1.2-54f659f6f2-c1a69e7f86.zip b/.yarn/cache/unset-value-npm-0.1.2-54f659f6f2-c1a69e7f86.zip deleted file mode 100644 index 3e298c0d108a..000000000000 Binary files a/.yarn/cache/unset-value-npm-0.1.2-54f659f6f2-c1a69e7f86.zip and /dev/null differ diff --git a/.yarn/cache/untildify-npm-4.0.0-4a8b569825-39ced9c418.zip b/.yarn/cache/untildify-npm-4.0.0-4a8b569825-39ced9c418.zip deleted file mode 100644 index a88f9ac1d5c7..000000000000 Binary files a/.yarn/cache/untildify-npm-4.0.0-4a8b569825-39ced9c418.zip and /dev/null differ diff --git a/.yarn/cache/uri-js-npm-4.2.2-e6ac2fca26-e9499d30bf.zip b/.yarn/cache/uri-js-npm-4.2.2-e6ac2fca26-e9499d30bf.zip deleted file mode 100644 index 30124d3116d9..000000000000 Binary files a/.yarn/cache/uri-js-npm-4.2.2-e6ac2fca26-e9499d30bf.zip and /dev/null differ diff --git a/.yarn/cache/uri-js-npm-4.4.1-66d11cbcaf-b271ca7e3d.zip b/.yarn/cache/uri-js-npm-4.4.1-66d11cbcaf-b271ca7e3d.zip new file mode 100644 index 000000000000..2c446e32d2c6 Binary files /dev/null and b/.yarn/cache/uri-js-npm-4.4.1-66d11cbcaf-b271ca7e3d.zip differ diff --git a/.yarn/cache/url-npm-0.11.1-797427bc52-27131c0e3f.zip b/.yarn/cache/url-npm-0.11.1-797427bc52-27131c0e3f.zip deleted file mode 100644 index a69a593765c1..000000000000 Binary files a/.yarn/cache/url-npm-0.11.1-797427bc52-27131c0e3f.zip and /dev/null differ diff --git a/.yarn/cache/url-npm-0.11.4-706538be7c-e787d070f0.zip b/.yarn/cache/url-npm-0.11.4-706538be7c-e787d070f0.zip new file mode 100644 index 000000000000..5cc01f8b2a92 Binary files /dev/null and b/.yarn/cache/url-npm-0.11.4-706538be7c-e787d070f0.zip differ diff --git a/.yarn/cache/url-parse-npm-1.5.10-64fa2bcd6d-c9e96bc8c5.zip b/.yarn/cache/url-parse-npm-1.5.10-64fa2bcd6d-c9e96bc8c5.zip new file mode 100644 index 000000000000..dc1974f2d518 Binary files /dev/null and b/.yarn/cache/url-parse-npm-1.5.10-64fa2bcd6d-c9e96bc8c5.zip differ diff --git a/.yarn/cache/use-callback-ref-npm-1.3.0-6c0773783f-f9f1b217db.zip b/.yarn/cache/use-callback-ref-npm-1.3.0-6c0773783f-f9f1b217db.zip deleted file mode 100644 index 3ecd166ecf22..000000000000 Binary files a/.yarn/cache/use-callback-ref-npm-1.3.0-6c0773783f-f9f1b217db.zip and /dev/null differ diff --git a/.yarn/cache/use-callback-ref-npm-1.3.2-ba60d2965f-3be76eae71.zip b/.yarn/cache/use-callback-ref-npm-1.3.2-ba60d2965f-3be76eae71.zip new file mode 100644 index 000000000000..60fca38ce3a5 Binary files /dev/null and b/.yarn/cache/use-callback-ref-npm-1.3.2-ba60d2965f-3be76eae71.zip differ diff --git a/.yarn/cache/uuid-npm-10.0.0-4872b46ff8-35aa606148.zip b/.yarn/cache/uuid-npm-10.0.0-4872b46ff8-35aa606148.zip new file mode 100644 index 000000000000..4d30c105af59 Binary files /dev/null and b/.yarn/cache/uuid-npm-10.0.0-4872b46ff8-35aa606148.zip differ diff --git a/.yarn/cache/uuid-npm-9.0.0-46c41e3e43-23857699a6.zip b/.yarn/cache/uuid-npm-9.0.0-46c41e3e43-23857699a6.zip deleted file mode 100644 index 9e232581a009..000000000000 Binary files a/.yarn/cache/uuid-npm-9.0.0-46c41e3e43-23857699a6.zip and /dev/null differ diff --git a/.yarn/cache/uuid-npm-9.0.1-39a8442bc6-9d0b6adb72.zip b/.yarn/cache/uuid-npm-9.0.1-39a8442bc6-9d0b6adb72.zip new file mode 100644 index 000000000000..8fd27d39f86e Binary files /dev/null and b/.yarn/cache/uuid-npm-9.0.1-39a8442bc6-9d0b6adb72.zip differ diff --git a/.yarn/cache/v8-compile-cache-npm-2.3.0-961375f150-7de7423db6.zip b/.yarn/cache/v8-compile-cache-npm-2.3.0-961375f150-7de7423db6.zip deleted file mode 100644 index 280119a96129..000000000000 Binary files a/.yarn/cache/v8-compile-cache-npm-2.3.0-961375f150-7de7423db6.zip and /dev/null differ diff --git a/.yarn/cache/v8-to-istanbul-npm-9.0.0-bd125c4318-0b76ab39d3.zip b/.yarn/cache/v8-to-istanbul-npm-9.0.0-bd125c4318-0b76ab39d3.zip deleted file mode 100644 index 3c22c48d9b33..000000000000 Binary files a/.yarn/cache/v8-to-istanbul-npm-9.0.0-bd125c4318-0b76ab39d3.zip and /dev/null differ diff --git a/.yarn/cache/v8-to-istanbul-npm-9.3.0-35fef658c9-fb1d70f117.zip b/.yarn/cache/v8-to-istanbul-npm-9.3.0-35fef658c9-fb1d70f117.zip new file mode 100644 index 000000000000..9c7106bd699a Binary files /dev/null and b/.yarn/cache/v8-to-istanbul-npm-9.3.0-35fef658c9-fb1d70f117.zip differ diff --git a/.yarn/cache/validate-npm-package-name-npm-3.0.0-e44c263962-6f89bcc91b.zip b/.yarn/cache/validate-npm-package-name-npm-3.0.0-e44c263962-6f89bcc91b.zip deleted file mode 100644 index b8e7c4237634..000000000000 Binary files a/.yarn/cache/validate-npm-package-name-npm-3.0.0-e44c263962-6f89bcc91b.zip and /dev/null differ diff --git a/.yarn/cache/validate-npm-package-name-npm-5.0.0-fc061c1b84-5342a99498.zip b/.yarn/cache/validate-npm-package-name-npm-5.0.0-fc061c1b84-5342a99498.zip deleted file mode 100644 index 7ccf34ce733b..000000000000 Binary files a/.yarn/cache/validate-npm-package-name-npm-5.0.0-fc061c1b84-5342a99498.zip and /dev/null differ diff --git a/.yarn/cache/validate-npm-package-name-npm-5.0.1-5af9a082cd-0d583a1af2.zip b/.yarn/cache/validate-npm-package-name-npm-5.0.1-5af9a082cd-0d583a1af2.zip new file mode 100644 index 000000000000..c550440bf90e Binary files /dev/null and b/.yarn/cache/validate-npm-package-name-npm-5.0.1-5af9a082cd-0d583a1af2.zip differ diff --git a/.yarn/cache/vfile-message-npm-2.0.4-ca3f9b6719-fad3d5a3a1.zip b/.yarn/cache/vfile-message-npm-2.0.4-ca3f9b6719-fad3d5a3a1.zip new file mode 100644 index 000000000000..5fafc4c877db Binary files /dev/null and b/.yarn/cache/vfile-message-npm-2.0.4-ca3f9b6719-fad3d5a3a1.zip differ diff --git a/.yarn/cache/vfile-npm-2.3.0-0781febdcc-e8c0f7e4bb.zip b/.yarn/cache/vfile-npm-2.3.0-0781febdcc-e8c0f7e4bb.zip deleted file mode 100644 index dbfb5a0e4c18..000000000000 Binary files a/.yarn/cache/vfile-npm-2.3.0-0781febdcc-e8c0f7e4bb.zip and /dev/null differ diff --git a/.yarn/cache/vfile-npm-4.2.1-fb052a35e5-f0de0b50df.zip b/.yarn/cache/vfile-npm-4.2.1-fb052a35e5-f0de0b50df.zip new file mode 100644 index 000000000000..81e4790aaa50 Binary files /dev/null and b/.yarn/cache/vfile-npm-4.2.1-fb052a35e5-f0de0b50df.zip differ diff --git a/.yarn/cache/vinyl-npm-2.2.0-b81d0fc829-27c1da8886.zip b/.yarn/cache/vinyl-npm-2.2.0-b81d0fc829-27c1da8886.zip deleted file mode 100644 index ba3e76312a34..000000000000 Binary files a/.yarn/cache/vinyl-npm-2.2.0-b81d0fc829-27c1da8886.zip and /dev/null differ diff --git a/.yarn/cache/vinyl-npm-2.2.1-6b14799ad3-6f7c034381.zip b/.yarn/cache/vinyl-npm-2.2.1-6b14799ad3-6f7c034381.zip new file mode 100644 index 000000000000..84d68a8dd5bd Binary files /dev/null and b/.yarn/cache/vinyl-npm-2.2.1-6b14799ad3-6f7c034381.zip differ diff --git a/.yarn/cache/vite-npm-4.3.9-24f3552941-c2f0b392a2.zip b/.yarn/cache/vite-npm-4.3.9-24f3552941-c2f0b392a2.zip deleted file mode 100644 index 75e6ee4b7d71..000000000000 Binary files a/.yarn/cache/vite-npm-4.3.9-24f3552941-c2f0b392a2.zip and /dev/null differ diff --git a/.yarn/cache/vite-npm-4.5.3-5cedc7cb8f-82efe1bc6d.zip b/.yarn/cache/vite-npm-4.5.3-5cedc7cb8f-82efe1bc6d.zip new file mode 100644 index 000000000000..a470a049f0b6 Binary files /dev/null and b/.yarn/cache/vite-npm-4.5.3-5cedc7cb8f-82efe1bc6d.zip differ diff --git a/.yarn/cache/vite-npm-5.3.5-3cbb728ee4-5672dde4a9.zip b/.yarn/cache/vite-npm-5.3.5-3cbb728ee4-5672dde4a9.zip new file mode 100644 index 000000000000..1cd560bd7607 Binary files /dev/null and b/.yarn/cache/vite-npm-5.3.5-3cbb728ee4-5672dde4a9.zip differ diff --git a/.yarn/cache/vue-npm-2.6.11-e997ef2640-3c9400c828.zip b/.yarn/cache/vue-npm-2.6.11-e997ef2640-3c9400c828.zip deleted file mode 100644 index 8e4f35b2ac16..000000000000 Binary files a/.yarn/cache/vue-npm-2.6.11-e997ef2640-3c9400c828.zip and /dev/null differ diff --git a/.yarn/cache/vue-npm-2.7.16-c163f6852b-0371f7bfaf.zip b/.yarn/cache/vue-npm-2.7.16-c163f6852b-0371f7bfaf.zip new file mode 100644 index 000000000000..8cfc0304773d Binary files /dev/null and b/.yarn/cache/vue-npm-2.7.16-c163f6852b-0371f7bfaf.zip differ diff --git a/.yarn/cache/w3c-xmlserializer-npm-5.0.0-589edd7bff-d78f59e6b4.zip b/.yarn/cache/w3c-xmlserializer-npm-5.0.0-589edd7bff-d78f59e6b4.zip new file mode 100644 index 000000000000..cbd929bcca29 Binary files /dev/null and b/.yarn/cache/w3c-xmlserializer-npm-5.0.0-589edd7bff-d78f59e6b4.zip differ diff --git a/.yarn/cache/web-component-analyzer-npm-2.0.0-5c75e0b280-e58b45c1c2.zip b/.yarn/cache/web-component-analyzer-npm-2.0.0-5c75e0b280-e58b45c1c2.zip new file mode 100644 index 000000000000..3d98426ea958 Binary files /dev/null and b/.yarn/cache/web-component-analyzer-npm-2.0.0-5c75e0b280-e58b45c1c2.zip differ diff --git a/.yarn/cache/webpack-dev-middleware-npm-7.4.1-6727840c35-8be3133374.zip b/.yarn/cache/webpack-dev-middleware-npm-7.4.1-6727840c35-8be3133374.zip deleted file mode 100644 index ecb531af00ef..000000000000 Binary files a/.yarn/cache/webpack-dev-middleware-npm-7.4.1-6727840c35-8be3133374.zip and /dev/null differ diff --git a/.yarn/cache/webpack-dev-middleware-npm-7.4.2-4c13142935-608d101b82.zip b/.yarn/cache/webpack-dev-middleware-npm-7.4.2-4c13142935-608d101b82.zip new file mode 100644 index 000000000000..9a8e18da83dc Binary files /dev/null and b/.yarn/cache/webpack-dev-middleware-npm-7.4.2-4c13142935-608d101b82.zip differ diff --git a/.yarn/cache/webpack-dev-server-npm-5.0.4-8ea5583022-3896866abf.zip b/.yarn/cache/webpack-dev-server-npm-5.0.4-8ea5583022-3896866abf.zip deleted file mode 100644 index 68d497af2936..000000000000 Binary files a/.yarn/cache/webpack-dev-server-npm-5.0.4-8ea5583022-3896866abf.zip and /dev/null differ diff --git a/.yarn/cache/webpack-dev-server-npm-5.1.0-e0775caea7-f23255681c.zip b/.yarn/cache/webpack-dev-server-npm-5.1.0-e0775caea7-f23255681c.zip new file mode 100644 index 000000000000..ffaeba08a7ad Binary files /dev/null and b/.yarn/cache/webpack-dev-server-npm-5.1.0-e0775caea7-f23255681c.zip differ diff --git a/.yarn/cache/webpack-hot-middleware-npm-2.25.1-8fc53b77a6-5917f386d2.zip b/.yarn/cache/webpack-hot-middleware-npm-2.25.1-8fc53b77a6-5917f386d2.zip deleted file mode 100644 index 6a89729f2c98..000000000000 Binary files a/.yarn/cache/webpack-hot-middleware-npm-2.25.1-8fc53b77a6-5917f386d2.zip and /dev/null differ diff --git a/.yarn/cache/webpack-hot-middleware-npm-2.26.1-f02099a337-69fa1a2528.zip b/.yarn/cache/webpack-hot-middleware-npm-2.26.1-f02099a337-69fa1a2528.zip new file mode 100644 index 000000000000..45838d2d887c Binary files /dev/null and b/.yarn/cache/webpack-hot-middleware-npm-2.26.1-f02099a337-69fa1a2528.zip differ diff --git a/.yarn/cache/webpack-virtual-modules-npm-0.5.0-314fd879d0-65a8f90c7e.zip b/.yarn/cache/webpack-virtual-modules-npm-0.5.0-314fd879d0-65a8f90c7e.zip deleted file mode 100644 index ee99bf38a06a..000000000000 Binary files a/.yarn/cache/webpack-virtual-modules-npm-0.5.0-314fd879d0-65a8f90c7e.zip and /dev/null differ diff --git a/.yarn/cache/whatwg-encoding-npm-3.1.1-7dfe21cf7d-bbef815eb6.zip b/.yarn/cache/whatwg-encoding-npm-3.1.1-7dfe21cf7d-bbef815eb6.zip new file mode 100644 index 000000000000..c472698ab3b1 Binary files /dev/null and b/.yarn/cache/whatwg-encoding-npm-3.1.1-7dfe21cf7d-bbef815eb6.zip differ diff --git a/.yarn/cache/whatwg-mimetype-npm-4.0.0-ebb293a688-894a618e2d.zip b/.yarn/cache/whatwg-mimetype-npm-4.0.0-ebb293a688-894a618e2d.zip new file mode 100644 index 000000000000..a3d8c2898e5b Binary files /dev/null and b/.yarn/cache/whatwg-mimetype-npm-4.0.0-ebb293a688-894a618e2d.zip differ diff --git a/.yarn/cache/whatwg-url-npm-14.0.0-fc3d13d5f4-67ea7a359a.zip b/.yarn/cache/whatwg-url-npm-14.0.0-fc3d13d5f4-67ea7a359a.zip new file mode 100644 index 000000000000..2ec66f5864a9 Binary files /dev/null and b/.yarn/cache/whatwg-url-npm-14.0.0-fc3d13d5f4-67ea7a359a.zip differ diff --git a/.yarn/cache/which-builtin-type-npm-1.1.4-23f1df9013-c0cdb9b004.zip b/.yarn/cache/which-builtin-type-npm-1.1.4-23f1df9013-c0cdb9b004.zip new file mode 100644 index 000000000000..88b5ac48b451 Binary files /dev/null and b/.yarn/cache/which-builtin-type-npm-1.1.4-23f1df9013-c0cdb9b004.zip differ diff --git a/.yarn/cache/which-collection-npm-1.0.1-cd2c054585-85c95fcf92.zip b/.yarn/cache/which-collection-npm-1.0.1-cd2c054585-85c95fcf92.zip deleted file mode 100644 index 22f5245b85b2..000000000000 Binary files a/.yarn/cache/which-collection-npm-1.0.1-cd2c054585-85c95fcf92.zip and /dev/null differ diff --git a/.yarn/cache/which-collection-npm-1.0.2-0d6277e921-674bf659b9.zip b/.yarn/cache/which-collection-npm-1.0.2-0d6277e921-674bf659b9.zip new file mode 100644 index 000000000000..19ae6c6cc0f6 Binary files /dev/null and b/.yarn/cache/which-collection-npm-1.0.2-0d6277e921-674bf659b9.zip differ diff --git a/.yarn/cache/which-module-npm-2.0.0-daf3daa08d-e3e46c9c84.zip b/.yarn/cache/which-module-npm-2.0.0-daf3daa08d-e3e46c9c84.zip deleted file mode 100644 index c508eda7cffd..000000000000 Binary files a/.yarn/cache/which-module-npm-2.0.0-daf3daa08d-e3e46c9c84.zip and /dev/null differ diff --git a/.yarn/cache/which-module-npm-2.0.1-90f889f6f6-1967b7ce17.zip b/.yarn/cache/which-module-npm-2.0.1-90f889f6f6-1967b7ce17.zip new file mode 100644 index 000000000000..bdf9a2d4c8d5 Binary files /dev/null and b/.yarn/cache/which-module-npm-2.0.1-90f889f6f6-1967b7ce17.zip differ diff --git a/.yarn/cache/which-npm-3.0.1-b2b0f09ace-adf720fe9d.zip b/.yarn/cache/which-npm-3.0.1-b2b0f09ace-adf720fe9d.zip deleted file mode 100644 index bb7aab33e66b..000000000000 Binary files a/.yarn/cache/which-npm-3.0.1-b2b0f09ace-adf720fe9d.zip and /dev/null differ diff --git a/.yarn/cache/which-npm-4.0.0-dd31cd4928-f17e84c042.zip b/.yarn/cache/which-npm-4.0.0-dd31cd4928-f17e84c042.zip new file mode 100644 index 000000000000..093e6f578f7d Binary files /dev/null and b/.yarn/cache/which-npm-4.0.0-dd31cd4928-f17e84c042.zip differ diff --git a/.yarn/cache/which-typed-array-npm-1.1.15-91410874a2-c3b6a99bea.zip b/.yarn/cache/which-typed-array-npm-1.1.15-91410874a2-c3b6a99bea.zip new file mode 100644 index 000000000000..33eb06866dc0 Binary files /dev/null and b/.yarn/cache/which-typed-array-npm-1.1.15-91410874a2-c3b6a99bea.zip differ diff --git a/.yarn/cache/which-typed-array-npm-1.1.9-9559c95dfc-90ef760a09.zip b/.yarn/cache/which-typed-array-npm-1.1.9-9559c95dfc-90ef760a09.zip deleted file mode 100644 index ef1370d49890..000000000000 Binary files a/.yarn/cache/which-typed-array-npm-1.1.9-9559c95dfc-90ef760a09.zip and /dev/null differ diff --git a/.yarn/cache/wrap-ansi-npm-9.0.0-c35f82c87c-b9d91564c0.zip b/.yarn/cache/wrap-ansi-npm-9.0.0-c35f82c87c-b9d91564c0.zip new file mode 100644 index 000000000000..7345994e524f Binary files /dev/null and b/.yarn/cache/wrap-ansi-npm-9.0.0-c35f82c87c-b9d91564c0.zip differ diff --git a/.yarn/cache/xml-name-validator-npm-5.0.0-0e0ec66944-43f30f3f67.zip b/.yarn/cache/xml-name-validator-npm-5.0.0-0e0ec66944-43f30f3f67.zip new file mode 100644 index 000000000000..20adb5520686 Binary files /dev/null and b/.yarn/cache/xml-name-validator-npm-5.0.0-0e0ec66944-43f30f3f67.zip differ diff --git a/.yarn/cache/y18n-npm-4.0.0-55cd797cc5-c3fabe29b0.zip b/.yarn/cache/y18n-npm-4.0.0-55cd797cc5-c3fabe29b0.zip deleted file mode 100644 index d3c820588880..000000000000 Binary files a/.yarn/cache/y18n-npm-4.0.0-55cd797cc5-c3fabe29b0.zip and /dev/null differ diff --git a/.yarn/cache/y18n-npm-4.0.3-ced95acdbc-392870b2a1.zip b/.yarn/cache/y18n-npm-4.0.3-ced95acdbc-392870b2a1.zip new file mode 100644 index 000000000000..94cd95ba72e6 Binary files /dev/null and b/.yarn/cache/y18n-npm-4.0.3-ced95acdbc-392870b2a1.zip differ diff --git a/.yarn/cache/y18n-npm-5.0.5-1fa41a2023-aa5307f9fe.zip b/.yarn/cache/y18n-npm-5.0.5-1fa41a2023-aa5307f9fe.zip deleted file mode 100644 index 8be9c826cfdb..000000000000 Binary files a/.yarn/cache/y18n-npm-5.0.5-1fa41a2023-aa5307f9fe.zip and /dev/null differ diff --git a/.yarn/cache/y18n-npm-5.0.8-5f3a0a7e62-5f1b5f95e3.zip b/.yarn/cache/y18n-npm-5.0.8-5f3a0a7e62-5f1b5f95e3.zip new file mode 100644 index 000000000000..8237762e5e1b Binary files /dev/null and b/.yarn/cache/y18n-npm-5.0.8-5f3a0a7e62-5f1b5f95e3.zip differ diff --git a/.yarn/cache/yaml-npm-2.3.4-8bb6dc2c0d-f8207ce430.zip b/.yarn/cache/yaml-npm-2.3.4-8bb6dc2c0d-f8207ce430.zip deleted file mode 100644 index e6c7a6708fb9..000000000000 Binary files a/.yarn/cache/yaml-npm-2.3.4-8bb6dc2c0d-f8207ce430.zip and /dev/null differ diff --git a/.yarn/cache/yaml-npm-2.4.5-4752f3d852-b09bf5a615.zip b/.yarn/cache/yaml-npm-2.4.5-4752f3d852-b09bf5a615.zip new file mode 100644 index 000000000000..07fda43b6d6b Binary files /dev/null and b/.yarn/cache/yaml-npm-2.4.5-4752f3d852-b09bf5a615.zip differ diff --git a/.yarn/cache/zip-stream-npm-4.1.0-c77601aed4-4a73da8567.zip b/.yarn/cache/zip-stream-npm-4.1.0-c77601aed4-4a73da8567.zip deleted file mode 100644 index e387a5091ddf..000000000000 Binary files a/.yarn/cache/zip-stream-npm-4.1.0-c77601aed4-4a73da8567.zip and /dev/null differ diff --git a/.yarn/cache/zip-stream-npm-4.1.1-879f54e934-33bd5ee701.zip b/.yarn/cache/zip-stream-npm-4.1.1-879f54e934-33bd5ee701.zip new file mode 100644 index 000000000000..0c6d7d1ee4cc Binary files /dev/null and b/.yarn/cache/zip-stream-npm-4.1.1-879f54e934-33bd5ee701.zip differ diff --git a/.yarn/cache/zwitch-npm-1.0.5-5911cef6ce-28a1bebaca.zip b/.yarn/cache/zwitch-npm-1.0.5-5911cef6ce-28a1bebaca.zip new file mode 100644 index 000000000000..c8115a2e4681 Binary files /dev/null and b/.yarn/cache/zwitch-npm-1.0.5-5911cef6ce-28a1bebaca.zip differ diff --git a/README.md b/README.md index a32c00181328..aa2a1334c044 100644 --- a/README.md +++ b/README.md @@ -86,225 +86,227 @@ check out our [Contributing Guide](/.github/CONTRIBUTING.md) and our - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Taylor Jones

💻 📖 ️️️️♿️

TJ Egan

💻 📖 🚇 👀 ️️️️♿️

Alessandra Davila

💻 📖 👀 ️️️️♿️

Andrea N. Cardona

💻 📖 👀 ️️️️♿️

Francine Lucca

💻 📖 👀 ️️️️♿️

Scott Strubberg

💻 📖 👀 ️️️️♿️

Alison Joseph

💻 📖 👀 ️️️️♿️

Anna Gonzales

🎨 👀

Lauren Rice

🎨 👀

Josh Black

💻 📖 🚇 👀 ️️️️♿️

DAK

💻 📖 👀 ️️️️♿️

Josefina Mancilla

💻 📖 👀 ️️️️♿️

emyarod

💻 📖 👀 ️️️️♿️

Eric Marcoux

💻

Vince Picone

💻 📖 👀 ️️️️♿️

jillianhowarth

🖋 🎨 👀

Ricardo Henriquez

💻 📖 👀 ️️️️♿️

johnbister

🎨 👀

Dominik Brugger

💻 🚧

Jan Hassel

💻 📖 ️️️️♿️ 🎨

Alexander Lyon

💻

Rosie Z

💻

Nishith P

📖

Eric Charpentier

💻

Luiza Mendes

💻 🚧

Akmal Hakimi Mohd Zamri

💻

sanjitbauli

📖

Laszlo Moczo

💻

LMapes

🖋 📖

conradennis

🎨

Eric Liu

💻 📖

Richard Všianský

💻

Lee Chase

💻 📖

Anton

💻

Panpan Lin

📖

Ashley Harrison

💻

Jen Downs

💻 📖 ️️️️♿️

Abdul Rehman

💻

MIchael Dudley

🎨

David Bradshaw

💻

Simon Finney

💻 ️️️️♿️

Attila Bartha

💻

배하람

💻

Yohanna Gadelrab

📖

Akira Sudoh

💻 📖 ️️️️♿️ 🚇

Oyinkan Oyetunmibi

📖

pbenson322

📖

Abbey Hart

💻 📖 ️️️️♿️

Lucas

💻

Dylan Klohr

📖

Gilli Sigurdsson

🎨

kennylam

💻 ️️️️♿️

Sébastien

💻

Dusan Milko

💻

Taras Polovyi

💻

Chris Connors

🎨 📖

David Conner

💻 ️️️️♿️

Harish Mohanani

💻

Frivalszky-Mayer Péter

💻 ️️️️♿️

s100

💻

Taranveer Virk

💻

Niall Cargill

📖

Matt Chapman

💻

Boston Cartwright

💻

DavidSCChen

💻

molyholy

💻

Scott Dickerson

💻

Evgeniy Podgaetskiy

💻

CassidyJensen

💻 ️️️️♿️

Zsolt Lattmann

💻

Conrad Schmidt

💻

Ignacio Becerra

💻

Swapnil Patil

📖

Fei Z

💻

Ignas Ausiejus

📖

Ryan O. Mackey

💻

Dávid Halász

💻

Bill Guigue

💻

szymonbrandys

💻

Adam Alston

📖

Krithika S Udupa

📖

Eshin Griffith

💻

@RianTavaresOn

💻 🎨

ColbyJohnIBM

💻

Håkon

💻 📖

Tanner Summers

💻

Zhen Wang

💻 📖

Cathal Kenneally

💻

Joel Humberto Gómez Paredes

💻

James Nash

💻 📖

Jakub Faliszewski

💻

Nick Gong

💻

Hannele Valtanen

💻

Llam4u

💻 🐛

G. Torres

💻

Fiona

💻

kindoflew

💻

Mario Gueyraud

💻

Dongjoon Lee

💻

ShankarV-CodeJunkie

💻

dario platania

💻

Mateusz Krzyżanowski

💻

jpsorensen

💻

jae kaplan

🚇

Sierra Wetmore

💻

kcprevatt

💻

Marcin Lewandowski

💻

remolueoend

💻

Jesse Hull

💻 ️️️️♿️

Ashvin Warrier

💻

GalvinGao

💻

Bianca Sparxs

💻

Mahmoud Abdulazim

💻

Dave Steinberg

💻

Seong-Hyun Ryoo

💻

Pratik Karad

💻 ️️️️♿️

Gerzon

💻

Guilherme Datilio Ribeiro

💻 📖 ️️️️♿️ 👀

Josef Kubíček

💻

Sunny Johal

💻

Steven Black

💻 ️️️️♿️

Mark Judy

💻

Anton Tsymuk

💻

Mohammed Aslam P. A.

💻 📖

Tony ZL

💻

Petr Kadlec

💻

David Ragsdale

💻

Hao Cheng

💻

cordesmj

💻

Aziz Chebbi

💻

Michał Konopski

💻

Omkar Ajagunde

💻 📖

Aman Lajpal

💻 📖

Niraj Sah

💻

David Padilla

💻

Allison Ishida

💻

Alex Lewitt

💻

Tresau

💻

Daniel Castillo

💻

HaRuki

💻 📖

Matej Ocovsky

💻

SamChinellato

💻

stevenpatrick009

💻

HunterXalc

💻

Onur Özkardeş

💻

Matias Borghi

💻

Alexandr Ovchinnikov

💻

J Thomas

💻

Garrett Dawson

💻 📖

Daniel Adebonojo

📖

Anjana M R

💻

Joseph Schultz

💻

anjaly0606

💻

jesnajoseijk

💻

Jawahar S

💻

Holly Springsteen

💻

Nikhil Tomar

💻

Anina Antony

💻

Ahmed Semih Erkan

💻

Yael Chavoya

💻 📖

Kilian Collender
💻

nandininarayanofficial

💻

Andrea DG

💻

Luis

💻

Luke Harrison

💻

Ahmed Alsinan

💻

Adam Shea

💻

Md Nabeel Ayubee

💻

Patan Amrulla Khan

💻 📖
Taylor Jones
Taylor Jones

💻 📖 ️️️️♿️
TJ Egan
TJ Egan

💻 📖 🚇 👀 ️️️️♿️
Alessandra Davila
Alessandra Davila

💻 📖 👀 ️️️️♿️
Andrea N. Cardona
Andrea N. Cardona

💻 📖 👀 ️️️️♿️
Francine Lucca
Francine Lucca

💻 📖 👀 ️️️️♿️
Scott Strubberg
Scott Strubberg

💻 📖 👀 ️️️️♿️
Alison Joseph
Alison Joseph

💻 📖 👀 ️️️️♿️
Anna Gonzales
Anna Gonzales

🎨 👀
Lauren Rice
Lauren Rice

🎨 👀
Josh Black
Josh Black

💻 📖 🚇 👀 ️️️️♿️
DAK
DAK

💻 📖 👀 ️️️️♿️
Josefina Mancilla
Josefina Mancilla

💻 📖 👀 ️️️️♿️
emyarod
emyarod

💻 📖 👀 ️️️️♿️
Eric Marcoux
Eric Marcoux

💻
Vince Picone
Vince Picone

💻 📖 👀 ️️️️♿️
jillianhowarth
jillianhowarth

🖋 🎨 👀
Ricardo Henriquez
Ricardo Henriquez

💻 📖 👀 ️️️️♿️
johnbister
johnbister

🎨 👀
Dominik Brugger
Dominik Brugger

💻 🚧
Jan Hassel
Jan Hassel

💻 📖 ️️️️♿️ 🎨
Alexander Lyon
Alexander Lyon

💻
Rosie Z
Rosie Z

💻
Nishith P
Nishith P

📖
Eric Charpentier
Eric Charpentier

💻
Luiza Mendes
Luiza Mendes

💻 🚧
Akmal Hakimi Mohd Zamri
Akmal Hakimi Mohd Zamri

💻
sanjitbauli
sanjitbauli

📖
Laszlo Moczo
Laszlo Moczo

💻
LMapes
LMapes

🖋 📖
conradennis
conradennis

🎨
Eric Liu
Eric Liu

💻 📖
Richard Všianský
Richard Všianský

💻
Lee Chase
Lee Chase

💻 📖
Anton
Anton

💻
Panpan Lin
Panpan Lin

📖
Ashley Harrison
Ashley Harrison

💻
Jen Downs
Jen Downs

💻 📖 ️️️️♿️
Abdul Rehman
Abdul Rehman

💻
MIchael Dudley
MIchael Dudley

🎨
David Bradshaw
David Bradshaw

💻
Simon Finney
Simon Finney

💻 ️️️️♿️
Attila Bartha
Attila Bartha

💻
배하람
배하람

💻
Yohanna Gadelrab
Yohanna Gadelrab

📖
Akira Sudoh
Akira Sudoh

💻 📖 ️️️️♿️ 🚇
Oyinkan Oyetunmibi
Oyinkan Oyetunmibi

📖
pbenson322
pbenson322

📖
Abbey Hart
Abbey Hart

💻 📖 ️️️️♿️
Lucas
Lucas

💻
Dylan Klohr
Dylan Klohr

📖
Gilli Sigurdsson
Gilli Sigurdsson

🎨
kennylam
kennylam

💻 ️️️️♿️
Sébastien
Sébastien

💻
Dusan Milko
Dusan Milko

💻
Taras Polovyi
Taras Polovyi

💻
Chris Connors
Chris Connors

🎨 📖
David Conner
David Conner

💻 ️️️️♿️
Harish Mohanani
Harish Mohanani

💻
Frivalszky-Mayer Péter
Frivalszky-Mayer Péter

💻 ️️️️♿️
s100
s100

💻
Taranveer Virk
Taranveer Virk

💻
Niall Cargill
Niall Cargill

📖
Matt Chapman
Matt Chapman

💻
Boston Cartwright
Boston Cartwright

💻
DavidSCChen
DavidSCChen

💻
molyholy
molyholy

💻
Scott Dickerson
Scott Dickerson

💻
Evgeniy Podgaetskiy
Evgeniy Podgaetskiy

💻
CassidyJensen
CassidyJensen

💻 ️️️️♿️
Zsolt Lattmann
Zsolt Lattmann

💻
Conrad Schmidt
Conrad Schmidt

💻
Ignacio Becerra
Ignacio Becerra

💻
Swapnil Patil
Swapnil Patil

📖
Fei Z
Fei Z

💻
Ignas Ausiejus
Ignas Ausiejus

📖
Ryan O. Mackey
Ryan O. Mackey

💻
Dávid Halász
Dávid Halász

💻
Bill Guigue
Bill Guigue

💻
szymonbrandys
szymonbrandys

💻
Adam Alston
Adam Alston

📖
Krithika S Udupa
Krithika S Udupa

📖
Eshin Griffith
Eshin Griffith

💻
@RianTavaresOn
@RianTavaresOn

💻 🎨
ColbyJohnIBM
ColbyJohnIBM

💻
Håkon
Håkon

💻 📖
Tanner Summers
Tanner Summers

💻
Zhen Wang
Zhen Wang

💻 📖
Cathal Kenneally
Cathal Kenneally

💻
Joel Humberto Gómez Paredes
Joel Humberto Gómez Paredes

💻
James Nash
James Nash

💻 📖
Jakub Faliszewski
Jakub Faliszewski

💻
Nick Gong
Nick Gong

💻
Hannele Valtanen
Hannele Valtanen

💻
Llam4u
Llam4u

💻 🐛
G. Torres
G. Torres

💻
Fiona
Fiona

💻
kindoflew
kindoflew

💻
Mario Gueyraud
Mario Gueyraud

💻
Dongjoon Lee
Dongjoon Lee

💻
ShankarV-CodeJunkie
ShankarV-CodeJunkie

💻
dario platania
dario platania

💻
Mateusz Krzyżanowski
Mateusz Krzyżanowski

💻
jpsorensen
jpsorensen

💻
jae kaplan
jae kaplan

🚇
Sierra Wetmore
Sierra Wetmore

💻
kcprevatt
kcprevatt

💻
Marcin Lewandowski
Marcin Lewandowski

💻
remolueoend
remolueoend

💻
Jesse Hull
Jesse Hull

💻 ️️️️♿️
Ashvin Warrier
Ashvin Warrier

💻
GalvinGao
GalvinGao

💻
Bianca Sparxs
Bianca Sparxs

💻
Mahmoud Abdulazim
Mahmoud Abdulazim

💻
Dave Steinberg
Dave Steinberg

💻
Seong-Hyun Ryoo
Seong-Hyun Ryoo

💻
Pratik Karad
Pratik Karad

💻 ️️️️♿️
Gerzon
Gerzon

💻
Guilherme Datilio Ribeiro
Guilherme Datilio Ribeiro

💻 📖 ️️️️♿️ 👀
Josef Kubíček
Josef Kubíček

💻
Sunny Johal
Sunny Johal

💻
Steven Black
Steven Black

💻 ️️️️♿️
Mark Judy
Mark Judy

💻
Anton Tsymuk
Anton Tsymuk

💻
Mohammed Aslam P. A.
Mohammed Aslam P. A.

💻 📖
Tony ZL
Tony ZL

💻
Petr Kadlec
Petr Kadlec

💻
David Ragsdale
David Ragsdale

💻
Hao Cheng
Hao Cheng

💻
cordesmj
cordesmj

💻
Aziz Chebbi
Aziz Chebbi

💻
Michał Konopski
Michał Konopski

💻
Omkar Ajagunde
Omkar Ajagunde

💻 📖
Aman Lajpal
Aman Lajpal

💻 📖
Niraj Sah
Niraj Sah

💻
David Padilla
David Padilla

💻
Allison Ishida
Allison Ishida

💻
Alex Lewitt
Alex Lewitt

💻
Tresau
Tresau

💻
Daniel Castillo
Daniel Castillo

💻
HaRuki
HaRuki

💻 📖
Matej Ocovsky
Matej Ocovsky

💻
SamChinellato
SamChinellato

💻
stevenpatrick009
stevenpatrick009

💻
HunterXalc
HunterXalc

💻
Onur Özkardeş
Onur Özkardeş

💻
Matias Borghi
Matias Borghi

💻
Alexandr Ovchinnikov
Alexandr Ovchinnikov

💻
J Thomas
J Thomas

💻
Garrett Dawson
Garrett Dawson

💻 📖
Daniel Adebonojo
Daniel Adebonojo

📖
Anjana M R
Anjana M R

💻
Joseph Schultz
Joseph Schultz

💻
anjaly0606
anjaly0606

💻
jesnajoseijk
jesnajoseijk

💻
Jawahar S
Jawahar S

💻
Holly Springsteen
Holly Springsteen

💻
Nikhil Tomar
Nikhil Tomar

💻
Anina Antony
Anina Antony

💻
Ahmed Semih Erkan
Ahmed Semih Erkan

💻
Yael Chavoya
Yael Chavoya

💻 📖
Kilian Collender
Kilian Collender
💻
nandininarayanofficial
nandininarayanofficial

💻
Andrea DG
Andrea DG

💻
Luis
Luis

💻
Luke Harrison
Luke Harrison

💻
Ahmed Alsinan
Ahmed Alsinan

💻
Adam Shea
Adam Shea

💻
Md Nabeel Ayubee
Md Nabeel Ayubee

💻
Patan Amrulla Khan
Patan Amrulla Khan

💻 📖
diff --git a/docs/guides/cwc-v2-migration.md b/docs/guides/cwc-v2-migration.md new file mode 100644 index 000000000000..8ab56c6962db --- /dev/null +++ b/docs/guides/cwc-v2-migration.md @@ -0,0 +1,363 @@ +# Carbon Web Components: v2 migration guide + +This document will review in detail the changes in @carbon/web-components v1 to +v2. Because @carbon/web-components v2 uses Carbon v11, which utilizes Sass +modules, there is a requirement for teams to use the +[Dart Sass package](https://sass-lang.com/dart-sass) (`sass`), as opposed to +`node-sass`. This introduces some new sass concepts such as +[`@use`](https://sass-lang.com/documentation/at-rules/use) vs +[`@import`](https://sass-lang.com/documentation/at-rules/import) and +[namespaces](https://sass-lang.com/documentation/at-rules/use#choosing-a-namespace). +For Carbon v11 migration guidance, see their +[migration guide](https://github.com/carbon-design-system/carbon/blob/main/docs/migration/v11.md). + +> When using @carbon/web-components v2 you need to include theming to get all +> the token values necessary for the components. This includes using white +> theme, see the accordion stackblitz example +> [here](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/accordion?file=src%2Fstyles.scss) + +## List of component changes + +| Component | Changes | +| -------------------- | ---------------------------------------- | +| accordion | View changes [here](#accordion) | +| breadcrumb | View changes [here](#breadcrumb) | +| button | View changes [here](#button) | +| checkbox | View changes [here](#checkbox) | +| code-snippet | View changes [here](#code-snippet) | +| combo-box | View changes [here](#combo-box) | +| content-switcher | View changes [here](#content-switcher) | +| copy-button | View changes [here](#copy-button) | +| data-table | View changes [here](#data-table) | +| date-picker | View changes [here](#date-picker) | +| dropdown | View changes [here](#dropdown) | +| file-uploader | View changes [here](#file-uploader) | +| form-group | New component in v2. | +| icon-button | New component in v2. | +| inline-loading | View changes [here](#inline-loading) | +| input | Replaced by `text-input` | +| layer | New component in v2. | +| link | View changes [here](#link) | +| loading | View changes [here](#loading) | +| modal | View changes [here](#modal) | +| multi-select | View changes [here](#multi-select) | +| notification | View changes [here](#notification) | +| number-input | View changes [here](#number-input) | +| ordered-list | No API changes. | +| overflow-menu | View changes [here](#overflow-menu) | +| pagination | View changes [here](#pagination) | +| popover | New component in v2. | +| progress-bar | New component in v2. | +| progress-indicator | View changes [here](#progress-indicator) | +| radio-button | View changes [here](#radio-button) | +| search | View changes [here](#search) | +| select | View changes [here](#select) | +| skeleton-placeholder | No API changes. | +| skeleton-text | View changes [here](#skeleton-text) | +| slider | View changes [here](#slider) | +| stack | New component in v2. | +| structured-list | View changes [here](#structured-list) | +| tabs | View changes [here](#tabs) | +| tag | View changes [here](#tag) | +| textarea | View changes [here](#textarea) | +| text-input | New component in v2. Replaces `input`. | +| tile | View changes [here](#tile) | +| toggle | View changes [here](#toggle) | +| toggletip | New component in v2. | +| tooltip | View changes [here](#tooltip) | +| ui-shell | View changes [here](#ui-shell) | +| unordered-list | No API changes. | + +### accordion + +- New `accordion-skeleton` & `accordion-item-skeleton` components +- `title-text` property replaced with `title` + +### button + +- New `cds-button-set` component +- `danger-primary` new option for `kind` property +- `size` now accepts `xs`, `sm`, `md`, `lg`, and `xl`, instead of `''`, `sm`, + `lg`, `field` +- `tooltip-text` can add a tooltip component that appears on hover +- `tooltip-alignment` and `tooltip-position` can be used to modify the tooltip + +### breadcrumb + +- New `breadcrumb-skeleton` component +- New `no-trailing-slash` property + +### checkbox + +- New `checkbox-skeleton` +- New `readonly` & `title` properties for `checkbox` + +### code-snippet + +- New properties: `copy-text`, `disabled`, `feedback`, `feedback-timeout`, + `hide-copy-button`, `maxCollapsedNumberOfRows`, `maxExpandedNumberOfRows`, + `minCollapsedNumberOfRows`, `minExpandedNumberOfRows`, `show-less-text`, + `show-more-text`, `wrap-text`, `tooltip-content` +- Removed properties: `code-assistive-text`, `collapse-button-text`, + `color-scheme`, `copy-button-assistive-text`, `copy-button-feedback-text`, + `copy-button-feedback-timeout`, `expand-button-text` + +### combo-box + +- `direction` property expects 'top' or 'bottom' value +- `size="md"` is now used instead of `size=""` +- `label-text` is now `title-text` +- `trigger-content` is now `label` +- New attributes: `hide-label`, `invalid`, `invalid-text`, `read-only`, `warn`, + `warn-text` +- Removed `color-scheme` property + +### content-switcher + +- New `icon` property for icon-only variation +- New `align` property for icon tooltips in icon-only variation +- New `close-on-activation` property + +### copy-button + +- `feedback-text` property replaced with `feedback` +- Removed `button-assistive-text` property +- New `class-name` & `disabled` properties + +### data-table + +- New optional `table-head` component +- New and old interactive features/logic are now built-in to the component -- + can still be customizable +- New properties: `batch-expansion`, `collator`, `expandable`, `filterRows`, + `is-selectable`, `is-sortable`, `locale`, `overflow-menu-on-hover`, `radio`, + `use-static-width`, `use-zebra-styles` +- `size` now accepts `xs`, `sm`, `md`, `lg`, and `xl`, instead of `compact`, + `short`, `''`, and `tall` +- `table-toolbar` can now be further customized with extra features +- Removed `color-scheme` in favor of `use-zebra-styles` +- Removed `table-expand-row` in favor of `table-row` with `expandable` attribute +- Removed smaller `skeleton` table components in favor of `cds-table-skeleton` + with `row-count` and `column-count` attributes + +### date-picker + +- New `date-picker-input` properties: `warn`, `warn-text`, `invalid-text`, + `readonly`, `short` +- Removed `date-picker-input` properties: `side-horizontal`, + `required-validity-message` +- New `date-picker` properties: `allow-input`, `close-on-select`, `min-date`, + `max-date`, `readonly` + +### dropdown + +- `direction` property expects 'top' or 'bottom' value +- `size="md"` is now used instead of `size=""` +- `label-text` is now `title-text` +- `trigger-content` is now `label` +- New attributes: `hide-label`, `invalid`, `invalid-text`, `read-only`, `warn`, + `warn-text` +- Removed `color-scheme` property + +### file-uploader + +- `state` now accepts `uploading`, `complete`, & `edit` instead of `uploading`, + `uploaded`, & `editing` +- `size` now accepts `sm`, `md`, `lg`, instead of `''`, `sm`, `lg`, `field` +- New `file-uploader-button` & `file-uploader-skeleton` components +- `file-drop-container` is replaced with `file-uploader-drop-container` with a + new `name` property +- New `file-uploader-item` properties: `icon-desciption`, `error-subject`, + `error-body` +- Removed `file-uploader-item` properties: `uploaded-assitive-text`, + `uploading-assistive-text`, `validity-message` +- New `file-uploader` properties: `disabled`, `label-description`, `label-title` +- Removed `file-uploader` properties: `helper-text`, `label-text` + +### inline-loading + +- New `assistive-text` property + +### link + +- `size` property replaced `REGULAR = ''` with `MEDIUM = 'md'` +- New `inline` & `visited` properties + +### loading + +- New `assistive-text` property + +### modal + +- `

` inside the `modal-body` is replaced with `cds-modal-body-content` +- New attributes: `alert`, `full-width`, `has-scrolling-content`, + `prevent-close`, `prevent-close-on-click-outside` + +### multi-select + +- Removed `color-scheme` property +- `size` property expected values have been changed from '' (default), 'sm' --> + 'sm', 'md' (default) +- New a11y `clear-selection-description` and `clear-selection-text` properties +- New `locale` property to specify locale of the multi-select, used when sorting + the list of items +- New `selection-feedback` property: `'fixed', 'top', 'top-after-reopen'` + options for sorting list items once selection occurs +- New `warn` and `warn-text` properties for warn state + +### notification + +- New `actionable-notification` component that has inline and toast variations +- New `info`, `info-square`, and `warning-alt` values for `kind` property +- `icon-label` property replaced with `status-icon-description` +- `close-button-label` property replaced with `aria-label` + +### number-input + +- Removed `color-scheme` and `mobile` properties +- `size` property expected values have been changed from '' (default), 'sm', + 'xl' --> 'sm', 'md' (default), and 'lg' +- `validity-message-min` and `validity-message-max` properties replaced with + `decrement-button-assistive-text` and `increment-button-assistive-text` + respectively +- `label-text` property replaced with `label` +- New `warn` and `warn-text` properties for warn state +- New `invalid-text` that appears when in invalid state +- New `hide-label` property +- New`allow-empty` property to allow empty string +- New `hide-steppers` property for option to hide increment/decrement steppers + +### overflow-menu + +- `size` now accepts: `sm`, `md`, `lg` instead of `''`, `sm`, `lg` `xl` +- New `overlfow-menu-body` properties: `flipped`, `size` +- Removed `overlfow-menu-body` properties: `alignment`, `color-scheme` +- New `overlfow-menu-item` properties: `divider`, `size` +- New `overlfow-menu` properties: `index` +- Removed `overlfow-menu` properties: `color-scheme` + +### pagination + +- Removed `page-sizes-select` in favor of a `cds-select` component +- Removed `pages-select` component in favor of built-in logic +- `prev-button-text` is now `backward-text` +- `next-button-text` is now `forward-text` +- `at-last-page` is now `is-last-page` +- New properties: `items-per-page-text`, `page-input-disabled`, + `page-size-input-disabled`, `page-size-label-text`, `pages-unkown`, `size`, + `total-items`, `total-pages` + +### progress-indicator + +- New `space-equally` property for `progress-indicator` +- New `description` property for `progress-step` +- New `label` property for `progress-step` +- New `secondary-label` property for `progress-step` + +### radio-button + +- New `radio-button-group` properties: `defaultSelected`, `legend-text`, + `readOnly` +- New `radio-button` properties: `disabledItem`, `readOnly` + +### tooltip + +- `tooltip-body` has been replaced with `tooltip-content +- `tooltip-footer` has been removed +- New `defaultOpen` & `closeOnActivation` properties + +### slider + +- New `required` property to specify if slider is required +- New `readonly` property +- New `max-label` and `min-label` a11y properties +- New `invalid` and `invalid-text` property for invalid state - when input + entered in the text-input is above or lower than given max / min, the invalid + state will be triggered automatically +- New `step-multiplier` property to determine how much the value should increase + / decrease by Shift + arrow keys +- New `warn` and `warn-text` properties for warn state +- New `hide-text-input` property for option to hide text input on side of slider + +### search + +- Removed `color-scheme` property +- `size` property expected values have been changed from '' (default), 'sm', and + 'xl' --> 'sm', 'md' (default), and 'lg' +- Can use custom icon over magnifying glass +- `closeButtonAssistiveText` is now `closeButtonLabelText` +- New properties: `autocomplete`, `expandable`, + +### select + +- Removed `color-scheme` property +- `size` property expected values have been changed from '' (default), 'sm', and + 'xl' --> 'sm', 'md' (default), and 'lg' +- New `inline` property for inline variation +- New `invalid-text` property for invalid state +- New `warn` and `warn-text` properties for warn state +- New `hide-label` property for option to hide label + +### skeleton-text + +- Removed `LINE` type def`and`line`option for`type` property + +### structured-list + +- New `condensed` property for condensed variation +- New `flush` property for flush variation + +### tabs + +- Replaced mobile dropdown style tabs with overflow scrolling tabs at all screen + sizes +- New `CONTAINED` value for `type` property + +### tag + +- Removed `filter-tag` in favor of `filter` attribute + +### textarea + +- Removed `color-scheme` property +- New `max-count` property that limits character count in component +- New `enable-counter` property for option to display character counter +- New `warn` and `warn-text` properties for warn state + +### tile + +- `fieldset` has been replaced with `tile-group` that handles selection logic +- "Single selectable" tiles are now `radio-tile`s +- `expandable-tile` can now include interactable components within + +### toggle + +- `checked-text` is now `label-a` +- `unchecked-text` is now `label-b` +- `size="small"` is now `size="sm"` +- New properties: `hide-checkbox`, `read-only` + +### tooltip + +- tooltip now displays on hover instead of click +- Removed `direction` property +- `alignment` property now has 12 directions to choose from +- `start` alignment is now `bottom-left` +- `center` alignment is now `bottom` +- `end` alignment is now `bottom-right` +- New properties `enter-delay-ms` and `leave-delay-ms` to affect tooltip + open/exit delay on hover + +### ui-shell + +- New `header-global-action`, `header-panel`, `header-side-nav-items`, + `switcher-divider`, `switcher-item`, `switcher` components +- The Header allows for Actions, Switcher, and Right Panel +- New SideNav Rail variation +- New `large` property for `side-nav-menu` and `side-nav-link` components +- `usage-mode` property has been replaced with combination of + `is-not-child-of-header` and `is-not-persistent` properties in `side-nav` +- `header-menu` has new `is-active` property +- `header-nav-item` has new `is-active` and `aria-current` properties +- `header-menu-button` no longer uses `usage-mode` property, replaced by + `is-not-child-of-header` diff --git a/package.json b/package.json index 999a365c208f..5e163eb1d90b 100644 --- a/package.json +++ b/package.json @@ -49,23 +49,23 @@ "@carbon/cli": "workspace:packages/cli", "@commitlint/cli": "^18.0.0", "@commitlint/config-conventional": "^18.0.0", - "@percy/cli": "^1.29.2", - "@percy/playwright": "^1.0.6", - "@playwright/test": "^1.46.1", + "@percy/cli": "^1.27.0", + "@percy/playwright": "^1.0.4", + "@playwright/test": "^1.36.2", "@testing-library/dom": "^10.1.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^16.0.0", "@testing-library/user-event": "^14.4.3", "@types/react-is": "~18.3.0", - "accessibility-checker": "^3.1.74", + "accessibility-checker": "^3.1.48", "all-contributors-cli": "^6.19.0", "cross-env": "^7.0.0", "cross-spawn": "^7.0.0", "doctoc": "^2.0.0", "eslint": "^9.0.0", - "eslint-plugin-playwright": "^1.6.2", + "eslint-plugin-playwright": "^1.0.0", "fs-extra": "^11.0.0", - "glob": "^11.0.0", + "glob": "^10.0.0", "husky": "^9.0.0", "jest": "^28.1.0", "jest-junit": "^16.0.0", @@ -74,7 +74,7 @@ "prettier": "^2.8.8", "react": "^18.2.0", "react-dom": "^18.2.0", - "rimraf": "^6.0.0", + "rimraf": "^5.0.0", "stylelint": "^15.0.0" }, "commitlint": { diff --git a/packages/styles/scss/components/accordion/_accordion.scss b/packages/styles/scss/components/accordion/_accordion.scss index 94ef8afbf166..095fe07ae17b 100644 --- a/packages/styles/scss/components/accordion/_accordion.scss +++ b/packages/styles/scss/components/accordion/_accordion.scss @@ -375,8 +375,7 @@ $content-padding: 0 0 0 $spacing-05 !default; // RTL overrides [dir='rtl'] .#{$prefix}--accordion--start .#{$prefix}--accordion__heading { - padding-inline-end: 0; - padding-inline-start: layout.density('padding-inline'); + padding-inline: layout.density('padding-inline') 0; } [dir='rtl'] .#{$prefix}--accordion--start .#{$prefix}--accordion__title { diff --git a/packages/styles/scss/components/breadcrumb/_breadcrumb.scss b/packages/styles/scss/components/breadcrumb/_breadcrumb.scss index 4c56850d1bba..30378039579d 100644 --- a/packages/styles/scss/components/breadcrumb/_breadcrumb.scss +++ b/packages/styles/scss/components/breadcrumb/_breadcrumb.scss @@ -163,7 +163,6 @@ .#{$prefix}--breadcrumb .#{$prefix}--overflow-menu.#{$prefix}--btn--icon-only { min-block-size: 1.125rem; - padding-inline-end: 0; - padding-inline-start: 0; + padding-inline: 0 0; } } diff --git a/packages/styles/scss/components/button/_mixins.scss b/packages/styles/scss/components/button/_mixins.scss index c93415759088..638ed292a53e 100644 --- a/packages/styles/scss/components/button/_mixins.scss +++ b/packages/styles/scss/components/button/_mixins.scss @@ -61,13 +61,11 @@ $button-focus-color: custom-property.get-var('button-focus-color', $focus); calc((layout.size('height') - var(--temp-1lh)) / 2 - convert.to-rem(1px)), var(--temp-padding-block-max) ); - padding-inline-end: calc( - layout.density('padding-inline') * 3 + convert.to-rem(16px) - - convert.to-rem(1px) - ); - padding-inline-start: calc( - layout.density('padding-inline') - convert.to-rem(1px) - ); + padding-inline: calc(layout.density('padding-inline') - convert.to-rem(1px)) + calc( + layout.density('padding-inline') * 3 + convert.to-rem(16px) - + convert.to-rem(1px) + ); text-align: start; text-decoration: none; transition: background $duration-fast-01 motion(entrance, productive), @@ -146,6 +144,5 @@ $button-focus-color: custom-property.get-var('button-focus-color', $focus); @mixin button-padding-large { align-items: baseline; padding-block-start: $spacing-05; - padding-inline-end: $spacing-10; - padding-inline-start: $spacing-05; + padding-inline: $spacing-05 $spacing-10; } diff --git a/packages/styles/scss/components/code-snippet/_code-snippet.scss b/packages/styles/scss/components/code-snippet/_code-snippet.scss index 2e859d7208d5..70b0715458cd 100644 --- a/packages/styles/scss/components/code-snippet/_code-snippet.scss +++ b/packages/styles/scss/components/code-snippet/_code-snippet.scss @@ -416,8 +416,7 @@ $copy-btn-feedback: $background-inverse !default; .#{$prefix}--snippet-button .#{$prefix}--btn--copy__feedback { // (The height of button) + (The height of the tooltip's triangle) + 4px inset-block-start: convert.to-rem(50.8px); - inset-inline-end: auto; - inset-inline-start: 50%; + inset-inline: 50% auto; &::before { inset-block-start: 0; @@ -439,8 +438,7 @@ $copy-btn-feedback: $background-inverse !default; // TODO: use updated global tooltip mixins under the hood // since all of the positioning values for the copy button tooltip are arbitrary hard coded rem values, we need this arbitrary 4px offset to keep the proper tooltip spacing according to the spec inset-block-start: calc(100% - #{convert.to-rem(4px)}); - inset-inline-end: auto; - inset-inline-start: 50%; + inset-inline: 50% auto; } // Overflow Indicator diff --git a/packages/styles/scss/components/contained-list/_contained-list.scss b/packages/styles/scss/components/contained-list/_contained-list.scss index 737268808b81..3c864af35c89 100644 --- a/packages/styles/scss/components/contained-list/_contained-list.scss +++ b/packages/styles/scss/components/contained-list/_contained-list.scss @@ -198,14 +198,13 @@ block-size: 1px; content: ''; inset-block-end: 0; - inset-inline-end: 0; - inset-inline-start: 0; + inset-inline: 0 0; } .#{$prefix}--contained-list--inset-rulers .#{$prefix}--contained-list-item:not(:last-of-type)::before { - inset-inline-end: layout.density('padding-inline'); - inset-inline-start: layout.density('padding-inline'); + inset-inline: layout.density('padding-inline') + layout.density('padding-inline'); } .#{$prefix}--contained-list-item--clickable @@ -249,8 +248,7 @@ display: flex; justify-content: flex-end; inset-block-start: 0; - inset-inline-end: 0; - inset-inline-start: 0; + inset-inline: 0 0; pointer-events: none; } diff --git a/packages/styles/scss/components/content-switcher/_content-switcher.scss b/packages/styles/scss/components/content-switcher/_content-switcher.scss index a20ec0ba189d..1f1f3fb9a20f 100644 --- a/packages/styles/scss/components/content-switcher/_content-switcher.scss +++ b/packages/styles/scss/components/content-switcher/_content-switcher.scss @@ -277,8 +277,7 @@ .#{$prefix}--content-switcher--lg .#{$prefix}--content-switcher-btn { // accounts for the larger icon sizes to keep the switcher at 48px - padding-inline-end: convert.to-rem(14px); - padding-inline-start: convert.to-rem(14px); + padding-inline: convert.to-rem(14px) convert.to-rem(14px); } .#{$prefix}--content-switcher--lg .#{$prefix}--content-switcher-btn svg { diff --git a/packages/styles/scss/components/data-table/_data-table.scss b/packages/styles/scss/components/data-table/_data-table.scss index 2ef9d7521d9b..08f3a68d14b8 100644 --- a/packages/styles/scss/components/data-table/_data-table.scss +++ b/packages/styles/scss/components/data-table/_data-table.scss @@ -49,8 +49,7 @@ //---------------------------------------------------------------------------- .#{$prefix}--data-table-header { background-color: $layer; - padding-block-end: $spacing-06; - padding-block-start: $spacing-05; + padding-block: $spacing-05 $spacing-06; padding-inline: $spacing-05; } @@ -143,8 +142,7 @@ &.#{$prefix}--data-table--lg tr:not([data-child-row]) td:not(.#{$prefix}--table-expand) { - padding-block-end: $spacing-05; - padding-block-start: $spacing-05; + padding-block: $spacing-05 $spacing-05; &.#{$prefix}--table-column-menu { padding-block-start: $spacing-03; @@ -163,8 +161,7 @@ .#{$prefix}--data-table.#{$prefix}--data-table--top-aligned-header { &.#{$prefix}--data-table--lg th:not(.#{$prefix}--table-expand):not(.#{$prefix}--table-sort__header) { - padding-block-end: $spacing-05; - padding-block-start: $spacing-05; + padding-block: $spacing-05 $spacing-05; &.#{$prefix}--table-column-menu { padding-block-start: $spacing-03; @@ -193,8 +190,7 @@ .#{$prefix}--data-table th { background-color: $layer-accent; color: $text-primary; - padding-inline-end: $spacing-05; - padding-inline-start: $spacing-05; + padding-inline: $spacing-05 $spacing-05; } .#{$prefix}--data-table th:last-of-type { @@ -212,8 +208,7 @@ border-block-end: 1px solid $border-subtle; border-block-start: 1px solid $layer; color: $text-secondary; - padding-inline-end: $spacing-05; - padding-inline-start: $spacing-05; + padding-inline: $spacing-05 $spacing-05; + td:first-of-type { padding-inline-start: $spacing-04; @@ -324,8 +319,7 @@ .#{$prefix}--data-table--xs td.#{$prefix}--table-column-menu, .#{$prefix}--data-table--sm td.#{$prefix}--table-column-menu { block-size: convert.to-rem(24px); - padding-block-end: 0; - padding-block-start: 0; + padding-block: 0 0; } .#{$prefix}--data-table--sm td.#{$prefix}--table-column-menu { @@ -418,8 +412,7 @@ .#{$prefix}--data-table tbody td.#{$prefix}--table-column-checkbox { min-inline-size: 2.5rem; // spacing between checkbox / chevron and next cell should be 8px / 0.5rem - padding-inline-end: convert.to-rem(4px); - padding-inline-start: 1rem; + padding-inline: 1rem convert.to-rem(4px); } .#{$prefix}--data-table thead th.#{$prefix}--table-expand, @@ -453,8 +446,7 @@ .#{$prefix}--data-table--xl thead th.#{$prefix}--table-expand, .#{$prefix}--data-table--xl tbody td.#{$prefix}--table-expand { block-size: convert.to-rem(64px); - padding-block-end: convert.to-rem(22px); - padding-block-start: convert.to-rem(10px); + padding-block: convert.to-rem(10px) convert.to-rem(22px); } .#{$prefix}--data-table--xl .#{$prefix}--table-column-checkbox { @@ -570,14 +562,12 @@ } .#{$prefix}--data-table--xs .#{$prefix}--table-header-label { - padding-block-end: convert.to-rem(2px); - padding-block-start: convert.to-rem(2px); + padding-block: convert.to-rem(2px) convert.to-rem(2px); } .#{$prefix}--data-table--xs td, .#{$prefix}--data-table--xs tbody tr th { - padding-block-end: convert.to-rem(2px); - padding-block-start: convert.to-rem(2px); + padding-block: convert.to-rem(2px) convert.to-rem(2px); } .#{$prefix}--data-table--xs .#{$prefix}--overflow-menu { @@ -593,8 +583,7 @@ .#{$prefix}--data-table--top-aligned-header ) th.#{$prefix}--table-column-checkbox { - padding-block-end: 0; - padding-block-start: 0; + padding-block: 0 0; } .#{$prefix}--data-table.#{$prefix}--data-table--xs @@ -615,16 +604,14 @@ } .#{$prefix}--data-table--sm .#{$prefix}--table-header-label { - padding-block-end: convert.to-rem(7px); - padding-block-start: convert.to-rem(7px); + padding-block: convert.to-rem(7px) convert.to-rem(7px); } .#{$prefix}--data-table--sm td, .#{$prefix}--data-table--sm tbody tr th, .#{$prefix}--data-table--sm.#{$prefix}--data-table--top-aligned-header th.#{$prefix}--table-column-checkbox { - padding-block-end: convert.to-rem(6px); - padding-block-start: convert.to-rem(7px); + padding-block: convert.to-rem(7px) convert.to-rem(6px); } .#{$prefix}--data-table.#{$prefix}--data-table--sm:not( @@ -635,8 +622,7 @@ .#{$prefix}--data-table--top-aligned-header ) th.#{$prefix}--table-column-checkbox { - padding-block-end: convert.to-rem(3px); - padding-block-start: convert.to-rem(3px); + padding-block: convert.to-rem(3px) convert.to-rem(3px); } .#{$prefix}--data-table--sm .#{$prefix}--overflow-menu { @@ -655,14 +641,12 @@ .#{$prefix}--data-table--md .#{$prefix}--table-header-label, .#{$prefix}--data-table--md.#{$prefix}--data-table--top-aligned-header th.#{$prefix}--table-column-checkbox { - padding-block-end: convert.to-rem(7px); - padding-block-start: convert.to-rem(7px); + padding-block: convert.to-rem(7px) convert.to-rem(7px); } .#{$prefix}--data-table--md td, .#{$prefix}--data-table--md tbody tr th { - padding-block-end: convert.to-rem(6px); - padding-block-start: convert.to-rem(7px); + padding-block: convert.to-rem(7px) convert.to-rem(6px); } .#{$prefix}--data-table.#{$prefix}--data-table--md:not( @@ -673,13 +657,11 @@ .#{$prefix}--data-table--top-aligned-header ) th.#{$prefix}--table-column-checkbox { - padding-block-end: convert.to-rem(3px); - padding-block-start: convert.to-rem(3px); + padding-block: convert.to-rem(3px) convert.to-rem(3px); } .#{$prefix}--data-table--md .#{$prefix}--table-column-menu { - padding-block-end: convert.to-rem(3px); - padding-block-start: convert.to-rem(3px); + padding-block: convert.to-rem(3px) convert.to-rem(3px); } //---------------------------------------------------------------------------- @@ -692,14 +674,12 @@ } .#{$prefix}--data-table--xl .#{$prefix}--table-header-label { - padding-block-end: $spacing-05; - padding-block-start: $spacing-05; + padding-block: $spacing-05 $spacing-05; } .#{$prefix}--data-table--xl td, .#{$prefix}--data-table--xl tbody tr th { - padding-block-end: $spacing-05; - padding-block-start: $spacing-05; + padding-block: $spacing-05 $spacing-05; } .#{$prefix}--data-table--xl th, @@ -900,19 +880,16 @@ max-inline-size: calc(100% - 10px); overflow-y: hidden; - padding-block-end: 1rem; + padding-block: convert.to-rem(15px) 1rem; // Needed to reduce 1px jump when toggling between variations - padding-block-start: convert.to-rem(15px); } &.#{$prefix}--data-table--xs th .#{$prefix}--table-header-label { - padding-block-end: 0; - padding-block-start: convert.to-rem(3px); + padding-block: convert.to-rem(3px) 0; } &.#{$prefix}--data-table--sm th .#{$prefix}--table-header-label { - padding-block-end: 0; - padding-block-start: convert.to-rem(8px); + padding-block: convert.to-rem(8px) 0; } &.#{$prefix}--data-table--xl th .#{$prefix}--table-header-label { diff --git a/packages/styles/scss/components/data-table/action/_data-table-action.scss b/packages/styles/scss/components/data-table/action/_data-table-action.scss index 9e43cef18818..87696f8b79f5 100644 --- a/packages/styles/scss/components/data-table/action/_data-table-action.scss +++ b/packages/styles/scss/components/data-table/action/_data-table-action.scss @@ -396,8 +396,7 @@ background-color: $background-brand; clip-path: polygon(0 0, 100% 0, 100% 0, 0 0); inset-block-end: 0; - inset-inline-end: 0; - inset-inline-start: 0; + inset-inline: 0 0; opacity: 0; pointer-events: none; transform: translate3d(0, 48px, 0); @@ -428,8 +427,7 @@ .#{$prefix}--action-list .#{$prefix}--btn, .#{$prefix}--batch-summary .#{$prefix}--btn { color: $text-on-color; - padding-inline-end: $spacing-05; - padding-inline-start: $spacing-05; + padding-inline: $spacing-05 $spacing-05; white-space: nowrap; } @@ -648,8 +646,7 @@ .#{$prefix}--table-toolbar--sm .#{$prefix}--btn--primary { block-size: convert.to-rem(32px); min-block-size: auto; - padding-block-end: 0.375rem; - padding-block-start: 0.375rem; + padding-block: 0.375rem 0.375rem; } .#{$prefix}--table-toolbar--sm diff --git a/packages/styles/scss/components/data-table/expandable/_data-table-expandable.scss b/packages/styles/scss/components/data-table/expandable/_data-table-expandable.scss index 661bee49e262..f42f73daa1fc 100644 --- a/packages/styles/scss/components/data-table/expandable/_data-table-expandable.scss +++ b/packages/styles/scss/components/data-table/expandable/_data-table-expandable.scss @@ -49,8 +49,7 @@ td { border: 0; background-color: $layer-hover; - padding-block-end: 0; - padding-block-start: 0; + padding-block: 0 0; transition: padding $duration-moderate-01 motion(standard, productive), background-color $duration-fast-01 motion(standard, productive); } @@ -199,8 +198,7 @@ .#{$prefix}--data-table td.#{$prefix}--table-expand + .#{$prefix}--table-column-checkbox { - padding-inline-end: convert.to-rem(6px); - padding-inline-start: convert.to-rem(6px); + padding-inline: convert.to-rem(6px) convert.to-rem(6px); } // Hide bottom border of checkbox column when expanded diff --git a/packages/styles/scss/components/data-table/sort/_data-table-sort.scss b/packages/styles/scss/components/data-table/sort/_data-table-sort.scss index 0b6e4a190138..fc9d0c877584 100644 --- a/packages/styles/scss/components/data-table/sort/_data-table-sort.scss +++ b/packages/styles/scss/components/data-table/sort/_data-table-sort.scss @@ -74,8 +74,7 @@ th > .#{$prefix}--table-header-label { line-height: 1; - padding-inline-end: $spacing-05; - padding-inline-start: $spacing-05; + padding-inline: $spacing-05 $spacing-05; } // ------------------------------------- @@ -107,20 +106,17 @@ th.#{$prefix}--table-sort__header .#{$prefix}--table-sort__flex .#{$prefix}--table-header-label { - padding-block-end: 0; - padding-block-start: 0; + padding-block: 0 0; } .#{$prefix}--data-table.#{$prefix}--data-table--top-aligned-header.#{$prefix}--data-table--sm th.#{$prefix}--table-sort__header { - padding-block-end: convert.to-rem(7px); - padding-block-start: convert.to-rem(7px); + padding-block: convert.to-rem(7px) convert.to-rem(7px); } .#{$prefix}--data-table.#{$prefix}--data-table--top-aligned-header.#{$prefix}--data-table--xs th.#{$prefix}--table-sort__header { - padding-block-end: convert.to-rem(2px); - padding-block-start: convert.to-rem(2px); + padding-block: convert.to-rem(2px) convert.to-rem(2px); } .#{$prefix}--data-table--sort:not(.#{$prefix}--data-table--xs):not( @@ -176,8 +172,7 @@ .#{$prefix}--table-sort__icon-unsorted { fill: $icon-primary; inline-size: convert.to-rem(20px); - margin-inline-end: $spacing-03; - margin-inline-start: $spacing-03; + margin-inline: $spacing-03 $spacing-03; min-inline-size: $spacing-05; opacity: 0; } @@ -205,8 +200,7 @@ .#{$prefix}--table-sort__icon { fill: $icon-primary; inline-size: convert.to-rem(20px); - margin-inline-end: $spacing-03; - margin-inline-start: $spacing-03; + margin-inline: $spacing-03 $spacing-03; min-inline-size: $spacing-05; opacity: 1; transform: rotate(0); @@ -251,8 +245,7 @@ // Slug styles .#{$prefix}--table-sort__header--slug .#{$prefix}--table-sort__icon, .#{$prefix}--table-sort__header--slug .#{$prefix}--table-sort__icon-unsorted { - margin-inline-end: convert.to-rem(8px); - margin-inline-start: auto; + margin-inline: auto convert.to-rem(8px); } .#{$prefix}--table-sort__header--slug .#{$prefix}--slug { diff --git a/packages/styles/scss/components/date-picker/_flatpickr.scss b/packages/styles/scss/components/date-picker/_flatpickr.scss index 2e326a389739..dd6942545179 100644 --- a/packages/styles/scss/components/date-picker/_flatpickr.scss +++ b/packages/styles/scss/components/date-picker/_flatpickr.scss @@ -265,8 +265,7 @@ } .flatpickr-current-month .cur-month { - margin-inline-end: $spacing-02; - margin-inline-start: $spacing-02; + margin-inline: $spacing-02 $spacing-02; &:hover { background-color: $layer-hover; diff --git a/packages/styles/scss/components/dropdown/_dropdown.scss b/packages/styles/scss/components/dropdown/_dropdown.scss index b10acdcd364b..66fd62d7807a 100644 --- a/packages/styles/scss/components/dropdown/_dropdown.scss +++ b/packages/styles/scss/components/dropdown/_dropdown.scss @@ -178,8 +178,7 @@ // Account for the border in `.cds--dropdown` block-size: calc(100% + 1px); // 2rem + SVG width - padding-inline-end: convert.to-rem(42px); - padding-inline-start: $spacing-05; + padding-inline: $spacing-05 convert.to-rem(42px); text-overflow: ellipsis; white-space: nowrap; } @@ -193,14 +192,13 @@ position: absolute; z-index: z('dropdown'); display: flex; + // NOTE: IE, Edge, and Safari do not support two value `overflow` shorthand. + overflow: hidden auto; flex-direction: column; background-color: $layer; inline-size: 100%; list-style: none; max-block-size: 0; - // NOTE: IE, Edge, and Safari do not support two value `overflow` shorthand. - overflow-x: hidden; - overflow-y: auto; transition: max-height $duration-fast-02 motion(standard, productive); } @@ -273,8 +271,7 @@ .#{$prefix}--dropdown--sm .#{$prefix}--dropdown-link { block-size: convert.to-rem(32px); - padding-block-end: convert.to-rem(7px); - padding-block-start: convert.to-rem(7px); + padding-block: convert.to-rem(7px) convert.to-rem(7px); } .#{$prefix}--dropdown--focused, diff --git a/packages/styles/scss/components/fluid-combo-box/_fluid-combo-box.scss b/packages/styles/scss/components/fluid-combo-box/_fluid-combo-box.scss index 0532dcb1ee9c..43d919b399a9 100644 --- a/packages/styles/scss/components/fluid-combo-box/_fluid-combo-box.scss +++ b/packages/styles/scss/components/fluid-combo-box/_fluid-combo-box.scss @@ -49,8 +49,7 @@ .#{$prefix}--list-box__wrapper--fluid .#{$prefix}--combo-box .#{$prefix}--list-box__selection { - inset-block-end: convert.to-rem(10px); - inset-block-start: auto; + inset-block: auto convert.to-rem(10px); transform: none; } diff --git a/packages/styles/scss/components/fluid-date-picker/_fluid-date-picker.scss b/packages/styles/scss/components/fluid-date-picker/_fluid-date-picker.scss index a8155ea4761c..e04c18026627 100644 --- a/packages/styles/scss/components/fluid-date-picker/_fluid-date-picker.scss +++ b/packages/styles/scss/components/fluid-date-picker/_fluid-date-picker.scss @@ -348,8 +348,7 @@ .#{$prefix}--date-picker--fluid__skeleton--container .#{$prefix}--date-picker__icon { - inset-block-end: $spacing-03; - inset-block-start: auto; + inset-block: auto $spacing-03; } // Range skeleton diff --git a/packages/styles/scss/components/fluid-list-box/_fluid-list-box.scss b/packages/styles/scss/components/fluid-list-box/_fluid-list-box.scss index ec2560c67b9f..aa67a0be4168 100644 --- a/packages/styles/scss/components/fluid-list-box/_fluid-list-box.scss +++ b/packages/styles/scss/components/fluid-list-box/_fluid-list-box.scss @@ -61,8 +61,7 @@ } .#{$prefix}--list-box__wrapper--fluid .#{$prefix}--list-box__field { - padding-block-end: convert.to-rem(13px); - padding-block-start: convert.to-rem(33px); + padding-block: convert.to-rem(33px) convert.to-rem(13px); padding-inline-start: $spacing-05; } diff --git a/packages/styles/scss/components/list-box/_list-box.scss b/packages/styles/scss/components/list-box/_list-box.scss index 25dc3b2e10e8..2cfb06a5875e 100644 --- a/packages/styles/scss/components/list-box/_list-box.scss +++ b/packages/styles/scss/components/list-box/_list-box.scss @@ -313,8 +313,7 @@ $list-box-menu-width: convert.to-rem(300px); cursor: pointer; outline: none; padding-block: 0; - padding-inline-end: $spacing-09; - padding-inline-start: $spacing-05; + padding-inline: $spacing-05 $spacing-09; text-overflow: ellipsis; vertical-align: top; white-space: nowrap; @@ -516,8 +515,7 @@ $list-box-menu-width: convert.to-rem(300px); display: none; background-color: $layer; inline-size: $list-box-width; - inset-inline-end: 0; - inset-inline-start: 0; + inset-inline: 0 0; overflow-y: auto; transition: max-height $duration-fast-02 motion(standard, productive); @@ -691,14 +689,12 @@ $list-box-menu-width: convert.to-rem(300px); .#{$prefix}--list-box--sm .#{$prefix}--list-box__menu-item__option { block-size: convert.to-rem(32px); - padding-block-end: convert.to-rem(7px); - padding-block-start: convert.to-rem(7px); + padding-block: convert.to-rem(7px) convert.to-rem(7px); } .#{$prefix}--list-box--lg .#{$prefix}--list-box__menu-item__option { block-size: convert.to-rem(48px); - padding-block-end: convert.to-rem(15px); - padding-block-start: convert.to-rem(15px); + padding-block: convert.to-rem(15px) convert.to-rem(15px); } .#{$prefix}--list-box--disabled @@ -770,8 +766,7 @@ $list-box-menu-width: convert.to-rem(300px); &:focus { margin: 0; - padding-inline-end: $spacing-03; - padding-inline-start: $spacing-03; + padding-inline: $spacing-03 $spacing-03; } } diff --git a/packages/styles/scss/components/modal/_modal.scss b/packages/styles/scss/components/modal/_modal.scss index 7265a53c8d67..7525b6542cff 100644 --- a/packages/styles/scss/components/modal/_modal.scss +++ b/packages/styles/scss/components/modal/_modal.scss @@ -113,12 +113,10 @@ grid-column: 1/-1; grid-row: 2/-2; overflow-y: auto; - padding-block-end: $spacing-09; + padding-block: $spacing-03 $spacing-09; // Required to accommodate focus outline's negative offset: - padding-block-start: $spacing-03; // anything besides text/p spans full width, with just 16px padding - padding-inline-end: $spacing-05; - padding-inline-start: $spacing-05; + padding-inline: $spacing-05 $spacing-05; &:focus { @include focus-outline('outline'); @@ -127,8 +125,7 @@ // fluid form in modal .#{$prefix}--modal-content .#{$prefix}--form--fluid { - margin-inline-end: -$spacing-05; - margin-inline-start: -$spacing-05; + margin-inline: -$spacing-05 -$spacing-05; } //TO-DO: remove .#{$prefix}--modal-content__regular-content in v11 since hasForm has been deprecated @@ -154,8 +151,7 @@ grid-row: 1/1; margin-block-end: $spacing-03; padding-block-start: $spacing-05; - padding-inline-end: $spacing-09; - padding-inline-start: $spacing-05; + padding-inline: $spacing-05 $spacing-09; } .#{$prefix}--modal-header__label { @@ -299,8 +295,7 @@ margin: 0; block-size: convert.to-rem(64px); max-inline-size: none; - padding-block-end: $spacing-07; - padding-block-start: calc($spacing-05 - convert.to-rem(2px)); + padding-block: calc($spacing-05 - convert.to-rem(2px)) $spacing-07; } .#{$prefix}--modal-footer--three-button .#{$prefix}--btn { diff --git a/packages/styles/scss/components/notification/_actionable-notification.scss b/packages/styles/scss/components/notification/_actionable-notification.scss index c3569fe4f68b..13134786cccb 100644 --- a/packages/styles/scss/components/notification/_actionable-notification.scss +++ b/packages/styles/scss/components/notification/_actionable-notification.scss @@ -336,8 +336,7 @@ margin-inline-start: calc( #{$spacing-07} + #{convert.to-rem(20px)} - #{convert.to-rem(2px)} ); - padding-inline-end: $spacing-05; - padding-inline-start: $spacing-05; + padding-inline: $spacing-05; } // Tertiary button styles by default use mostly "inverse" tokens. Since the non-low-contrast notification diff --git a/packages/styles/scss/components/number-input/_number-input.scss b/packages/styles/scss/components/number-input/_number-input.scss index 9003eb54f9e7..5a1010f386b8 100644 --- a/packages/styles/scss/components/number-input/_number-input.scss +++ b/packages/styles/scss/components/number-input/_number-input.scss @@ -59,8 +59,7 @@ font-weight: 400; inline-size: 100%; min-inline-size: 9.375rem; - padding-inline-end: $spacing-12; - padding-inline-start: $spacing-05; + padding-inline: $spacing-05 $spacing-12; transition: background-color $duration-fast-01 motion(standard, productive), outline $duration-fast-01 motion(standard, productive); diff --git a/packages/styles/scss/components/overflow-menu/_overflow-menu.scss b/packages/styles/scss/components/overflow-menu/_overflow-menu.scss index 515b23cc3c2a..30c5868b8686 100644 --- a/packages/styles/scss/components/overflow-menu/_overflow-menu.scss +++ b/packages/styles/scss/components/overflow-menu/_overflow-menu.scss @@ -202,14 +202,12 @@ .#{$prefix}--overflow-menu--flip.#{$prefix}--overflow-menu-options[data-floating-menu-direction='top']::after, .#{$prefix}--overflow-menu--flip.#{$prefix}--overflow-menu-options[data-floating-menu-direction='bottom']::after { - inset-inline-end: 0; - inset-inline-start: auto; + inset-inline: auto 0; } .#{$prefix}--overflow-menu--flip.#{$prefix}--overflow-menu-options[data-floating-menu-direction='left']::after, .#{$prefix}--overflow-menu--flip.#{$prefix}--overflow-menu-options[data-floating-menu-direction='right']::after { - inset-block-end: 0; - inset-block-start: auto; + inset-block: auto 0; } .#{$prefix}--overflow-menu-options--open { diff --git a/packages/styles/scss/components/pagination/_pagination.scss b/packages/styles/scss/components/pagination/_pagination.scss index 58a290b64c71..d856dd5cb2fd 100644 --- a/packages/styles/scss/components/pagination/_pagination.scss +++ b/packages/styles/scss/components/pagination/_pagination.scss @@ -164,14 +164,12 @@ } .#{$prefix}--pagination__right .#{$prefix}--pagination__text { - margin-inline-end: 1rem; - margin-inline-start: convert.to-rem(1px); + margin-inline: convert.to-rem(1px) 1rem; } .#{$prefix}--pagination__right .#{$prefix}--pagination__text.#{$prefix}--pagination__page-text { - margin-inline-end: convert.to-rem(1px); - margin-inline-start: 1rem; + margin-inline: 1rem convert.to-rem(1px); } .#{$prefix}--pagination__right diff --git a/packages/styles/scss/components/pagination/_unstable_pagination.scss b/packages/styles/scss/components/pagination/_unstable_pagination.scss index d7a2784edd8c..5083d39b9508 100644 --- a/packages/styles/scss/components/pagination/_unstable_pagination.scss +++ b/packages/styles/scss/components/pagination/_unstable_pagination.scss @@ -66,8 +66,7 @@ .#{$prefix}--unstable-pagination__right .#{$prefix}--unstable-pagination__text { - margin-inline-end: $spacing-05; - margin-inline-start: convert.to-rem(1px); + margin-inline: convert.to-rem(1px) $spacing-05; } .#{$prefix}--unstable-pagination__button { diff --git a/packages/styles/scss/components/popover/_popover.scss b/packages/styles/scss/components/popover/_popover.scss index d27cb1cc53be..c5c6147eee14 100644 --- a/packages/styles/scss/components/popover/_popover.scss +++ b/packages/styles/scss/components/popover/_popover.scss @@ -297,8 +297,7 @@ $popover-caret-height: custom-property.get-var( > .#{$prefix}--popover-content::before { block-size: $popover-offset; inset-block-start: 0; - inset-inline-end: 0; - inset-inline-start: 0; + inset-inline: 0 0; transform: translateY(-100%); } @@ -461,8 +460,7 @@ $popover-caret-height: custom-property.get-var( > .#{$prefix}--popover-content::before { block-size: $popover-offset; inset-block-end: 0; - inset-inline-end: 0; - inset-inline-start: 0; + inset-inline: 0 0; transform: translateY(100%); } @@ -618,8 +616,7 @@ $popover-caret-height: custom-property.get-var( > .#{$prefix}--popover > .#{$prefix}--popover-content::before { inline-size: $popover-offset; - inset-block-end: 0; - inset-block-start: 0; + inset-block: 0 0; inset-inline-start: 0; transform: translateX(-100%); } @@ -786,8 +783,7 @@ $popover-caret-height: custom-property.get-var( > .#{$prefix}--popover > .#{$prefix}--popover-content::before { inline-size: $popover-offset; - inset-block-end: 0; - inset-block-start: 0; + inset-block: 0 0; inset-inline-end: 0; transform: translateX(100%); } diff --git a/packages/styles/scss/components/radio-button/_radio-button.scss b/packages/styles/scss/components/radio-button/_radio-button.scss index 0f4f1231d3ce..31165501faee 100644 --- a/packages/styles/scss/components/radio-button/_radio-button.scss +++ b/packages/styles/scss/components/radio-button/_radio-button.scss @@ -285,8 +285,7 @@ $radio-border-width: 1px !default; .#{$prefix}--radio-button__appearance, .#{$prefix}--radio-button-wrapper.#{$prefix}--radio-button-wrapper--label-left .#{$prefix}--radio-button__appearance { - margin-inline-end: 0; - margin-inline-start: $spacing-03; + margin-inline: $spacing-03 0; } // Slug styles diff --git a/packages/styles/scss/components/select/_select.scss b/packages/styles/scss/components/select/_select.scss index e3348ac53fa2..529d681865eb 100644 --- a/packages/styles/scss/components/select/_select.scss +++ b/packages/styles/scss/components/select/_select.scss @@ -217,8 +217,7 @@ border-block-end: none; color: $text-primary; inline-size: auto; - padding-inline-end: $spacing-07; - padding-inline-start: $spacing-03; + padding-inline: $spacing-03 $spacing-07; } .#{$prefix}--select--inline .#{$prefix}--select-input:focus, diff --git a/packages/styles/scss/components/slider/_slider.scss b/packages/styles/scss/components/slider/_slider.scss index cbbb113d9222..20ca6bd448bc 100644 --- a/packages/styles/scss/components/slider/_slider.scss +++ b/packages/styles/scss/components/slider/_slider.scss @@ -280,8 +280,7 @@ transform: none; &::before { - inset-inline-end: auto; - inset-inline-start: 0; + inset-inline: 0 auto; } &:hover, diff --git a/packages/styles/scss/components/slug/_slug.scss b/packages/styles/scss/components/slug/_slug.scss index f0f1a3b08d1b..2db1dacc1f61 100644 --- a/packages/styles/scss/components/slug/_slug.scss +++ b/packages/styles/scss/components/slug/_slug.scss @@ -684,8 +684,7 @@ $sizes: ( .#{$prefix}--slug .#{$prefix}--toggletip-content { // This sets the max size to the size of the action bar with 3 buttons - padding-block-end: convert.to-rem(80px); - padding-block-start: convert.to-rem(24px); + padding-block: convert.to-rem(24px) convert.to-rem(80px); padding-inline: convert.to-rem(24px); } diff --git a/packages/styles/scss/components/structured-list/_mixins.scss b/packages/styles/scss/components/structured-list/_mixins.scss index 55a5bf475a33..ae764afe6081 100644 --- a/packages/styles/scss/components/structured-list/_mixins.scss +++ b/packages/styles/scss/components/structured-list/_mixins.scss @@ -32,13 +32,11 @@ $structured-list-text-transform: none !default; /// @group structured-list /// @param {Number} $padding [$structured-list-padding] @mixin padding--data-structured-list($padding: $structured-list-padding) { - padding-inline-end: $padding * 0.5; - padding-inline-start: $padding * 0.5; + padding-inline: $padding * 0.5 $padding * 0.5; // Controls gutter sizes for check &:first-child { - padding-inline-end: $padding * 0.5; - padding-inline-start: $padding * 0.5; + padding-inline: $padding * 0.5 $padding * 0.5; } } diff --git a/packages/styles/scss/components/structured-list/_structured-list.scss b/packages/styles/scss/components/structured-list/_structured-list.scss index 38ce56aecfb1..e6ed3c1c859f 100644 --- a/packages/styles/scss/components/structured-list/_structured-list.scss +++ b/packages/styles/scss/components/structured-list/_structured-list.scss @@ -68,8 +68,7 @@ &.#{$prefix}--structured-list--flush .#{$prefix}--structured-list-row .#{$prefix}--structured-list-th:first-of-type { - padding-inline-end: 1rem; - padding-inline-start: 0; + padding-inline: 0 1rem; } } diff --git a/packages/styles/scss/components/tabs/_tabs.scss b/packages/styles/scss/components/tabs/_tabs.scss index fe0af9e7ac30..d81091110acb 100644 --- a/packages/styles/scss/components/tabs/_tabs.scss +++ b/packages/styles/scss/components/tabs/_tabs.scss @@ -91,10 +91,9 @@ } .#{$prefix}--tab--list { + overflow: visible auto; flex-direction: column; inline-size: 100%; - overflow-x: visible; - overflow-y: auto; } .#{$prefix}--tab--list-gradient_bottom { @@ -157,8 +156,7 @@ .#{$prefix}--tab--overflow-nav-button--next { position: absolute; - inset-block-end: 0; - inset-block-start: 0; + inset-block: 0 0; inset-inline-end: 0; } @@ -187,8 +185,7 @@ .#{$prefix}--tab--overflow-nav-button--previous { position: absolute; - inset-block-end: 0; - inset-block-start: 0; + inset-block: 0 0; inset-inline-start: 0; } diff --git a/packages/styles/scss/components/tag/_tag.scss b/packages/styles/scss/components/tag/_tag.scss index 3adf9ccf8db6..30d5dcee08dc 100644 --- a/packages/styles/scss/components/tag/_tag.scss +++ b/packages/styles/scss/components/tag/_tag.scss @@ -97,8 +97,7 @@ // tags used for filtering .#{$prefix}--tag--filter { - padding-block-end: 0; - padding-block-start: 0; + padding-block: 0; padding-inline-end: 0; &:hover { diff --git a/packages/styles/scss/components/treeview/_treeview.scss b/packages/styles/scss/components/treeview/_treeview.scss index 2fc1d0db26ea..a3156534e9d4 100644 --- a/packages/styles/scss/components/treeview/_treeview.scss +++ b/packages/styles/scss/components/treeview/_treeview.scss @@ -100,9 +100,8 @@ .#{$prefix}--tree-node:not(.#{$prefix}--tree-parent-node) .#{$prefix}--tree-node__label { - padding-block-end: convert.to-rem(7px); + padding-block: convert.to-rem(7px) convert.to-rem(7px); // (min-height 32px - single line text height 18px) / 2 = 7px - padding-block-start: convert.to-rem(7px); } .#{$prefix}--tree-node__label:hover .#{$prefix}--tree-node__label__details { @@ -146,8 +145,7 @@ block-size: convert.to-rem(24px); inline-size: convert.to-rem(24px); margin-block-start: $spacing-02; - margin-inline-end: $spacing-02; - margin-inline-start: -$spacing-02; + margin-inline: -$spacing-02 $spacing-02; padding-inline-start: $spacing-02; &:hover { @@ -173,8 +171,7 @@ align-self: flex-start; fill: $icon-secondary; margin-block-start: convert.to-rem(1px); - margin-inline-end: $spacing-03; - margin-inline-start: $spacing-03; + margin-inline: $spacing-03 $spacing-03; min-block-size: 1rem; min-inline-size: 1rem; } diff --git a/packages/styles/scss/components/ui-shell/header-panel/_header-panel.scss b/packages/styles/scss/components/ui-shell/header-panel/_header-panel.scss index f9f424cdae70..162c6c2e26f7 100644 --- a/packages/styles/scss/components/ui-shell/header-panel/_header-panel.scss +++ b/packages/styles/scss/components/ui-shell/header-panel/_header-panel.scss @@ -27,8 +27,7 @@ background-color: $layer; color: $text-secondary; inline-size: 0; - inset-block-end: 0; - inset-block-start: mini-units(6); + inset-block: mini-units(6) 0; inset-inline-end: 0; transition: width $duration-fast-02 motion(exit, productive); will-change: width; diff --git a/packages/styles/scss/components/ui-shell/header/_header.scss b/packages/styles/scss/components/ui-shell/header/_header.scss index 0c9ad9f4da86..fc7a8d9cbb03 100644 --- a/packages/styles/scss/components/ui-shell/header/_header.scss +++ b/packages/styles/scss/components/ui-shell/header/_header.scss @@ -35,8 +35,7 @@ block-size: mini-units(6); border-block-end: 1px solid $border-subtle; inset-block-start: 0; - inset-inline-end: 0; - inset-inline-start: 0; + inset-inline: 0 0; } .#{$prefix}--header__action { diff --git a/packages/styles/scss/components/ui-shell/side-nav/_side-nav.scss b/packages/styles/scss/components/ui-shell/side-nav/_side-nav.scss index 34818624fad4..a48ee1e827f5 100644 --- a/packages/styles/scss/components/ui-shell/side-nav/_side-nav.scss +++ b/packages/styles/scss/components/ui-shell/side-nav/_side-nav.scss @@ -36,8 +36,7 @@ background-color: $background; color: $text-secondary; inline-size: mini-units(6); - inset-block-end: 0; - inset-block-start: 0; + inset-block: 0 0; inset-inline-start: 0; max-inline-size: mini-units(32); // TODO: sync with motion work @@ -271,8 +270,7 @@ background-color: $border-interactive; content: ''; inline-size: 3px; - inset-block-end: 0; - inset-block-start: 0; + inset-block: 0 0; inset-inline-start: 0; } } @@ -383,8 +381,7 @@ background-color: $border-interactive; content: ''; inline-size: 3px; - inset-block-end: 0; - inset-block-start: 0; + inset-block: 0 0; inset-inline-start: 0; } diff --git a/packages/web-components/.cfignore b/packages/web-components/.cfignore new file mode 100644 index 000000000000..f33b593b5dab --- /dev/null +++ b/packages/web-components/.cfignore @@ -0,0 +1,3 @@ +* +!Staticfile +!storybook-static/ diff --git a/packages/web-components/.editorconfig b/packages/web-components/.editorconfig new file mode 100644 index 000000000000..3fd345c8adb8 --- /dev/null +++ b/packages/web-components/.editorconfig @@ -0,0 +1,14 @@ +root = true + +[*] + +indent_style = space +indent_size = 2 + +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/packages/web-components/.gitignore b/packages/web-components/.gitignore new file mode 100644 index 000000000000..f8b31082b19a --- /dev/null +++ b/packages/web-components/.gitignore @@ -0,0 +1,8 @@ +# Build folders +scss/ +examples/**/.yarn +examples/**/yarn.lock +custom-elements.json + +# Storybook +storybook-static diff --git a/packages/web-components/.storybook/_container.scss b/packages/web-components/.storybook/_container.scss new file mode 100644 index 000000000000..37e41860a746 --- /dev/null +++ b/packages/web-components/.storybook/_container.scss @@ -0,0 +1,72 @@ +// +// @license +// +// Copyright IBM Corp. 2019, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/themes/scss/themes'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/grid'; + +@use '@carbon/styles/scss/components/button/tokens' as button-tokens; +@use '@carbon/styles/scss/components/notification/tokens' as notification-tokens; +@use '@carbon/styles/scss/components/tag/tokens' as tag-tokens; +@include theme.add-component-tokens(button-tokens.$button-tokens); +@include theme.add-component-tokens(notification-tokens.$notification-tokens); +@include theme.add-component-tokens(tag-tokens.$tag-tokens); + +// Emit the flex-grid styles +@include grid.flex-grid(); + +*, +*::before, +*::after { + box-sizing: border-box; +} + +// The default theme is "white" (White) +:root { + @include theme.theme(themes.$white); +} +// Set the theme attribute to "g10" to use the Gray 10 theme +// +:root[storybook-carbon-theme='g10'] { + @include theme.theme(themes.$g10); +} + +// Set the theme attribute to "g90" to use the Gray 90 theme +// +:root[storybook-carbon-theme='g90'] { + @include theme.theme(themes.$g90); +} + +// Set the theme attribute to "g100" to use the Gray 100 theme +// +:root[storybook-carbon-theme='g100'] { + @include theme.theme(themes.$g100); +} + +body { + background-color: theme.$background; + color: theme.$text-primary; +} + +.sb-show-main.sb-main-padded { + padding: 0; +} + +#main-content { + padding: 42px; + position: relative; +} + +.#{$prefix}--content.#{$prefix}-ce-demo-devenv--ui-shell-content { + margin: 0; + height: 100vh; + width: 100%; + padding: 2rem; +} diff --git a/packages/web-components/.storybook/basic-example-cdn.html b/packages/web-components/.storybook/basic-example-cdn.html new file mode 100644 index 000000000000..bcad085883ac --- /dev/null +++ b/packages/web-components/.storybook/basic-example-cdn.html @@ -0,0 +1,31 @@ + + + + + + + +

+ + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + +
+ + diff --git a/packages/web-components/.storybook/container.ts b/packages/web-components/.storybook/container.ts new file mode 100644 index 000000000000..c000bcacde35 --- /dev/null +++ b/packages/web-components/.storybook/container.ts @@ -0,0 +1,40 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html, TemplateResult } from 'lit'; +import containerStyles from './_container.scss?lit'; // eslint-disable-line import/first +import '../src/components/skip-to-content/skip-to-content'; + +/** + * @param options The rendering options. + * @param [options.hasMainTag] `true` if the story itself has `
` tag. + * @param [options.children] The story content. + * @returns The content that wraps the story. + */ +const container = ({ + hasMainTag, + children, +}: { + hasMainTag?: boolean; + children: TemplateResult; +}) => html` + + +
+ ${children} +
+`; + +export default container; diff --git a/packages/web-components/.storybook/main.ts b/packages/web-components/.storybook/main.ts new file mode 100644 index 000000000000..03cb28870c45 --- /dev/null +++ b/packages/web-components/.storybook/main.ts @@ -0,0 +1,74 @@ +/** + * @license + * + * Copyright IBM Corp. 2023, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type { StorybookConfig } from '@storybook/web-components-vite'; +import { mergeConfig } from 'vite'; +import { litStyleLoader, litTemplateLoader } from '@mordech/vite-lit-loader'; +import remarkGfm from 'remark-gfm'; +import viteSVGResultCarbonIconLoader from '../tools/vite-svg-result-carbon-icon-loader'; +const glob = require('fast-glob'); + +const stories = glob.sync( + [ + '../docs/**/*.mdx', + '../src/**/*.mdx', + '../src/**/*.stories.@(js|jsx|ts|tsx)', + ], + { + ignore: ['../src/**/docs/*.mdx'], + cwd: __dirname, + } +); + +const config: StorybookConfig = { + stories: stories, + addons: [ + { + name: '@storybook/addon-docs', + options: { + mdxPluginOptions: { + mdxCompileOptions: { + remarkPlugins: [remarkGfm], + }, + }, + }, + }, + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-storysource', + 'storybook-addon-accessibility-checker', + ], + framework: { + name: '@storybook/web-components-vite', + options: {}, + }, + async viteFinal(config) { + // Merge custom configuration into the default config + return mergeConfig(config, { + plugins: [ + litStyleLoader(), + litTemplateLoader(), + viteSVGResultCarbonIconLoader(), + ], + optimizeDeps: { + include: ['@storybook/web-components'], + exclude: ['lit', 'lit-html'], + }, + define: { + 'process.env': process.env, + }, + sourcemap: true, + }); + }, + docs: { + autodocs: true, + defaultName: 'Overview', + }, +}; +export default config; diff --git a/packages/web-components/.storybook/manager-head.html b/packages/web-components/.storybook/manager-head.html new file mode 100644 index 000000000000..fe466db1369a --- /dev/null +++ b/packages/web-components/.storybook/manager-head.html @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/web-components/.storybook/manager.js b/packages/web-components/.storybook/manager.js new file mode 100644 index 000000000000..714fb881fe62 --- /dev/null +++ b/packages/web-components/.storybook/manager.js @@ -0,0 +1,39 @@ +/** + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Conditionally generate CSS to hide a component based on its corresponding + * feature flag environment variable. + * + * @param {*} envVar + * Environment variable to check. + * @param {*} cssId + * CSS ID for selector. + * @returns + */ +const getCss = (envVar, cssId) => { + return envVar !== 'true' + ? `button[id^="${cssId}"] { display: none !important; }\n` + : ''; +}; + +// Build string of CSS rules. +let css = ''; +if (!process.env.CDS_FLAGS_ALL) { + css += getCss( + process.env.CDS_EXPERIEMENTAL_COMPONENT_NAME, + 'components-experimental-component-name' + ); +} + +// Inject any CSS rules into the page. +if (css.length) { + const head = document.head || document.getElementsByTagName('head')[0]; + const style = document.createElement('style'); + head.appendChild(style); + style.appendChild(document.createTextNode(css)); +} diff --git a/packages/web-components/.storybook/preview-head.html b/packages/web-components/.storybook/preview-head.html new file mode 100644 index 000000000000..51390b883807 --- /dev/null +++ b/packages/web-components/.storybook/preview-head.html @@ -0,0 +1,18 @@ + + + + diff --git a/packages/web-components/.storybook/preview.js b/packages/web-components/.storybook/preview.js new file mode 100644 index 000000000000..bbfe19bc23d5 --- /dev/null +++ b/packages/web-components/.storybook/preview.js @@ -0,0 +1,211 @@ +/** + * Copyright IBM Corp. 2016, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { setCustomElementsManifest } from '@storybook/web-components'; +import customElements from '../custom-elements.json'; +import container from './container'; +import { white, g10, g90, g100 } from '@carbon/themes'; +import { breakpoints } from '@carbon/layout'; +import theme from './theme'; +import './templates/with-layer'; + +setCustomElementsManifest(customElements); + +export const globalTypes = { + locale: { + name: 'Locale', + description: 'Set the localization for the storybook', + defaultValue: 'en', + toolbar: { + icon: 'globe', + items: [ + { + right: '🇺🇸', + title: 'English', + value: 'en', + }, + { + right: '🇵🇸', + title: 'Arabic', + value: 'ar', + }, + ], + }, + }, + dir: { + name: 'Text direction', + description: 'Set the text direction for the story', + defaultValue: 'ltr', + toolbar: { + icon: 'transfer', + title: 'Text direction', + items: [ + { + right: '🔄', + title: 'auto', + value: 'auto', + }, + { + right: '➡️', + title: 'left-to-right (ltr)', + value: 'ltr', + }, + { + right: '⬅️', + title: 'right-to-left (rtl)', + value: 'rtl', + }, + ], + }, + }, + theme: { + name: 'Theme', + description: 'Set the global theme for displaying components', + defaultValue: 'white', + toolbar: { + icon: 'paintbrush', + title: 'Theme', + items: ['white', 'g10', 'g90', 'g100'], + }, + }, +}; + +export const parameters = { + a11y: { + // Can specify engine as "axe" or "accessibility-checker" (axe default) + engine: 'accessibility-checker', + config: { + rules: [ + { + // To disable a rule across all stories, set `enabled` to `false`. + // Use with caution: all violations of this rule will be ignored! + id: 'html_lang_exists', + enabled: false, + }, + { id: 'page_title_exists', enabled: false }, + { id: 'skip_main_exists', enabled: false }, + { id: 'html_skipnav_exists', enabled: false }, + { id: 'aria_content_in_landmark', enabled: false }, + { id: 'aria_child_tabbable', enabled: false }, + ], + }, + }, + actions: { argTypesRegex: '^on.*' }, + backgrounds: { + // https://storybook.js.org/docs/react/essentials/backgrounds#grid + grid: { + cellSize: 8, + opacity: 0.5, + }, + values: [ + { + name: 'white', + value: white.background, + }, + { + name: 'g10', + value: g10.background, + }, + { + name: 'g90', + value: g90.background, + }, + { + name: 'g100', + value: g100.background, + }, + ], + }, + controls: { + expanded: true, + sort: 'alpha', + hideNoControlsWarning: true, + }, + docs: { + theme, + }, + viewport: { + viewports: { + sm: { + name: 'Small', + styles: { + width: breakpoints.sm.width, + height: '100%', + }, + }, + md: { + name: 'Medium', + styles: { + width: breakpoints.md.width, + height: '100%', + }, + }, + lg: { + name: 'Large', + styles: { + width: breakpoints.lg.width, + height: '100%', + }, + }, + xlg: { + name: 'X-Large', + styles: { + width: breakpoints.xlg.width, + height: '100%', + }, + }, + Max: { + name: 'Max', + styles: { + width: breakpoints.max.width, + height: '100%', + }, + }, + }, + }, + options: { + storySort: { + method: 'alphabetical', + order: [ + 'Introduction', + [ + 'Welcome', + 'Custom styles', + 'Carbon CDN style helpers', + 'Form Participation', + ], + 'Components', + 'Layout', + ], + }, + }, +}; + +export const decorators = [ + function decoratorContainer(story, context) { + const result = story(); + const { hasMainTag } = result; + const { locale, dir, theme } = context.globals; + + if (process.env.STORYBOOK_USE_RTL === 'true') { + document.documentElement.setAttribute('dir', 'rtl'); + } + + document.documentElement.setAttribute('storybook-carbon-theme', theme); + + document.documentElement.lang = locale; + document.documentElement.dir = dir; + + return container({ hasMainTag, children: result }); + }, +]; + +export const Preview = { + parameters, + globalTypes, + decorators, +}; diff --git a/packages/web-components/.storybook/templates/with-layer.scss b/packages/web-components/.storybook/templates/with-layer.scss new file mode 100644 index 000000000000..fa1ea5b5eb6c --- /dev/null +++ b/packages/web-components/.storybook/templates/with-layer.scss @@ -0,0 +1,38 @@ +// +// Copyright IBM Corp. 2019, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/colors'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/spacing'; +@use '@carbon/styles/scss/type'; +@use '@carbon/styles/scss/components/tag'; + +@use '@carbon/styles/scss/config' as *; + +.#{$prefix}--with-layer__layer { + position: relative; + border: 1px dashed colors.$purple-50; +} + +.#{$prefix}--with-layer__layer .#{$prefix}--with-layer__layer { + background-color: theme.$layer; + margin-block-start: spacing.$spacing-07; +} + +.#{$prefix}--with-layer__label { + @include type.type-style('code-01'); + + display: inline-flex; + padding: spacing.$spacing-02; + background-color: tag.$tag-background-purple; + color: tag.$tag-color-purple; + column-gap: spacing.$spacing-02; +} + +.#{$prefix}--with-layer__content { + padding: spacing.$spacing-05; +} diff --git a/packages/web-components/.storybook/templates/with-layer.ts b/packages/web-components/.storybook/templates/with-layer.ts new file mode 100644 index 000000000000..d7ff7d81493d --- /dev/null +++ b/packages/web-components/.storybook/templates/with-layer.ts @@ -0,0 +1,90 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import Layers from '@carbon/icons/lib/layers/16'; +import { prefix } from '../../src/globals/settings'; + +import styles from './with-layer.scss?lit'; + +/** + * Storybook template layer component, strictly for presentation purposes + * + * @element sb-template-layers + * @slot The elements contained within the component. + */ +@customElement(`sb-template-layers`) +class CDSLayer extends LitElement { + @property() + content; + + private _handleSlotChange({ target }: Event) { + if (!this.content) { + const content = (target as HTMLSlotElement) + .assignedNodes() + .filter( + (node) => + node.nodeType !== Node.TEXT_NODE || node!.textContent!.trim() + ); + + this.content = content[0]; + } + } + + updated() { + if (this.content) { + const layer2 = this.content.cloneNode(true) as HTMLElement; + const layer3 = this.content.cloneNode(true) as HTMLElement; + layer2.setAttribute('slot', 'layer-2'); + layer3.setAttribute('slot', 'layer-3'); + this.appendChild(layer2); + this.appendChild(layer3); + } + } + + render() { + return html` +
+
+
${Layers()} Layer 1
+
+ + +
+
+ ${Layers()} Layer 2 +
+
+ + +
+
+ ${Layers()} Layer 3 +
+
+ + + +
+
+
+
+
+
+
+
+
+ `; + } + + static styles = styles; +} + +export default CDSLayer; diff --git a/packages/web-components/.storybook/theme.js b/packages/web-components/.storybook/theme.js new file mode 100644 index 000000000000..bcfed88fd61d --- /dev/null +++ b/packages/web-components/.storybook/theme.js @@ -0,0 +1,21 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { create } from '@storybook/theming/create'; +import { version } from '../package.json'; + +export default create({ + // Typography + fontBase: "'IBM Plex Sans', 'Helvetica Neue', Arial, sans-serif", + fontCode: + "'IBM Plex Mono', Menlo, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', Courier, monospace", + brandTitle: `@carbon/web-components ${version}`, + brandUrl: + 'https://github.com/carbon-design-system/carbon-for-ibm-dotcom/tree/main/packages/carbon-web-components', +}); diff --git a/packages/web-components/CHANGELOG.md b/packages/web-components/CHANGELOG.md new file mode 100644 index 000000000000..2a48b87aa50d --- /dev/null +++ b/packages/web-components/CHANGELOG.md @@ -0,0 +1,483 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [2.13.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.13.1-rc.0...@carbon/web-components@2.13.1) (2024-09-18) +**Note:** Version bump only for package @carbon/web-components + + + +# [2.13.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.13.0-rc.0...@carbon/web-components@2.13.0) (2024-09-16) +**Note:** Version bump only for package @carbon/web-components + + + +# [2.12.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.12.0-rc.0...@carbon/web-components@2.12.0) (2024-09-03) + +**Note:** Version bump only for package @carbon/web-components + + + + + +# [2.12.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.11.1...@carbon/web-components@2.12.0-rc.0) (2024-08-26) + + +### Bug Fixes + +* **accordion:** apply carbon element decorator for accordion skeleton ([#11989](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11989)) ([dfdc39b](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/dfdc39bca433fc210e45fd2f4540bf7e19aa4b08)) + +### Features + +* **dotcom-components:** add shadowparts ([#11812](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11812)) ([b8983f2](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/b8983f2c98b8339cc5e678db5b9ac0d4e5508278)), closes [#11673](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11673) + + +## [2.11.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.11.1-rc.0...@carbon/web-components@2.11.1) (2024-07-30) + +**Note:** Version bump only for package @carbon/web-components + +# [2.11.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.11.0-rc.1...@carbon/web-components@2.11.0) (2024-07-23) + +**Note:** Version bump only for package @carbon/web-components + +# [2.11.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.11.0-rc.0...@carbon/web-components@2.11.0-rc.1) (2024-07-23) + +### Bug Fixes + +- **custom-element:** ensure all cwc components use carbonElement ([#11937](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11937)) ([f727bae](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/f727bae4e80fce59991dc8ad7bf5ea9e68c01cbc)) + +# [2.11.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.10.0-rc.0...@carbon/web-components@2.11.0-rc.0) (2024-07-12) + +### Bug Fixes + +- **left-nav:** fix focus trapping ([#11842](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11842)) ([5f824ec](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/5f824ecee9f2bb086bdebee41e2271faa7972cbe)) + +# [2.10.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.9.0-rc.0...@carbon/web-components@2.10.0-rc.0) (2024-05-28) + +### Bug Fixes + +- **side-panel:** import missing icon-button and codesandbox example ([#11821](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11821)) ([3c51597](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/3c51597f48ffd6a18201f56fe740322b9e15127c)) +- **tearsheet:** tearsheet styles and codesandbox example ([#11792](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11792)) ([f0ddd6e](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/f0ddd6e22c5298e8c612ae113301dc4e2b5292f2)) + +# [2.9.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.9.0-rc.0...@carbon/web-components@2.9.0) (2024-05-16) + +**Note:** Version bump only for package @carbon/web-components + +# [2.9.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.8.0...@carbon/web-components@2.9.0-rc.0) (2024-05-06) + +### Bug Fixes + +- **data-table:** center align checkboxes ([#11743](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11743)) ([3c045f5](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/3c045f51578f10c9fc0f03bd71441fa098c1d52c)), closes [#11742](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11742) + +### Features + +- instrument with telemetry JS scope ([#11747](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11747)) ([650739e](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/650739e4d23677dd4891c781be20d76060170533)) + +# [2.8.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.8.0-rc.0...@carbon/web-components@2.8.0) (2024-04-23) + +**Note:** Version bump only for package @carbon/web-components + +# [2.8.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.7.0...@carbon/web-components@2.8.0-rc.0) (2024-04-17) + +### Features + +- **slug:** ai slug updates ([#11716](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11716)) ([e9fa12f](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/e9fa12fd8cd3973aa7279a9d69582139937934d9)) +- **slug:** remove no longer needed dot-type prop ([#11726](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11726)) ([2cca4b3](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/2cca4b38955d738104c60739ee09052ae4625c7d)) + +# [2.7.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.7.0-rc.0...@carbon/web-components@2.7.0) (2024-04-09) + +**Note:** Version bump only for package @carbon/web-components + +# [2.7.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.6.0-rc.0...@carbon/web-components@2.7.0-rc.0) (2024-04-02) + +**Note:** Version bump only for package @carbon/web-components + +# [2.6.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.6.0-rc.0...@carbon/web-components@2.6.0) (2024-03-27) + +**Note:** Version bump only for package @carbon/web-components + +# [2.6.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.5.0...@carbon/web-components@2.6.0-rc.0) (2024-03-21) + +### Bug Fixes + +- **cdn:** emit the CSS grid classes in a new artifact cssgrid.css ([#11626](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11626)) ([98afd6a](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/98afd6a25015763508cca5fec6625db5acd38808)) +- **combobox:** fix import path for some bundlers ([#11639](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11639)) ([5c491a0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/5c491a02a56dc07b69091d2f4e09e6778cf6ad00)), closes [#11635](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11635) + +# [2.5.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.5.0-rc.1...@carbon/web-components@2.5.0) (2024-03-11) + +**Note:** Version bump only for package @carbon/web-components + +# [2.5.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.5.0-rc.0...@carbon/web-components@2.5.0-rc.1) (2024-03-07) + +### Bug Fixes + +- reduced motion side panel close ([#11608](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11608)) ([dbddbb0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/dbddbb03b2da53993b6323f99ca95bbb8520c2e2)) + +# [2.5.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.4.0...@carbon/web-components@2.5.0-rc.0) (2024-03-01) + +### Bug Fixes + +- **chat-button:** update to latest with no icon option ([#11577](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11577)) ([4106d3d](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/4106d3d490a611ef99844fb6812b6790e5b678c3)) +- **content-switcher:** get current content-switcher-item on icon click ([#11602](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11602)) ([271295a](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/271295a242e04fb185b042b73f11bc03e1657953)), closes [#10963](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10963) +- **date picker:** detect change range interval console error ([#11532](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11532)) ([eee2c73](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/eee2c73e434f4afed7eccde69017734d0deae0c9)), closes [#11490](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11490) +- **dropdown:** visibility of warn-text and invalid-text ([#11573](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11573)) ([92225bb](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/92225bb4842bc9cefdf9d302836da8291483dd24)) +- side panel story slug alignment ([#11594](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11594)) ([b0ee3b7](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/b0ee3b759b91749137d69bd8f5f019c52edb867a)) + +### Features + +- Add CWC Tearsheet ([#11545](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11545)) ([fd18753](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/fd18753e21dcd9f11f537da50ce113e2811d131f)) +- cwc stacking tearsheets ([#11586](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11586)) ([7a1842e](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/7a1842ef204f4196aaf62d67f45740ef41921933)) + +# [2.4.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.4.0-rc.3...@carbon/web-components@2.4.0) (2024-02-26) + +# 2.4.0-rc.4 (2024-02-23) + +### Bug Fixes + +- **autoalign:** fix autoalign CSB example ([#11572](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11572)) ([bf6ccfb](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/bf6ccfbb259a3bd884d037048c522c6729813e6c)) +- **side-nav:** update max-block-size; closes [#10936](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10936) ([#11571](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11571)) ([0fe6fef](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/0fe6fef5c1713cfe4e155a5c4f3b8376b5d4e246)) + +# [2.4.0-rc.4](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.4.0-rc.3...@carbon/web-components@2.4.0-rc.4) (2024-02-23) + +### Bug Fixes + +- **autoalign:** fix autoalign CSB example ([#11572](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11572)) ([bf6ccfb](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/bf6ccfbb259a3bd884d037048c522c6729813e6c)) +- **side-nav:** update max-block-size; closes [#10936](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10936) ([#11571](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11571)) ([0fe6fef](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/0fe6fef5c1713cfe4e155a5c4f3b8376b5d4e246)) + +# [2.4.0-rc.3](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.4.0-rc.2...@carbon/web-components@2.4.0-rc.3) (2024-02-22) + +### Bug Fixes + +- **datatable:** is sortable console error ([#11568](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11568)) ([d827360](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/d827360733c98ea138ad0eb92ca98ea78fb33624)) + +# [2.4.0-rc.2](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.4.0-rc.1...@carbon/web-components@2.4.0-rc.2) (2024-02-21) + +### Features + +- **autoalign:** utilize autoUpdate from @floating-ui/dom ([#11565](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11565)) ([918089c](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/918089cfee729db0d642788f973416dfc0fcca3a)) + +# [2.4.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.4.0-rc.0...@carbon/web-components@2.4.0-rc.1) (2024-02-20) + +### Bug Fixes + +- **tabs:** container size wrong ([#11556](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11556)) ([b520fc4](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/b520fc4a7b8d55b7bf622cbcebebdfa528cb43f1)) + +### Features + +- **autoalign:** @floating-ui/dom implementation ([#11549](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11549)) ([85db5f4](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/85db5f47ca3303e14410f73b9ac3bc2c08bb6d3e)) + +# [2.4.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.3.0...@carbon/web-components@2.4.0-rc.0) (2024-02-19) + +### Bug Fixes + +- **code-snippet:** multi copy button ([#11492](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11492)) ([c65ed61](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/c65ed617e3e57745b2f94c82dc655c08e45b8839)), closes [#11475](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11475) +- **datatable:** search not working with uppercase characters in query ([#11493](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11493)) ([7c92bfe](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/7c92bfe8940d995ddd9e4fea50e07c93854676c5)), closes [#11483](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11483) +- **file uploader:** drag and drop not working ([#11536](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11536)) ([0e75f3b](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/0e75f3bc3117037aaa9b0f5938f0f0d1936e68cd)) +- **side-panel:** refactor to match latest ibm-products ([#11511](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11511)) ([51e021a](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/51e021a34f9cb72b97c81dc04e7a35925c275df8)) + +### Features + +- **ai-skeleton:** new cwc experminetal ([#11544](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11544)) ([acb7535](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/acb7535b31ebef944c2988bd1af2b0e9b21e6d66)), closes [#11505](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11505) +- **chat-button:** experimental wc ([#11510](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11510)) ([a1560a5](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/a1560a5bda222e4931da16780d91b6005c05e4db)), closes [#11498](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11498) +- **data-table:** ai updates ([#11530](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11530)) ([627dc5a](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/627dc5a98a9bb5d6b2f9a86d278cceb40d2f16a9)), closes [#11499](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11499) +- **modal:** ai updates ([#11533](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11533)) ([d60f94a](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/d60f94a90cc0283b53beeb4941f168fdd06d10d4)), closes [#11500](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11500) + +# [2.3.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.3.0-rc.1...@carbon/web-components@2.3.0) (2024-02-12) + +**Note:** Version bump only for package @carbon/web-components + +# [2.3.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.3.0-rc.0...@carbon/web-components@2.3.0-rc.1) (2024-02-09) + +### Bug Fixes + +- **datatable:** is sortable not working in table header cell ([#11516](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11516)) ([8da0be7](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/8da0be77b80cdd5faecfd273e5bf41e8e0da5a80)) + +# [2.3.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.2.0-rc.0...@carbon/web-components@2.3.0-rc.0) (2024-02-02) + +### Bug Fixes + +- **data table:** filter issue in expansion table ([#11438](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11438)) ([944a69a](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/944a69a84f0c746728dbf7ef4ca7a059d146e2fe)), closes [#11179](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11179) +- **data-table:** Sorting and expansion doesn't work together ([#11416](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11416)) ([2259364](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/22593642d9c5adc80caea484e618ea0df97ee954)), closes [#11178](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11178) [#11481](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11481) +- **datatable:** selection function not working as expected ([#11449](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11449)) ([d20ec1f](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/d20ec1fad2ce28fdf9d1c7e51b9c43c4756600eb)), closes [#11349](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11349) +- **dropdown:** remove excess border of first dropdown element ([#11400](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11400)) ([a0830b0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/a0830b0d4e41e28f57af1579db7be088e3ca8026)), closes [#11271](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11271) [#11271](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11271) +- **overflow-menu:** position jumping ([#11448](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11448)) ([1adb618](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/1adb61873b9c37aa9e541cf469f701f8092271ff)), closes [#9827](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9827) +- **progress-indicator:** label attribute not showing when there is when there is white space before closing tag ([#11430](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11430)) ([954ecf4](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/954ecf408889d896121872adac3ebca721fe21d3)), closes [#11167](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11167) +- **stackblitz:** fix and standardize masthead examples for v2 ([#11199](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11199)) ([c3ddeb8](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/c3ddeb8016b0259ce4f202cb2d99c16b6b5c2545)) +- **tabs:** Restore the highlight style when tab is selected ([#11181](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11181)) ([929ca6f](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/929ca6fe1609c7dc374ac06d790bab9b16284f9a)), closes [#11147](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11147) [/github.com/carbon-design-system/carbon-for-ibm-dotcom/blob/91e50fa5cfcd5a5b4950ad09bc76cc89b1dc09e0/packages/carbon-web-components/src/components/tabs/tabs.scss#L104](https://github.com//github.com/carbon-design-system/carbon-for-ibm-dotcom/blob/91e50fa5cfcd5a5b4950ad09bc76cc89b1dc09e0/packages/carbon-web-components/src/components/tabs/tabs.scss/issues/L104) + +### Features + +- **sidepanel:** introduce side panel component ([#11201](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11201)) ([c2c5bca](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/c2c5bcae45745193dca47bbab8799e8a22d181f8)) +- **skeleton-icon:** new cwc component ([#11434](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11434)) ([30be3c1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/30be3c1b04e4e5d7ed0ab6945b91242e9150d1cf)), closes [#11380](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11380) +- **tile:** slug ai updates ([#11484](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11484)) ([a4cc518](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/a4cc518bf85cac970d22a01e72bd332b2ec5a179)) + +# [2.2.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.2.0-rc.1...@carbon/web-components@2.2.0) (2024-01-29) + +**Note:** Version bump only for package @carbon/web-components + +# [2.2.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.2.0-rc.0...@carbon/web-components@2.2.0-rc.1) (2024-01-26) + +### Features + +- **slug:** ai callout updates for 2.2.0 ([#11453](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11453)) ([8f0b9f6](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/8f0b9f609b4d98a148071937db7bcdb689bea514)) + +# [2.2.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@2.1.2...@carbon/web-components@2.2.0-rc.0) (2024-01-19) + +### Bug Fixes + +- **number-input:** fix incorrect controls border for readonly mode ([#11402](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11402)) ([3b2149b](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/3b2149bb71c2b8cf4325972f728032d13b0b6ce1)), closes [#11390](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11390) +- **radio-button:** add missing slot optioin ([#11307](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11307)) ([95e9eb5](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/95e9eb56d5ef3926f361de5c2e9b854a722631e7)), closes [#11288](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11288) +- **select:** selected item is not showing for ios/ipados ([#11214](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11214)) ([2186384](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/218638476e26c72e67376b1b8fa430219f63b4ad)) +- **tooltip:** tooltip persists issue ([#11324](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11324)) ([d355535](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/d35553594e84406878f3b8a21489bb6b66faaa7e)) + +### Features + +- **modal:** with slug ([#11247](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11247)) ([209142a](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/209142a44187788965dd5b193f31491de8b12c0b)), closes [#11142](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11142) + +# [1.34.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.34.0-rc.2...@carbon/web-components@1.34.0) (2023-11-15) + +**Note:** Version bump only for package @carbon/web-components + +# [1.34.0-rc.2](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.34.0-rc.1...@carbon/web-components@1.34.0-rc.2) (2023-11-06) + +**Note:** Version bump only for package @carbon/web-components + +# [1.34.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.33.0-rc.1...@carbon/web-components@1.34.0-rc.1) (2023-11-02) + +### Bug Fixes + +- **language-selector:** remove internal decorator ([#11069](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11069)) ([d61199d](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/d61199d5c9e03671aa08f9a0b774f470900dfd0c)), closes [#10885](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10885) +- **link-with-icon:** refactor LINK_SIZE enum ([#11071](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11071)) ([cf570e1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/cf570e15079f8fc58c8b2600848d0c1a87e9b065)) +- **ui-shell:** a11y issue with side nav item ([#11044](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11044)) ([9eb94ea](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/9eb94ea097dcf9610a72900468008373cfec3bbe)), closes [#10918](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10918) + +# [1.34.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.33.0-rc.1...@carbon/web-components@1.34.0-rc.0) (2023-10-30) + +### Bug Fixes + +- **language-selector:** remove internal decorator ([#11069](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11069)) ([d61199d](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/d61199d5c9e03671aa08f9a0b774f470900dfd0c)), closes [#10885](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10885) +- **ui-shell:** a11y issue with side nav item ([#11044](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/11044)) ([9eb94ea](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/9eb94ea097dcf9610a72900468008373cfec3bbe)), closes [#10918](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10918) + +# [1.33.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.33.0-rc.0...@carbon/web-components@1.33.0-rc.1) (2023-10-12) + +**Note:** Version bump only for package @carbon/web-components + +# [1.33.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.32.1-rc.0...@carbon/web-components@1.33.0-rc.0) (2023-10-03) + +**Note:** Version bump only for package @carbon/web-components + +## [1.32.1-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.32.0...@carbon/web-components@1.32.1-rc.0) (2023-09-25) + +**Note:** Version bump only for package @carbon/web-components + +# [1.32.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.32.0-rc.0...@carbon/web-components@1.32.0) (2023-09-19) + +**Note:** Version bump only for package @carbon/web-components + +# [1.32.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.31.0...@carbon/web-components@1.32.0-rc.0) (2023-09-06) + +### Bug Fixes + +- **lerna:** build packages & codesandbox updates ([#10876](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10876)) ([fa5bee0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/fa5bee07eb65a0f730c7cb1094a5eb8d122ab593)) +- **pagination:** mark selected option in page-sizes-select component ([#10884](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10884)) ([ec3e4cf](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/ec3e4cfaa4f50282c037c789898b7d6a61d6d54c)) + +# [1.31.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.31.0-rc.2...@carbon/web-components@1.31.0) (2023-08-22) + +**Note:** Version bump only for package @carbon/web-components + +# [1.31.0-rc.2](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.31.0-rc.1...@carbon/web-components@1.31.0-rc.2) (2023-08-18) + +**Note:** Version bump only for package @carbon/web-components + +# [1.31.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.31.0-rc.0...@carbon/web-components@1.31.0-rc.1) (2023-08-18) + +**Note:** Version bump only for package @carbon/web-components + +# [1.31.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.30.0...@carbon/web-components@1.31.0-rc.0) (2023-08-14) + +### Bug Fixes + +- **breadcrumb:** update aria role to now have the value of navigation ([#10780](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10780)) ([e964047](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/e96404775f1bb14e8954f29f5b519d88f79e7b79)), closes [#10730](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10730) + +# [1.30.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.30.0-rc.0...@carbon/web-components@1.30.0) (2023-07-26) + +**Note:** Version bump only for package @carbon/web-components + +# [1.30.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.29.0...@carbon/web-components@1.30.0-rc.0) (2023-07-11) + +### Bug Fixes + +- **date-picker:** prevent range inputs from clearing prematurely ([#10603](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10603)) ([77306c8](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/77306c89d2b5d374efdafba99b77e50cf65f61b7)) +- **masthead:** Esc to close Cloud Masthead ([#10555](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10555)) ([de67bf8](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/de67bf8242ff47f2c26f285fc878f932bc822397)), closes [#10174](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10174) + +# [1.29.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.29.0-rc.3...@carbon/web-components@1.29.0) (2023-06-27) + +**Note:** Version bump only for package @carbon/web-components + +# [1.29.0-rc.3](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.29.0-rc.2...@carbon/web-components@1.29.0-rc.3) (2023-06-27) + +### Bug Fixes + +- **multi-select:** move filterable attribute out of scope for styles ([#10608](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10608)) ([1c1cf35](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/1c1cf35ced1d73c9b0558ce474edd124ce773da8)) + +# [1.29.0-rc.2](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.29.0-rc.1...@carbon/web-components@1.29.0-rc.2) (2023-06-23) + +**Note:** Version bump only for package @carbon/web-components + +# [1.29.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.29.0-rc.0...@carbon/web-components@1.29.0-rc.1) (2023-06-22) + +### Bug Fixes + +- **masthead:** Esc to close Cloud Masthead ([#10555](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10555)) ([#10588](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10588)) ([06cd69d](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/06cd69dec6d91cafb358e078d8d083ae62edfc13)), closes [#10174](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10174) + +# [1.29.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.28.0...@carbon/web-components@1.29.0-rc.0) (2023-06-09) + +### Bug Fixes + +- **bx-header-menu:** add button role ([#10440](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10440)) ([c5d8c5d](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/c5d8c5db8c42e129a901cda81aba7eeadb5f8c79)), closes [#10392](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10392) +- **input:** autocomplete property ([#10540](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10540)) ([6096958](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/60969585cc3792409e967784437fefd2bf096c71)), closes [#10498](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10498) +- **modal:** small screen view ([#10511](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10511)) ([7f4aaef](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/7f4aaef392fa7b3482b3544a4b0b7833034ccf33)) + +# [1.28.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.28.0-rc.2...@carbon/web-components@1.28.0) (2023-05-23) + +**Note:** Version bump only for package @carbon/web-components + +# [1.28.0-rc.2](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.28.0-rc.1...@carbon/web-components@1.28.0-rc.2) (2023-05-18) + +**Note:** Version bump only for package @carbon/web-components + +# [1.28.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.28.0-rc.0...@carbon/web-components@1.28.0-rc.1) (2023-05-11) + +**Note:** Version bump only for package @carbon/web-components + +# [1.28.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.27.0-rc.0...@carbon/web-components@1.28.0-rc.0) (2023-05-08) + +### Bug Fixes + +- **checkbox:** set relative `position` ([#10333](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10333)) ([8f10b78](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/8f10b78cc1543ca6f2e69339be96a0974bc79631)) + +# [1.27.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.27.0-rc.1...@carbon/web-components@1.27.0) (2023-04-25) + +**Note:** Version bump only for package @carbon/web-components + +# [1.27.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.27.0-rc.0...@carbon/web-components@1.27.0-rc.1) (2023-04-18) + +### Bug Fixes + +- **checkbox:** set relative `position` ([#10333](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10333)) ([8f10b78](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/8f10b78cc1543ca6f2e69339be96a0974bc79631)) + +# [1.27.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.26.0...@carbon/web-components@1.27.0-rc.0) (2023-04-11) + +**Note:** Version bump only for package @carbon/web-components + +# [1.26.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.26.0-rc.3...@carbon/web-components@1.26.0) (2023-03-28) + +**Note:** Version bump only for package @carbon/web-components + +# [1.26.0-rc.3](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.26.0-rc.2...@carbon/web-components@1.26.0-rc.3) (2023-03-27) + +**Note:** Version bump only for package @carbon/web-components + +# [1.26.0-rc.2](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.26.0-rc.1...@carbon/web-components@1.26.0-rc.2) (2023-03-23) + +### Bug Fixes + +- **modal:** styles with sass upgrade ([#10237](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10237)) ([46993a9](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/46993a90bcb072ae77d07ea63e672821e9bdf628)) + +# [1.26.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.26.0-rc.0...@carbon/web-components@1.26.0-rc.1) (2023-03-16) + +### Bug Fixes + +- **notificaiton/breadcrumb:** update styles/remove [@extend](https://github.com/extend) ([#10231](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10231)) ([96affe7](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/96affe7426a988e00f75e2313651a76ff095b162)) + +# [1.26.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.25.0...@carbon/web-components@1.26.0-rc.0) (2023-03-13) + +### Bug Fixes + +- **cwc:** storybook link ([#10194](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10194)) ([ea4d0a6](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/ea4d0a6c11859effef23b6aa073918dad41ce3de)) +- **date-picker:** range mode clearing first value ([#10168](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10168)) ([fe4d6da](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/fe4d6dabc2ee15953de62c7d12d72d1329756b39)), closes [#10088](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10088) +- **lightbox-carousel:** accessibility & QA improvements to lightbox carousels ([#9149](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9149)) ([fa408af](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/fa408afb43e47d3c0c1259a33a47c637bedb0fac)), closes [#8911](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8911) [#8913](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8913) [#8915](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8915) [#8912](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8912) [#8914](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8914) [#8911](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8911) [#8912](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8912) [/github.com/carbon-design-system/carbon-for-ibm-dotcom/blob/main/packages/web-components/src/components/expressive-modal/expressive-modal.ts#L358](https://github.com//github.com/carbon-design-system/carbon-for-ibm-dotcom/blob/main/packages/web-components/src/components/expressive-modal/expressive-modal.ts/issues/L358) [#8913](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8913) [#8914](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8914) [#8915](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8915) +- **storybook:** fix cwc cdn link docs ([#10189](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10189)) ([8656e2e](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/8656e2e84bcb48a7fe6d00d6ae66e4830650a10d)) +- **tile:** fix expanable content visibility ([#10203](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10203)) ([a71b9f9](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/a71b9f9c74b854851511cad3de98f47aea46cc36)), closes [#10202](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10202) +- **tooltip:** adjust focus to div within tooltip-body ([#10217](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/10217)) ([9d4a326](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/9d4a326257c869ecf7d4d1288af99a9ef8373144)) + +# [1.25.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.25.0-rc.0...@carbon/web-components@1.25.0) (2023-02-28) + +**Note:** Version bump only for package @carbon/web-components + +# [1.25.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.24.0...@carbon/web-components@1.25.0-rc.0) (2023-02-10) + +**Note:** Version bump only for package @carbon/web-components + +# [1.24.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.24.0-rc.1...@carbon/web-components@1.24.0) (2023-01-31) + +**Note:** Version bump only for package @carbon/web-components + +# [1.24.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.24.0-rc.0...@carbon/web-components@1.24.0-rc.1) (2023-01-31) + +### Bug Fixes + +- **styles:** downgrade sass version as there is an issue with [@extend](https://github.com/extend) ([#9973](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9973)) ([8cff8a9](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/8cff8a9fb8b926dff5089497ea41a423c97d7e73)) + +# [1.24.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.23.0...@carbon/web-components@1.24.0-rc.0) (2023-01-25) + +### Bug Fixes + +- **bx-dropdown:** prevent interactivity while disabled ([#9881](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9881)) ([5fe8471](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/5fe84714b109b2cebb1cde06cf88eeb22da6baf5)), closes [#9754](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9754) +- **masthead:** update logo url protocol ([#9914](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9914)) ([ece8c04](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/ece8c0426bb222341b2ddd423498fcb9b899e7dc)), closes [#9567](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9567) +- **styles:** add missing styles for breadcrumb and modal ([#9942](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9942)) ([9a90ea1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/9a90ea15de00b182dd3795f820ef525cd1809a4e)), closes [#9936](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9936) [#9923](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9923) +- **tooltip:** close tooltip on escape or focusout ([#9871](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9871)) ([3fdd70e](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/3fdd70e85627fcf1d704b1dbb316771050ca6047)), closes [#8996](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/8996) + +### Features + +- **tile:** add custom event to `selected-tile` ([#9898](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9898)) ([11fe5bf](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/11fe5bfb03ded3c766e10245b03406c846bb03bd)), closes [#9740](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9740) + +# [1.23.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.23.0-rc.0...@carbon/web-components@1.23.0) (2023-01-17) + +**Note:** Version bump only for package @carbon/web-components + +# [1.23.0-rc.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.22.0...@carbon/web-components@1.23.0-rc.0) (2023-01-04) + +### Bug Fixes + +- **deps:** update dependency carbon-components to v10.58.3 ([#9849](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9849)) ([152eb57](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/152eb5739ef811336ffecc14faa8fda695d72ca6)) +- **deps:** update dependency flatpickr to v4.6.13 ([#9666](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9666)) ([7995814](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/79958142bd036972906dd1ba18458e4e4c192f56)) +- **notification/tag:** token documentation ([#9809](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9809)) ([f9e1b1c](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/f9e1b1c2d21a1f47bb068c98cb7fe5a09c3cee07)), closes [carbon-design-system/carbon-for-ibm-dotcom#9757](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9757) +- **progress-indicator:** add missing import for progress indicator skeleton ([#9853](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9853)) ([7b28a85](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/7b28a85d6ad7799c80b0865e3dd66b95da266bb7)), closes [#9825](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9825) +- **rollup:** update cwc rollup config ([#9854](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9854)) ([ca282b3](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/ca282b35c83f8d0efaef0d2a534fe7b8843a2728)) +- **tabs:** basic keyboard navigation ([#9811](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9811)) ([b785e61](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/b785e617602d27a11927398a495fb473d8efb43e)) +- **tooltip:** interpolate sass var ([#9880](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/issues/9880)) ([20cd1dc](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/20cd1dca7bb5fff5b9edc9eaa0e4d0ef1bd31e72)) + +# [1.22.0](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.22.0-rc.3...@carbon/web-components@1.22.0) (2022-12-06) + +**Note:** Version bump only for package @carbon/web-components + +# 1.22.0-rc.3 (2022-12-06) + +# 1.41.0-rc.2 (2022-12-05) + +# 1.41.0-rc.1 (2022-11-23) + +# 1.41.0-rc.0 (2022-11-22) + +### Bug Fixes + +- **cwc:** percy update ([5ac2674](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/5ac2674bdac3d7d033335c693e36a1ae33042242)) +- **cwc:** update package.json & karma test ([a52ab2f](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/a52ab2f5937d9576c79c63748065a1dcf03ee2b0)) +- **packages:** update versions to get working storybooks ([42d8eee](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/42d8eeee12c732c56599de24861252159e91905b)) + +# [1.22.0-rc.2](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.22.0-rc.1...@carbon/web-components@1.22.0-rc.2) (2022-12-05) + +**Note:** Version bump only for package @carbon/web-components + +# [1.22.0-rc.1](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/compare/@carbon/web-components@1.22.0-rc.0...@carbon/web-components@1.22.0-rc.1) (2022-11-23) + +**Note:** Version bump only for package @carbon/web-components + +# 1.22.0-rc.0 (2022-11-22) + +### Bug Fixes + +- **cwc:** percy update ([5ac2674](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/5ac2674bdac3d7d033335c693e36a1ae33042242)) +- **cwc:** update package.json & karma test ([a52ab2f](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/a52ab2f5937d9576c79c63748065a1dcf03ee2b0)) +- **packages:** update versions to get working storybooks ([42d8eee](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/commit/42d8eeee12c732c56599de24861252159e91905b)) diff --git a/packages/web-components/LICENSE b/packages/web-components/LICENSE new file mode 100644 index 000000000000..261eeb9e9f8b --- /dev/null +++ b/packages/web-components/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/web-components/README.md b/packages/web-components/README.md new file mode 100644 index 000000000000..46cdb63eaa6b --- /dev/null +++ b/packages/web-components/README.md @@ -0,0 +1,319 @@ +A Carbon Design System variant that's as easy to use as native HTML elements, +with no framework tax, no framework silo. + +

+ + Carbon Design System + +

+ +> Carbon is an open-source design system built by IBM. With the IBM Design +> Language as its foundation, the system consists of working code, design tools +> and resources, human interface guidelines, and a vibrant community of +> contributors. + +

+ + Carbon is released under the Apache-2.0 license + +

+

+ + This project is using Percy.io for visual regression testing + +

+ +# `@carbon/web-components` + +`@carbon/web-components` is a variant of Carbon Design System with Custom +Elements v1 and Shadow DOM v1 specs. + + + + +- [Getting started](#getting-started) + - [Using CDN](#using-cdn) + - [How to install](#how-to-install) + - [Basic usage](#basic-usage) + - [Using ES imports](#using-es-imports) + - [How to install](#how-to-install-1) + - [Basic usage](#basic-usage-1) + - [Other usage guides](#other-usage-guides) +- [JavaScript framework support](#javascript-framework-support) + - [Angular](#angular) + - [React](#react) + - [Vue](#vue) +- [Getting started with development](#getting-started-with-development) +- [Running React/Angular/Vue Storybook demo](#running-reactangularvue-storybook-demo) +- [List of available components](#list-of-available-components) +- [Browser support](#browser-support) +- [Coding conventions](#coding-conventions) +- [Creating build](#creating-build) +- [Running unit test](#running-unit-test) +- [Running build integration test](#running-build-integration-test) +- [Running UI integration test](#running-ui-integration-test) + + + +## Getting started + +### Using CDN + +#### How to install + +All components are available via CDN. This means that they can be added to your +application without the need of any bundler configuration. Each component is +available by the `latest` tag, or referencing a specific version (starting at +version `v1.16.0`): + +```html + + + + + +``` + +
+ See full list of available components via CDN + +- accordion.min.js +- breadcrumb.min.js +- button.min.js +- checkbox.min.js +- code-snippet.min.js +- combo-box.min.js +- content-switcher.min.js +- copy-button.min.js +- data-table.min.js +- date-picker.min.js +- dropdown.min.js +- file-uploader.min.js +- floating-menu.min.js +- form.min.js +- inline-loading.min.js +- input.min.js +- link.min.js +- list.min.js +- loading.min.js +- modal.min.js +- multi-select.min.js +- notification.min.js +- number-input.min.js +- overflow-menu.min.js +- pagination.min.js +- progress-indicator.min.js +- radio-button.min.js +- search.min.js +- select.min.js +- skeleton-icon.min.js +- skeleton-placeholder.min.js +- skeleton-text.min.js +- skip-to-content.min.js +- slider.min.js +- structured-list.min.js +- tabs.min.js +- tag.min.js +- textarea.min.js +- tile.min.js +- toggle.min.js +- tooltip.min.js +- ui-shell.min.js +
+ +#### Basic usage + +The CDN artifacts define the custom elements for the browser, so they can be +directly used once the script tag has been added to the page. For example: + +```html + + + + + + + +
+ + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + +
+ + +``` + +Our example at [CodeSandbox](https://codesandbox.io) shows usage with only CDN +artifacts: + +[![Edit carbon-web-components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/carbon-design-system/carbon-for-ibm-dotcom/tree/main/packages/carbon-web-components/examples/codesandbox/cdn) + +### Using ES imports + +#### How to install + +To install `@carbon/web-components` in your project, you will need to run the +following command using [npm](https://www.npmjs.com/): + +```bash +npm install --save @carbon/web-components +``` + +If you prefer [Yarn](https://yarnpkg.com/en/), use the following command +instead: + +```bash +yarn add @carbon/web-components +``` + +#### Basic usage + +Our example at [CodeSandbox](https://codesandbox.io) shows the most basic usage: + +[![Edit carbon-web-components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/carbon-design-system/carbon-for-ibm-dotcom/tree/main/packages/carbon-web-components/examples/codesandbox/basic) + +The first thing you need is **setting up a module bundler** to resolve +ECMAScript `import`s. The above example uses [Webpack](https://webpack.js.org), +but you can use other bundlers like [Rollup](https://rollupjs.org/) too. + +Once you set up a module bundler, you can start importing our component modules, +for example: + +```javascript +import '@carbon/web-components/es/components/dropdown/dropdown.js'; +import '@carbon/web-components/es/components/dropdown/dropdown-item.js'; +``` + +Once you've imported the component modules, you can use our components in the +same manner as native HTML tags, for example: + +```html + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + +``` + +### Other usage guides + +- [Having components participate in form](./docs/form.md) +- [Using custom styles in components](./docs/styling.md) +- [Using `carbon-web-components` with old build toolchain](./docs/old-build-toolchain.md) + +## JavaScript framework support + +This package also supports integration with other JavaScript frameworks like +Angular and Vue. This is achievable since Web Components is the modern browser +standard, and works well with other front-end frameworks that exist in the +application. In turn, this also comes with the benefits of encapsulation within +the Shadow DOM: + +### Angular + +Angular users can use our components in the same manner as native HTML tags, +too, once you add +[`CUSTOM_ELEMENTS_SCHEMA`](https://angular.io/api/core/CUSTOM_ELEMENTS_SCHEMA) +schema to your Angular module, for example: + +```javascript +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; + +@NgModule({ + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [AppComponent], + imports: [BrowserModule], + bootstrap: [AppComponent], +}) +export class AppModule {} +``` + +The `.d.ts` files in `@carbon/web-components` package are compiled with +TypeScript 3.7. You can use TypeScript 3.7 in your Angular application with +upcoming Angular `9.0` release, or with the following instructions, so your +application can use those `.d.ts` files: + +- Set `true` to + [`angularCompilerOptions.disableTypeScriptVersionCheck`](https://angular.io/guide/angular-compiler-options#disabletypescriptversioncheck) + in `tsconfig.json` +- In `polyfills.ts`, change + [`__importDefault` TypeScript helper](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#example-8) + as follows: + `window.__importDefault = mod => (mod?.__esModule ? mod : { default: mod })` + +### Vue + +[![Edit carbon-web-components with Vue](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/carbon-design-system/carbon-for-ibm-dotcom/tree/main/packages/carbon-web-components/examples/codesandbox/vue) + +Vue users can use our components in the same manner as native HTML tags, without +any additional steps! + +## Getting started with development + +1. Fork this repository and clone it +2. `yarn install` +3. `cd packages/carbon-web-components` +4. `yarn wca && yarn storybook` + +## List of available components + +View available web components at: +https://www.ibm.com/standards/carbon/carbon-web-components. You can see usage +information in several ways: + +1. Going to Docs tab, where it shows the usage and available attributes, + properties and custom events. +2. Clicking the **KNOBS** tab at the bottom and changing values there. Most + knobs are shown as something like `Button kind (kind)`, where `kind` is the + attribute name +3. Clicking the **ACTION LOGGER** tab at the bottom and interacting with the + selected component. You may see something like `cds-modal-closed` which + typically indicates that an event with such event type is fired. You can also + expand the twistie to see the details of the event + +## Browser support + +- Latest Chrome/Safari/FF + +## Coding conventions + +Can be found at [here](./src/coding-conventions.md). + +## Creating build + +``` +> yarn clean +> yarn build +``` + +You'll see the build artifacts in `/path/to/carbon-web-components/es` directory. + +## IBM Telemetry IBM Telemetry + +This package uses IBM Telemetry to collect metrics data. By installing this +package as a dependency you are agreeing to telemetry collection. To opt out, +see +[Opting out of IBM Telemetry data collection](https://github.com/ibm-telemetry/telemetry-js/tree/main#opting-out-of-ibm-telemetry-data-collection). +For more information on the data being collected, please see the +[IBM Telemetry documentation](https://github.com/ibm-telemetry/telemetry-js/tree/main#ibm-telemetry-collection-basics). diff --git a/packages/web-components/Staticfile b/packages/web-components/Staticfile new file mode 100644 index 000000000000..50d8902c17bc --- /dev/null +++ b/packages/web-components/Staticfile @@ -0,0 +1,2 @@ +root: storybook-static +force_https: true diff --git a/packages/web-components/carbon.yml b/packages/web-components/carbon.yml new file mode 100644 index 000000000000..a8df1597a2e0 --- /dev/null +++ b/packages/web-components/carbon.yml @@ -0,0 +1,581 @@ +# yaml-language-server: $schema=https://unpkg.com/@carbon-platform/schemas@v1/carbon-resources.schema.json +library: + id: carbon-web-components + name: Carbon Web Components + description: Build user interfaces with web components based on Carbon's React library. + externalDocsUrl: https://www.ibm.com/standards/web/carbon-for-ibm-dotcom + inherits: carbon-styles + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components + navData: + - title: Get started + path: 'https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/developing/frameworks/web-components.mdx' +assets: + accordion: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/accordion/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-accordion + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/accordion/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/accordion/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/accordion/accessibility.mdx + overviewPath: ./src/components/accordion/docs/overview.mdx + breadcrumb: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/breadcrumb/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-breadcrumb + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/breadcrumb/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/breadcrumb/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/breadcrumb/accessibility.mdx + overviewPath: ./src/components/breadcrumb/docs/overview.mdx + button: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/button/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-button + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/button/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/button/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/button/accessibility.mdx + overviewPath: ./src/components/button/docs/overview.mdx + checkbox: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/checkbox/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-checkbox + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/checkbox/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/checkbox/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/checkbox/accessibility.mdx + overviewPath: ./src/components/checkbox/docs/overview.mdx + code-snippet: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/code-snippet/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-code-snippet + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/code-snippet/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/code-snippet/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/code-snippet/accessibility.mdx + overviewPath: ./src/components/code-snippet/docs/overview.mdx + combo-box: + status: stable + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-combo-box + docs: + overviewPath: ./src/components/combo-box/docs/overview.mdx + content-switcher: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/content-switcher/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-content-switcher + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/content-switcher/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/content-switcher/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/content-switcher/accessibility.mdx + overviewPath: ./src/components/content-switcher/docs/overview.mdx + copy-button: + status: stable + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-copy-button + docs: + overviewPath: ./src/components/copy-button/docs/overview.mdx + data-table: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/data-table/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-data-table + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/data-table/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/data-table/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/data-table/accessibility.mdx + overviewPath: ./src/components/data-table/docs/overview.mdx + date-picker: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/date-picker/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-date-picker + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/date-picker/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/date-picker/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/date-picker/accessibility.mdx + overviewPath: ./src/components/date-picker/docs/overview.mdx + dropdown: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/dropdown/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-dropdown + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/dropdown/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/dropdown/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/dropdown/accessibility.mdx + overviewPath: ./src/components/dropdown/docs/overview.mdx + file-uploader: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/file-uploader/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-file-uploader + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/file-uploader/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/file-uploader/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/file-uploader/accessibility.mdx + overviewPath: ./src/components/file-uploader/docs/overview.mdx + icon: + name: Icon + framework: web-component + status: stable + type: component + platform: web + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-icon + thumbnailPath: "./thumbnails/icon.svg" + tags: + - media + - content-element + docs: + overviewPath: ./src/components/icon/docs/overview.mdx + inline-loading: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/inline-loading/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-inline-loading + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/inline-loading/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/inline-loading/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/inline-loading/accessibility.mdx + overviewPath: ./src/components/inline-loading/docs/overview.mdx + input: + name: Input + status: stable + type: component + framework: web-component + platform: web + thumbnailPath: "./thumbnails/input.svg" + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-input + tags: + - input-control + docs: + overviewPath: ./src/components/input/docs/overview.mdx + link: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/link/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-link + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/link/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/link/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/link/accessibility.mdx + overviewPath: ./src/components/link/docs/overview.mdx + list: + status: stable + externalDocsUrl: https://carbondesignsystem.com/components/list/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-list + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/list/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/list/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/list/accessibility.mdx + overviewPath: ./src/components/list/docs/overview.mdx + loading: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/loading/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-loading + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/loading/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/loading/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/loading/accessibility.mdx + overviewPath: ./src/components/loading/docs/overview.mdx + modal: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/modal/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-modal + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/modal/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/modal/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/modal/accessibility.mdx + overviewPath: ./src/components/modal/docs/overview.mdx + multiselect: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/dropdown/usage/#multiselect + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-multi-select + docs: + overviewPath: ./src/components/multi-select/docs/overview.mdx + notification: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/notification/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-notifications + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/notification/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/notification/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/notification/accessibility.mdx + overviewPath: ./src/components/notification/docs/overview.mdx + number-input: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/number-input/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-number-input + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/number-input/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/number-input/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/number-input/accessibility.mdx + overviewPath: ./src/components/number-input/docs/overview.mdx + overflow-menu: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/overflow-menu/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-overflow-menu + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/overflow-menu/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/overflow-menu/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/overflow-menu/accessibility.mdx + overviewPath: ./src/components/overflow-menu/docs/overview.mdx + pagination: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/pagination/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-pagination + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/pagination/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/pagination/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/pagination/accessibility.mdx + overviewPath: ./src/components/pagination/docs/overview.mdx + progress-indicator: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/progress-indicator/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-progress-indicator + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/progress-indicator/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/progress-indicator/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/progress-indicator/accessibility.mdx + overviewPath: ./src/components/progress-indicator/docs/overview.mdx + radio-button: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/radio-button/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-radio-button + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/radio-button/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/radio-button/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/radio-button/accessibility.mdx + overviewPath: ./src/components/radio-button/docs/overview.mdx + search: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/search/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-search + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/search/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/search/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/search/accessibility.mdx + overviewPath: ./src/components/search/docs/overview.mdx + select: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/select/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-select + tags: + - shell + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/select/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/select/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/select/accessibility.mdx + overviewPath: ./src/components/select/docs/overview.mdx + skeleton-placeholder: + name: Skeleton placeholder + status: stable + type: component + platform: web + framework: web-component + thumbnailPath: './thumbnails/skeleton-placeholder.svg' + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-skeleton-placeholder + tags: + - system-feedback + docs: + overviewPath: ./src/components/skeleton-placeholder/docs/overview.mdx + skeleton-text: + name: Skeleton text + status: stable + type: component + platform: web + framework: web-component + thumbnailPath: './thumbnails/skeleton-text.svg' + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-skeleton-text + tags: + - shell + docs: + overviewPath: ./src/components/skeleton-text/docs/overview.mdx + skip-to-content: + name: Skip to content + type: component + platform: web + status: stable + framework: web-component + thumbnailPath: './thumbnails/skip-to-content.svg' + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-skip-to-content + tags: + - contextual-navigation + docs: + overviewPath: ./src/components/skip-to-content/docs/overview.mdx + slider: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/slider/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-slider + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/slider/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/slider/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/slider/accessibility.mdx + overviewPath: ./src/components/slider/docs/overview.mdx + structured-list: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/structured-list/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-structured-list + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/structured-list/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/structured-list/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/structured-list/accessibility.mdx + overviewPath: ./src/components/structured-list/docs/overview.mdx + tabs: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/tabs/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-tabs + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tabs/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tabs/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tabs/accessibility.mdx + overviewPath: ./src/components/tabs/docs/overview.mdx + tag: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/tag/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-tag + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tag/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tag/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tag/accessibility.mdx + overviewPath: ./src/components/tag/docs/overview.mdx + text-area: + status: stable + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-textarea + docs: + overviewPath: ./src/components/textarea/docs/overview.mdx + tile: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/tile/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-tile + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tile/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tile/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tile/accessibility.mdx + overviewPath: ./src/components/tile/docs/overview.mdx + toggle: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/toggle/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-toggle + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/toggle/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/toggle/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/toggle/accessibility.mdx + overviewPath: ./src/components/toggle/docs/overview.mdx + tooltip: + status: stable + externalDocsUrl: https://www.carbondesignsystem.com/components/tooltip/usage + framework: web-component + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-tooltip + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tooltip/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tooltip/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/tooltip/accessibility.mdx + overviewPath: ./src/components/tooltip/docs/overview.mdx + ui-shell: + name: UI shell + type: component + platform: web + framework: web-component + thumbnailPath: './thumbnails/ui-shell.svg' + externalDocsUrl: https://www.carbondesignsystem.com/components/UI-shell-header/usage + status: stable + demoLinks: + - type: storybook + name: Storybook + action: link + url: https://www.ibm.com/standards/carbon/carbon-web-components/?path=/docs/components-ui-shell + tags: + - contextual-navigation + docs: + usagePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/UI-shell-header/usage.mdx + stylePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/UI-shell-header/style.mdx + accessibilityPath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/UI-shell-header/accessibility.mdx + codePath: https://github.com/carbon-design-system/carbon-website/blob/carbon-platform/src/pages/components/UI-shell-header/code.mdx + overviewPath: ./src/components/ui-shell/docs/overview.mdx diff --git a/packages/web-components/docs/carbon-cdn-style-helpers.mdx b/packages/web-components/docs/carbon-cdn-style-helpers.mdx new file mode 100644 index 000000000000..16089c8c520d --- /dev/null +++ b/packages/web-components/docs/carbon-cdn-style-helpers.mdx @@ -0,0 +1,342 @@ +import { Description, Meta } from '@storybook/blocks'; + + + +# Carbon CDN Style Helpers + +## Table of contents + +- [Overview](#overview) +- [Plex fonts and Carbon reset](#plex-fonts-and-carbon-reset) +- [Carbon grid](#carbon-grid) +- [Carbon theme zoning classes](#carbon-theme-zoning-classes) + - [Available classes](#available-classes) + - [Example usage](#example-usage) + + +## Overview + +In order to minimize the necessity of using front-end bundlers with the Carbon Web Components CDN artifacts, page level styles artifacts are also +available to use. + +If your application is not already compiling its own version of the below +artifacts, these can be included as part of your project. + +> NOTE: The latest/next tags are moving versions. While beneficial to +> always stay on the most recent version, it is recommended to choose a specific +> version and properly test your application when upgrading to a newer version. +> Check for latest version number on [npm](https://www.npmjs.com/package/@carbon/ibmdotcom-web-components). + +## Plex fonts and Carbon reset + +The following includes Carbon reset, as well as imports Plex fonts necessary for +the page. Note, this will import `IBM Plex Sans`, `IBM Plex Serif`, and `IBM Plex Mono`. + +```html +// SPECIFIC VERSION + + +// LATEST tag + + +// NEXT tag + +``` + +### Alternative: individual Plex family loading + +Plex fonts are also available as CSS artifacts, where the Plex font families can be loaded in individually. + +Available CSS files: + +| IBM Plex Mono (all) | https://1.www.s81c.com/common/carbon/plex/mono.css | +|---------------------------------|----------------------------------------------------------------------| +| IBM Plex Mono Bold | https://1.www.s81c.com/common/carbon/plex/mono-bold.css | +| IBM Plex Mono Bold Italic | https://1.www.s81c.com/common/carbon/plex/mono-bold-italic.css | +| IBM Plex Mono ExtraLight | https://1.www.s81c.com/common/carbon/plex/mono-extralight.css | +| IBM Plex Mono ExtraLight Italic | https://1.www.s81c.com/common/carbon/plex/mono-extralight-italic.css | +| IBM Plex Mono Italic | https://1.www.s81c.com/common/carbon/plex/mono-italic.css | +| IBM Plex Mono Light | https://1.www.s81c.com/common/carbon/plex/mono-light.css | +| IBM Plex Mono Light Italic | https://1.www.s81c.com/common/carbon/plex/mono-light-italic.css | +| IBM Plex Mono Medium | https://1.www.s81c.com/common/carbon/plex/mono-medium.css | +| IBM Plex Mono Medium Italic | https://1.www.s81c.com/common/carbon/plex/mono-medium-italic.css | +| IBM Plex Mono | https://1.www.s81c.com/common/carbon/plex/mono-regular.css | +| IBM Plex Mono SemiBold | https://1.www.s81c.com/common/carbon/plex/mono-semibold.css | +| IBM Plex Mono SemiBold Italic | https://1.www.s81c.com/common/carbon/plex/mono-semibold-italic.css | +| IBM Plex Mono Text | https://1.www.s81c.com/common/carbon/plex/mono-text.css | +| IBM Plex Mono Text Italic | https://1.www.s81c.com/common/carbon/plex/mono-text-italic.css | +| IBM Plex Mono Thin | https://1.www.s81c.com/common/carbon/plex/mono-thin.css | +| IBM Plex Mono Thin Italic | https://1.www.s81c.com/common/carbon/plex/mono-thin-italic.css | + +| IBM Plex Sans (all) | https://1.www.s81c.com/common/carbon/plex/sans.css | +|---------------------------------|----------------------------------------------------------------------| +| IBM Plex Sans Bold | https://1.www.s81c.com/common/carbon/plex/sans-bold.css | +| IBM Plex Sans Bold Italic | https://1.www.s81c.com/common/carbon/plex/sans-bold-italic.css | +| IBM Plex Sans ExtraLight | https://1.www.s81c.com/common/carbon/plex/sans-extralight.css | +| IBM Plex Sans ExtraLight Italic | https://1.www.s81c.com/common/carbon/plex/sans-extralight-italic.css | +| IBM Plex Sans Italic | https://1.www.s81c.com/common/carbon/plex/sans-italic.css | +| IBM Plex Sans Light | https://1.www.s81c.com/common/carbon/plex/sans-light.css | +| IBM Plex Sans Light Italic | https://1.www.s81c.com/common/carbon/plex/sans-light-italic.css | +| IBM Plex Sans Medium | https://1.www.s81c.com/common/carbon/plex/sans-medium.css | +| IBM Plex Sans Medium Italic | https://1.www.s81c.com/common/carbon/plex/sans-medium-italic.css | +| IBM Plex Sans | https://1.www.s81c.com/common/carbon/plex/sans-regular.css | +| IBM Plex Sans SemiBold | https://1.www.s81c.com/common/carbon/plex/sans-semibold.css | +| IBM Plex Sans SemiBold Italic | https://1.www.s81c.com/common/carbon/plex/sans-semibold-italic.css | +| IBM Plex Sans Text | https://1.www.s81c.com/common/carbon/plex/sans-text.css | +| IBM Plex Sans Text Italic | https://1.www.s81c.com/common/carbon/plex/sans-text-italic.css | +| IBM Plex Sans Thin | https://1.www.s81c.com/common/carbon/plex/sans-thin.css | +| IBM Plex Sans Thin Italic | https://1.www.s81c.com/common/carbon/plex/sans-thin-italic.css | + +| IBM Plex Sans Arabic (all) | https://1.www.s81c.com/common/carbon/plex/sans-arabic.css | +|---------------------------------|----------------------------------------------------------------------| +| IBM Plex Sans Arabic Bold | https://1.www.s81c.com/common/carbon/plex/sans-arabic-bold.css | +| IBM Plex Sans Arabic ExtraLight | https://1.www.s81c.com/common/carbon/plex/sans-arabic-extralight.css | +| IBM Plex Sans Arabic Light | https://1.www.s81c.com/common/carbon/plex/sans-arabic-light.css | +| IBM Plex Sans Arabic Medium | https://1.www.s81c.com/common/carbon/plex/sans-arabic-medium.css | +| IBM Plex Sans Arabic | https://1.www.s81c.com/common/carbon/plex/sans-arabic-regular.css | +| IBM Plex Sans Arabic SemiBold | https://1.www.s81c.com/common/carbon/plex/sans-arabic-semibold.css | +| IBM Plex Sans Arabic Text | https://1.www.s81c.com/common/carbon/plex/sans-arabic-text.css | +| IBM Plex Sans Arabic Thin | https://1.www.s81c.com/common/carbon/plex/sans-arabic-thin.css | + +| IBM Plex Sans Cond (all) | https://1.www.s81c.com/common/carbon/plex/sans-condensed.css | +|---------------------------------|--------------------------------------------------------------------------------| +| IBM Plex Sans Cond Bold | https://1.www.s81c.com/common/carbon/plex/sans-condensed-bold.css | +| IBM Plex Sans Cond Bold Italic | https://1.www.s81c.com/common/carbon/plex/sans-condensed-bold-italic.css | +| IBM Plex Sans Cond ExtLt | https://1.www.s81c.com/common/carbon/plex/sans-condensed-extralight.css | +| IBM Plex Sans Cond ExtLt Italic | https://1.www.s81c.com/common/carbon/plex/sans-condensed-extralight-italic.css | +| IBM Plex Sans Cond Italic | https://1.www.s81c.com/common/carbon/plex/sans-condensed-italic.css | +| IBM Plex Sans Cond Light | https://1.www.s81c.com/common/carbon/plex/sans-condensed-light.css | +| IBM Plex Sans Cond Light Italic | https://1.www.s81c.com/common/carbon/plex/sans-condensed-light-italic.css | +| IBM Plex Sans Cond Medm | https://1.www.s81c.com/common/carbon/plex/sans-condensed-medium.css | +| IBM Plex Sans Cond Medm Italic | https://1.www.s81c.com/common/carbon/plex/sans-condensed-medium-italic.css | +| IBM Plex Sans Cond | https://1.www.s81c.com/common/carbon/plex/sans-condensed-regular.css | +| IBM Plex Sans Cond SmBld | https://1.www.s81c.com/common/carbon/plex/sans-condensed-semibold.css | +| IBM Plex Sans Cond SmBld Italic | https://1.www.s81c.com/common/carbon/plex/sans-condensed-semibold-italic.css | +| IBM Plex Sans Cond Text | https://1.www.s81c.com/common/carbon/plex/sans-condensed-text.css | +| IBM Plex Sans Cond Text Italic | https://1.www.s81c.com/common/carbon/plex/sans-condensed-text-italic.css | +| IBM Plex Sans Cond Thin | https://1.www.s81c.com/common/carbon/plex/sans-condensed-thin.css | +| IBM Plex Sans Cond Thin Italic | https://1.www.s81c.com/common/carbon/plex/sans-condensed-thin-italic.css | + +| IBM Plex Sans Devanagari (all) | https://1.www.s81c.com/common/carbon/plex/sans-devanagari.css | +|-------------------------------------|--------------------------------------------------------------------------| +| IBM Plex Sans Devanagari Bold | https://1.www.s81c.com/common/carbon/plex/sans-devanagari-bold.css | +| IBM Plex Sans Devanagari ExtraLight | https://1.www.s81c.com/common/carbon/plex/sans-devanagari-extralight.css | +| IBM Plex Sans Devanagari Light | https://1.www.s81c.com/common/carbon/plex/sans-devanagari-light.css | +| IBM Plex Sans Devanagari Medium | https://1.www.s81c.com/common/carbon/plex/sans-devanagari-medium.css | +| IBM Plex Sans Devanagari | https://1.www.s81c.com/common/carbon/plex/sans-devanagari-regular.css | +| IBM Plex Sans Devanagari SemiBold | https://1.www.s81c.com/common/carbon/plex/sans-devanagari-semibold.css | +| IBM Plex Sans Devanagari Text | https://1.www.s81c.com/common/carbon/plex/sans-devanagari-text.css | +| IBM Plex Sans Devanagari Thin | https://1.www.s81c.com/common/carbon/plex/sans-devanagari-thin.css | + +| IBM Plex Sans Hebrew (all) | https://1.www.s81c.com/common/carbon/plex/sans-hebrew.css | +|---------------------------------|----------------------------------------------------------------------| +| IBM Plex Sans Hebrew Bold | https://1.www.s81c.com/common/carbon/plex/sans-hebrew-bold.css | +| IBM Plex Sans Hebrew ExtraLight | https://1.www.s81c.com/common/carbon/plex/sans-hebrew-extralight.css | +| IBM Plex Sans Hebrew Light | https://1.www.s81c.com/common/carbon/plex/sans-hebrew-light.css | +| IBM Plex Sans Hebrew Medium | https://1.www.s81c.com/common/carbon/plex/sans-hebrew-medium.css | +| IBM Plex Sans Hebrew | https://1.www.s81c.com/common/carbon/plex/sans-hebrew-regular.css | +| IBM Plex Sans Hebrew SemiBold | https://1.www.s81c.com/common/carbon/plex/sans-hebrew-semibold.css | +| IBM Plex Sans Hebrew Text | https://1.www.s81c.com/common/carbon/plex/sans-hebrew-text.css | +| IBM Plex Sans Hebrew Thin | https://1.www.s81c.com/common/carbon/plex/sans-hebrew-thin.css | + +| IBM Plex Sans JP (all) | https://1.www.s81c.com/common/carbon/plex/sans-jp.css | +|-----------------------------|------------------------------------------------------------------| +| IBM Plex Sans JP Bold | https://1.www.s81c.com/common/carbon/plex/sans-jp-bold.css | +| IBM Plex Sans JP ExtraLight | https://1.www.s81c.com/common/carbon/plex/sans-jp-extralight.css | +| IBM Plex Sans JP Light | https://1.www.s81c.com/common/carbon/plex/sans-jp-light.css | +| IBM Plex Sans JP Medium | https://1.www.s81c.com/common/carbon/plex/sans-jp-medium.css | +| IBM Plex Sans JP | https://1.www.s81c.com/common/carbon/plex/sans-jp-regular.css | +| IBM Plex Sans JP SemiBold | https://1.www.s81c.com/common/carbon/plex/sans-jp-semibold.css | +| IBM Plex Sans JP Text | https://1.www.s81c.com/common/carbon/plex/sans-jp-text.css | +| IBM Plex Sans JP Thin | https://1.www.s81c.com/common/carbon/plex/sans-jp-thin.css | + +| IBM Plex Sans KR (all) | https://1.www.s81c.com/common/carbon/plex/sans-kr.css | +|-----------------------------|------------------------------------------------------------------| +| IBM Plex Sans KR Bold | https://1.www.s81c.com/common/carbon/plex/sans-kr-bold.css | +| IBM Plex Sans KR ExtraLight | https://1.www.s81c.com/common/carbon/plex/sans-kr-extralight.css | +| IBM Plex Sans KR Light | https://1.www.s81c.com/common/carbon/plex/sans-kr-light.css | +| IBM Plex Sans KR Medium | https://1.www.s81c.com/common/carbon/plex/sans-kr-medium.css | +| IBM Plex Sans KR | https://1.www.s81c.com/common/carbon/plex/sans-kr-regular.css | +| IBM Plex Sans KR SemiBold | https://1.www.s81c.com/common/carbon/plex/sans-kr-semibold.css | +| IBM Plex Sans KR Text | https://1.www.s81c.com/common/carbon/plex/sans-kr-text.css | +| IBM Plex Sans KR Thin | https://1.www.s81c.com/common/carbon/plex/sans-kr-thin.css | + +| IBM Plex Sans Thai (all) | https://1.www.s81c.com/common/carbon/plex/sans-thai.css | +|-------------------------------|--------------------------------------------------------------------| +| IBM Plex Sans Thai Bold | https://1.www.s81c.com/common/carbon/plex/sans-thai-bold.css | +| IBM Plex Sans Thai ExtraLight | https://1.www.s81c.com/common/carbon/plex/sans-thai-extralight.css | +| IBM Plex Sans Thai Light | https://1.www.s81c.com/common/carbon/plex/sans-thai-light.css | +| IBM Plex Sans Thai Medium | https://1.www.s81c.com/common/carbon/plex/sans-thai-medium.css | +| IBM Plex Sans Thai | https://1.www.s81c.com/common/carbon/plex/sans-thai-regular.css | +| IBM Plex Sans Thai SemiBold | https://1.www.s81c.com/common/carbon/plex/sans-thai-semibold.css | +| IBM Plex Sans Thai Text | https://1.www.s81c.com/common/carbon/plex/sans-thai-text.css | +| IBM Plex Sans Thai Thin | https://1.www.s81c.com/common/carbon/plex/sans-thai-thin.css | + +| IBM Plex Sans Thai Looped (all) | https://1.www.s81c.com/common/carbon/plex/sans-thai-looped.css | +|--------------------------------------|---------------------------------------------------------------------------| +| IBM Plex Sans Thai Looped Bold | https://1.www.s81c.com/common/carbon/plex/sans-thai-looped-bold.css | +| IBM Plex Sans Thai Looped ExtraLight | https://1.www.s81c.com/common/carbon/plex/sans-thai-looped-extralight.css | +| IBM Plex Sans Thai Looped Light | https://1.www.s81c.com/common/carbon/plex/sans-thai-looped-light.css | +| IBM Plex Sans Thai Looped Medium | https://1.www.s81c.com/common/carbon/plex/sans-thai-looped-medium.css | +| IBM Plex Sans Thai Looped | https://1.www.s81c.com/common/carbon/plex/sans-thai-looped-regular.css | +| IBM Plex Sans Thai Looped SemiBold | https://1.www.s81c.com/common/carbon/plex/sans-thai-looped-semibold.css | +| IBM Plex Sans Thai Looped Text | https://1.www.s81c.com/common/carbon/plex/sans-thai-looped-text.css | +| IBM Plex Sans Thai Looped Thin | https://1.www.s81c.com/common/carbon/plex/sans-thai-looped-thin.css | + +| IBM Plex Serif (all) | https://1.www.s81c.com/common/carbon/plex/serif.css | +|-----------------------------|-----------------------------------------------------------------------| +| IBM Plex Serif Bold | https://1.www.s81c.com/common/carbon/plex/serif-bold.css | +| IBM Plex Serif Bold Italic | https://1.www.s81c.com/common/carbon/plex/serif-bold-italic.css | +| IBM Plex Serif ExtLt | https://1.www.s81c.com/common/carbon/plex/serif-extralight.css | +| IBM Plex Serif ExtLt Italic | https://1.www.s81c.com/common/carbon/plex/serif-extralight-italic.css | +| IBM Plex Serif Italic | https://1.www.s81c.com/common/carbon/plex/serif-italic.css | +| IBM Plex Serif Light | https://1.www.s81c.com/common/carbon/plex/serif-light.css | +| IBM Plex Serif Light Italic | https://1.www.s81c.com/common/carbon/plex/serif-light-italic.css | +| IBM Plex Serif Medm | https://1.www.s81c.com/common/carbon/plex/serif-medium.css | +| IBM Plex Serif Medm Italic | https://1.www.s81c.com/common/carbon/plex/serif-medium-italic.css | +| IBM Plex Serif | https://1.www.s81c.com/common/carbon/plex/serif-regular.css | +| IBM Plex Serif SmBld | https://1.www.s81c.com/common/carbon/plex/serif-semibold.css | +| IBM Plex Serif SmBld Italic | https://1.www.s81c.com/common/carbon/plex/serif-semibold-italic.css | +| IBM Plex Serif Text | https://1.www.s81c.com/common/carbon/plex/serif-text.css | +| IBM Plex Serif Text Italic | https://1.www.s81c.com/common/carbon/plex/serif-text-italic.css | +| IBM Plex Serif Thin | https://1.www.s81c.com/common/carbon/plex/serif-thin.css | +| IBM Plex Serif Thin Italic | https://1.www.s81c.com/common/carbon/plex/serif-thin-italic.css | + +And the full plex package (excluding `jp` and `kr`): + +- https://1.www.s81c.com/common/carbon/plex/plex-full.css + +Example usage: + +```html + + + + + ... + + +... + + +``` + +### Non-latin dynamic font loader + +A dynamic font loader for non-Latin fonts is available, called `load-non-latin-plex`. This utility is +available at the following CDN url: + +- https://1.www.s81c.com/common/carbon/plex/load-non-latin-plex.js + +Usage: + +```html + +``` + +Note, this script loads in the font based on the detected 2-character language code in the `window.digitalData` object. + +For more details, visit: https://www.ibm.com/standards/carbon/developing/building-for-ibm-dotcom/#page-language + + +## Carbon grid + +The following includes Carbon grid (using flex grid) and all corresponding grid classes. + +```html +// SPECIFIC VERSION + + +// LATEST tag + + +// NEXT tag + +``` + +The following includes Carbon grid (using CSS grid) and all corresponding grid classes. + +```html +// SPECIFIC VERSION + + +// LATEST tag + + +// NEXT tag + +``` + +[Learn more about the Carbon 2x Grid](https://carbondesignsystem.com/guidelines/2x-grid/overview) + +## Carbon theme zoning classes + +The following includes classes for creating Carbon theme zones (white, g10, g90, +g100). Note that these classes take advantage of using CSS Custom Properties enabled +in Carbon. + +```html +// SPECIFIC VERSION + + +// LATEST tag + + +// NEXT tag + +``` + +### Available classes + +| Theme | Class name | +| ------ | ----------------------- | +| white | `.cds-theme-zone-white` | +| g10 | `.cds-theme-zone-g10` | +| g90 | `.cds-theme-zone-g90` | +| g100 | `.cds-theme-zone-g100` | + +### Example usage + +```html + + + + + + + + ... + + + + Foo + Bar + Baz + +
+ button + + This is a tag + +
+ + + +``` + diff --git a/packages/web-components/docs/form.md b/packages/web-components/docs/form.md new file mode 100644 index 000000000000..87abe2a7a009 --- /dev/null +++ b/packages/web-components/docs/form.md @@ -0,0 +1,34 @@ +# Having components participate in form + +Though form elements in `@carbon/web-components` (e.g. ``) are +not native form elements like ``, they have some extra APIs that align +well with web/framework standards. + +## `formdata` event + +Browsers supporting +[`formdata` event](https://www.chromestatus.com/feature/5662230242656256) fire +that event when the user clicks on ` + +
+

Available storage

+

+ This server has 150 GB of block storage remaining. +

+
+
+ + + +
+ + Toggletip label + +

+ Occassionally, services are updated in a specified time window to + ensure no down time for customers. +

+ Test + Button +
+
+ +
+ + + + Occassionally, services are updated in a specified time window to + ensure no down time for customers. + + +
+ +
+ +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed + do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+
+
+ + + + diff --git a/packages/web-components/examples/autoalign/index.html b/packages/web-components/examples/autoalign/index.html new file mode 100644 index 000000000000..aaa8c32399d3 --- /dev/null +++ b/packages/web-components/examples/autoalign/index.html @@ -0,0 +1,145 @@ + + + + + @carbon/web-components autoalign example + + + + + + + + +
+ + + +
+

Available storage

+

+ This server has 150 GB of block storage remaining. +

+
+
+
+
+ +
+ + Toggletip label + +

+ Occassionally, services are updated in a specified time window to + ensure no down time for customers. +

+ Test + Button +
+
+ +
+ + + + Occassionally, services are updated in a specified time window to + ensure no down time for customers. + + +
+ +
+ +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed + do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+
+
+ + + + diff --git a/packages/web-components/examples/autoalign/package.json b/packages/web-components/examples/autoalign/package.json new file mode 100644 index 000000000000..cde67581b2bc --- /dev/null +++ b/packages/web-components/examples/autoalign/package.json @@ -0,0 +1,21 @@ +{ + "name": "carbon-web-components-autoalign-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.51.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/autoalign/sandbox.config.json b/packages/web-components/examples/autoalign/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/autoalign/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/autoalign/src/index.js b/packages/web-components/examples/autoalign/src/index.js new file mode 100644 index 000000000000..d091351152ff --- /dev/null +++ b/packages/web-components/examples/autoalign/src/index.js @@ -0,0 +1,14 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import "@carbon/web-components/es/components/slug/index.js"; +import "@carbon/web-components/es/components/popover/index.js"; +import "@carbon/web-components/es/components/toggle-tip/index.js"; +import "@carbon/web-components/es/components/tooltip/index.js"; +import "@carbon/web-components/es/components/button/index.js"; diff --git a/packages/web-components/examples/autoalign/src/styles.scss b/packages/web-components/examples/autoalign/src/styles.scss new file mode 100644 index 000000000000..61f9fcc39d6e --- /dev/null +++ b/packages/web-components/examples/autoalign/src/styles.scss @@ -0,0 +1,62 @@ +/** + * @license + * + * Copyright IBM Corp. 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +@use "@carbon/styles/scss/reset"; +@use "@carbon/styles/scss/theme"; +@use "@carbon/styles/scss/themes"; +@use "@carbon/styles/scss/type"; +@use "@carbon/styles/scss/spacing" as *; +@use "@carbon/styles/scss/utilities/button-reset"; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} + +.section { + display: flex; + align-items: center; + justify-content: center; + margin: 6rem 0; +} + +.p-3 { + padding: $spacing-05; +} + +.popover-title { + @include type.type-style("heading-compact-01"); + + margin-block-end: $spacing-01; +} + +.popover-details { + @include type.type-style("body-compact-01"); +} + +.playground-trigger { + display: flex; + align-items: center; + justify-content: center; + border: 1px solid theme.$border-subtle; + block-size: $spacing-07; + inline-size: $spacing-07; +} + +.sb-tooltip-trigger { + @include button-reset.reset(); + + display: flex; + align-items: center; + justify-content: center; + border: 1px solid theme.$border-subtle; + block-size: $spacing-07; + inline-size: $spacing-07; +} diff --git a/packages/web-components/examples/autoalign/vite.config.js b/packages/web-components/examples/autoalign/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/autoalign/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/accordion/.gitignore b/packages/web-components/examples/components/accordion/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/accordion/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/accordion/.sassrc b/packages/web-components/examples/components/accordion/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/accordion/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/accordion/cdn.html b/packages/web-components/examples/components/accordion/cdn.html new file mode 100644 index 000000000000..4b9c278c0ffe --- /dev/null +++ b/packages/web-components/examples/components/accordion/cdn.html @@ -0,0 +1,62 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad + minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

+
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad + minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

+
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad + minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

+
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad + minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

+
+
+ + diff --git a/packages/web-components/examples/components/accordion/index.html b/packages/web-components/examples/components/accordion/index.html new file mode 100644 index 000000000000..0c28ddd2a877 --- /dev/null +++ b/packages/web-components/examples/components/accordion/index.html @@ -0,0 +1,62 @@ + + + + + carbon-web-components example + + + + + + + + + + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad + minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

+
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad + minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

+
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad + minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

+
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad + minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

+
+
+ + diff --git a/packages/web-components/examples/components/accordion/package.json b/packages/web-components/examples/components/accordion/package.json new file mode 100644 index 000000000000..33a24618c517 --- /dev/null +++ b/packages/web-components/examples/components/accordion/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-accordion-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/accordion/sandbox.config.json b/packages/web-components/examples/components/accordion/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/accordion/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/accordion/src/index.js b/packages/web-components/examples/components/accordion/src/index.js new file mode 100644 index 000000000000..9131b90d7452 --- /dev/null +++ b/packages/web-components/examples/components/accordion/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/accordion/index.js'; diff --git a/packages/web-components/examples/components/accordion/src/styles.scss b/packages/web-components/examples/components/accordion/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/accordion/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/accordion/vite.config.js b/packages/web-components/examples/components/accordion/vite.config.js new file mode 100644 index 000000000000..e4af9f51b170 --- /dev/null +++ b/packages/web-components/examples/components/accordion/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/ai-skeleton/.gitignore b/packages/web-components/examples/components/ai-skeleton/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/ai-skeleton/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/ai-skeleton/.sassrc b/packages/web-components/examples/components/ai-skeleton/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/ai-skeleton/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/ai-skeleton/cdn.html b/packages/web-components/examples/components/ai-skeleton/cdn.html new file mode 100644 index 000000000000..03f87e04b0f2 --- /dev/null +++ b/packages/web-components/examples/components/ai-skeleton/cdn.html @@ -0,0 +1,32 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/ai-skeleton/index.html b/packages/web-components/examples/components/ai-skeleton/index.html new file mode 100644 index 000000000000..ea2a4d13975d --- /dev/null +++ b/packages/web-components/examples/components/ai-skeleton/index.html @@ -0,0 +1,31 @@ + + + + + carbon-web-components example + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/ai-skeleton/package.json b/packages/web-components/examples/components/ai-skeleton/package.json new file mode 100644 index 000000000000..b84d57ea8ae9 --- /dev/null +++ b/packages/web-components/examples/components/ai-skeleton/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-ai-skeleton-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/ai-skeleton/sandbox.config.json b/packages/web-components/examples/components/ai-skeleton/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/ai-skeleton/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/ai-skeleton/src/index.js b/packages/web-components/examples/components/ai-skeleton/src/index.js new file mode 100644 index 000000000000..ff6159edf794 --- /dev/null +++ b/packages/web-components/examples/components/ai-skeleton/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/ai-skeleton/index.js'; diff --git a/packages/web-components/examples/components/ai-skeleton/src/styles.scss b/packages/web-components/examples/components/ai-skeleton/src/styles.scss new file mode 100644 index 000000000000..2183124956e2 --- /dev/null +++ b/packages/web-components/examples/components/ai-skeleton/src/styles.scss @@ -0,0 +1,18 @@ +/** + * @license + * + * Copyright IBM Corp. 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/ai-skeleton/vite.config.js b/packages/web-components/examples/components/ai-skeleton/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/ai-skeleton/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/breadcrumb/.gitignore b/packages/web-components/examples/components/breadcrumb/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/breadcrumb/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/breadcrumb/.sassrc b/packages/web-components/examples/components/breadcrumb/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/breadcrumb/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/breadcrumb/cdn.html b/packages/web-components/examples/components/breadcrumb/cdn.html new file mode 100644 index 000000000000..395388a22d36 --- /dev/null +++ b/packages/web-components/examples/components/breadcrumb/cdn.html @@ -0,0 +1,42 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + Breadcrumb 1 + + + Breadcrumb 2 + + + Breadcrumb 3 + + + Breadcrumb 4 + + + + diff --git a/packages/web-components/examples/components/breadcrumb/index.html b/packages/web-components/examples/components/breadcrumb/index.html new file mode 100644 index 000000000000..2122648ea02a --- /dev/null +++ b/packages/web-components/examples/components/breadcrumb/index.html @@ -0,0 +1,42 @@ + + + + + carbon-web-components example + + + + + + + + + + + Breadcrumb 1 + + + Breadcrumb 2 + + + Breadcrumb 3 + + + Breadcrumb 4 + + + + diff --git a/packages/web-components/examples/components/breadcrumb/package.json b/packages/web-components/examples/components/breadcrumb/package.json new file mode 100644 index 000000000000..317385c8e45d --- /dev/null +++ b/packages/web-components/examples/components/breadcrumb/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-breadcrumb-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/breadcrumb/sandbox.config.json b/packages/web-components/examples/components/breadcrumb/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/breadcrumb/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/breadcrumb/src/index.js b/packages/web-components/examples/components/breadcrumb/src/index.js new file mode 100644 index 000000000000..74bd526e58a3 --- /dev/null +++ b/packages/web-components/examples/components/breadcrumb/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/breadcrumb/index.js'; diff --git a/packages/web-components/examples/components/breadcrumb/src/styles.scss b/packages/web-components/examples/components/breadcrumb/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/breadcrumb/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/breadcrumb/vite.config.js b/packages/web-components/examples/components/breadcrumb/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/breadcrumb/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/button/.gitignore b/packages/web-components/examples/components/button/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/button/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/button/.sassrc b/packages/web-components/examples/components/button/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/button/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/button/cdn.html b/packages/web-components/examples/components/button/cdn.html new file mode 100644 index 000000000000..ab44f84655df --- /dev/null +++ b/packages/web-components/examples/components/button/cdn.html @@ -0,0 +1,31 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + Button + + + diff --git a/packages/web-components/examples/components/button/index.html b/packages/web-components/examples/components/button/index.html new file mode 100644 index 000000000000..4a222327a1dd --- /dev/null +++ b/packages/web-components/examples/components/button/index.html @@ -0,0 +1,31 @@ + + + + + carbon-web-components example + + + + + + + + + + Button + + + diff --git a/packages/web-components/examples/components/button/package.json b/packages/web-components/examples/components/button/package.json new file mode 100644 index 000000000000..f791b0f177f8 --- /dev/null +++ b/packages/web-components/examples/components/button/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-button-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/button/sandbox.config.json b/packages/web-components/examples/components/button/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/button/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/button/src/index.js b/packages/web-components/examples/components/button/src/index.js new file mode 100644 index 000000000000..f2d6d95e02fa --- /dev/null +++ b/packages/web-components/examples/components/button/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/button/index.js'; diff --git a/packages/web-components/examples/components/button/src/styles.scss b/packages/web-components/examples/components/button/src/styles.scss new file mode 100644 index 000000000000..d34691ef7773 --- /dev/null +++ b/packages/web-components/examples/components/button/src/styles.scss @@ -0,0 +1,13 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +@use '@carbon/styles/scss/components/button/tokens' as button-tokens; +@include theme.add-component-tokens(button-tokens.$button-tokens); + + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/button/vite.config.js b/packages/web-components/examples/components/button/vite.config.js new file mode 100644 index 000000000000..e4af9f51b170 --- /dev/null +++ b/packages/web-components/examples/components/button/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/chat-button/.gitignore b/packages/web-components/examples/components/chat-button/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/chat-button/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/chat-button/.sassrc b/packages/web-components/examples/components/chat-button/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/chat-button/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/chat-button/cdn.html b/packages/web-components/examples/components/chat-button/cdn.html new file mode 100644 index 000000000000..e26909ed64d3 --- /dev/null +++ b/packages/web-components/examples/components/chat-button/cdn.html @@ -0,0 +1,31 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + Chat button + + + diff --git a/packages/web-components/examples/components/chat-button/index.html b/packages/web-components/examples/components/chat-button/index.html new file mode 100644 index 000000000000..6d2054b64056 --- /dev/null +++ b/packages/web-components/examples/components/chat-button/index.html @@ -0,0 +1,31 @@ + + + + + carbon-web-components example + + + + + + + + + + Chat button + + + diff --git a/packages/web-components/examples/components/chat-button/package.json b/packages/web-components/examples/components/chat-button/package.json new file mode 100644 index 000000000000..a08e45a88c14 --- /dev/null +++ b/packages/web-components/examples/components/chat-button/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-chat-button-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/chat-button/sandbox.config.json b/packages/web-components/examples/components/chat-button/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/chat-button/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/chat-button/src/index.js b/packages/web-components/examples/components/chat-button/src/index.js new file mode 100644 index 000000000000..3720c0adf1c4 --- /dev/null +++ b/packages/web-components/examples/components/chat-button/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/chat-button/index.js'; diff --git a/packages/web-components/examples/components/chat-button/src/styles.scss b/packages/web-components/examples/components/chat-button/src/styles.scss new file mode 100644 index 000000000000..0adba98beda4 --- /dev/null +++ b/packages/web-components/examples/components/chat-button/src/styles.scss @@ -0,0 +1,22 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +@use '@carbon/styles/scss/components/button/tokens' as button-tokens; +@include theme.add-component-tokens(button-tokens.$button-tokens); + + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/chat-button/vite.config.js b/packages/web-components/examples/components/chat-button/vite.config.js new file mode 100644 index 000000000000..e4af9f51b170 --- /dev/null +++ b/packages/web-components/examples/components/chat-button/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/checkbox/.gitignore b/packages/web-components/examples/components/checkbox/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/checkbox/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/checkbox/.sassrc b/packages/web-components/examples/components/checkbox/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/checkbox/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/checkbox/cdn.html b/packages/web-components/examples/components/checkbox/cdn.html new file mode 100644 index 000000000000..9353f60da595 --- /dev/null +++ b/packages/web-components/examples/components/checkbox/cdn.html @@ -0,0 +1,29 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + Lorem Ipsum + + diff --git a/packages/web-components/examples/components/checkbox/index.html b/packages/web-components/examples/components/checkbox/index.html new file mode 100644 index 000000000000..1ab440fed16a --- /dev/null +++ b/packages/web-components/examples/components/checkbox/index.html @@ -0,0 +1,29 @@ + + + + + carbon-web-components example + + + + + + + + + Lorem Ipsum + + diff --git a/packages/web-components/examples/components/checkbox/package.json b/packages/web-components/examples/components/checkbox/package.json new file mode 100644 index 000000000000..e4390741cfef --- /dev/null +++ b/packages/web-components/examples/components/checkbox/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-checkbox-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/checkbox/sandbox.config.json b/packages/web-components/examples/components/checkbox/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/checkbox/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/checkbox/src/index.js b/packages/web-components/examples/components/checkbox/src/index.js new file mode 100644 index 000000000000..b365548d7515 --- /dev/null +++ b/packages/web-components/examples/components/checkbox/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/checkbox/index.js'; diff --git a/packages/web-components/examples/components/checkbox/src/styles.scss b/packages/web-components/examples/components/checkbox/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/checkbox/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/checkbox/vite.config.js b/packages/web-components/examples/components/checkbox/vite.config.js new file mode 100644 index 000000000000..e4af9f51b170 --- /dev/null +++ b/packages/web-components/examples/components/checkbox/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/code-snippet/.gitignore b/packages/web-components/examples/components/code-snippet/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/code-snippet/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/code-snippet/.sassrc b/packages/web-components/examples/components/code-snippet/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/code-snippet/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/code-snippet/cdn.html b/packages/web-components/examples/components/code-snippet/cdn.html new file mode 100644 index 000000000000..47c72e224582 --- /dev/null +++ b/packages/web-components/examples/components/code-snippet/cdn.html @@ -0,0 +1,33 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + node -v Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, veritatis voluptate id incidunt molestiae + officia possimus, quasi itaque alias, architecto hic, dicta fugit? Debitis delectus quidem explicabo vitae + laboriosam! + + + diff --git a/packages/web-components/examples/components/code-snippet/index.html b/packages/web-components/examples/components/code-snippet/index.html new file mode 100644 index 000000000000..16e9c6c0596d --- /dev/null +++ b/packages/web-components/examples/components/code-snippet/index.html @@ -0,0 +1,33 @@ + + + + + carbon-web-components example + + + + + + + + + + node -v Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, veritatis voluptate id incidunt molestiae + officia possimus, quasi itaque alias, architecto hic, dicta fugit? Debitis delectus quidem explicabo vitae + laboriosam! + + + diff --git a/packages/web-components/examples/components/code-snippet/package.json b/packages/web-components/examples/components/code-snippet/package.json new file mode 100644 index 000000000000..df6e1f63f0c8 --- /dev/null +++ b/packages/web-components/examples/components/code-snippet/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-code-snippet-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/code-snippet/sandbox.config.json b/packages/web-components/examples/components/code-snippet/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/code-snippet/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/code-snippet/src/index.js b/packages/web-components/examples/components/code-snippet/src/index.js new file mode 100644 index 000000000000..5726d23f9055 --- /dev/null +++ b/packages/web-components/examples/components/code-snippet/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/code-snippet/index.js'; diff --git a/packages/web-components/examples/components/code-snippet/src/styles.scss b/packages/web-components/examples/components/code-snippet/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/code-snippet/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/code-snippet/vite.config.js b/packages/web-components/examples/components/code-snippet/vite.config.js new file mode 100644 index 000000000000..e4af9f51b170 --- /dev/null +++ b/packages/web-components/examples/components/code-snippet/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/combo-box/.gitignore b/packages/web-components/examples/components/combo-box/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/combo-box/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/combo-box/.sassrc b/packages/web-components/examples/components/combo-box/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/combo-box/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/combo-box/cdn.html b/packages/web-components/examples/components/combo-box/cdn.html new file mode 100644 index 000000000000..851575cc8247 --- /dev/null +++ b/packages/web-components/examples/components/combo-box/cdn.html @@ -0,0 +1,42 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + Option 6 + Option 7 + Option 8 + + + diff --git a/packages/web-components/examples/components/combo-box/index.html b/packages/web-components/examples/components/combo-box/index.html new file mode 100644 index 000000000000..d9768d9e875d --- /dev/null +++ b/packages/web-components/examples/components/combo-box/index.html @@ -0,0 +1,42 @@ + + + + + carbon-web-components example + + + + + + + + + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + Option 6 + Option 7 + Option 8 + + + diff --git a/packages/web-components/examples/components/combo-box/package.json b/packages/web-components/examples/components/combo-box/package.json new file mode 100644 index 000000000000..f35fe562e649 --- /dev/null +++ b/packages/web-components/examples/components/combo-box/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-combo-box-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/combo-box/sandbox.config.json b/packages/web-components/examples/components/combo-box/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/combo-box/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/combo-box/src/index.js b/packages/web-components/examples/components/combo-box/src/index.js new file mode 100644 index 000000000000..f8b60a617a5f --- /dev/null +++ b/packages/web-components/examples/components/combo-box/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/combo-box/index.js'; diff --git a/packages/web-components/examples/components/combo-box/src/styles.scss b/packages/web-components/examples/components/combo-box/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/combo-box/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/combo-box/vite.config.js b/packages/web-components/examples/components/combo-box/vite.config.js new file mode 100644 index 000000000000..e4af9f51b170 --- /dev/null +++ b/packages/web-components/examples/components/combo-box/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/content-switcher/.gitignore b/packages/web-components/examples/components/content-switcher/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/content-switcher/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/content-switcher/.sassrc b/packages/web-components/examples/components/content-switcher/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/content-switcher/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/content-switcher/cdn.html b/packages/web-components/examples/components/content-switcher/cdn.html new file mode 100644 index 000000000000..08ab715ab5e7 --- /dev/null +++ b/packages/web-components/examples/components/content-switcher/cdn.html @@ -0,0 +1,35 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + + + diff --git a/packages/web-components/examples/components/content-switcher/index.html b/packages/web-components/examples/components/content-switcher/index.html new file mode 100644 index 000000000000..4fd9e304a33f --- /dev/null +++ b/packages/web-components/examples/components/content-switcher/index.html @@ -0,0 +1,35 @@ + + + + + carbon-web-components example + + + + + + + + + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + + + diff --git a/packages/web-components/examples/components/content-switcher/package.json b/packages/web-components/examples/components/content-switcher/package.json new file mode 100644 index 000000000000..1adc0c53255a --- /dev/null +++ b/packages/web-components/examples/components/content-switcher/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-content-switcher-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/content-switcher/sandbox.config.json b/packages/web-components/examples/components/content-switcher/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/content-switcher/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/content-switcher/src/index.js b/packages/web-components/examples/components/content-switcher/src/index.js new file mode 100644 index 000000000000..cb4eafe5991b --- /dev/null +++ b/packages/web-components/examples/components/content-switcher/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/content-switcher/index.js'; diff --git a/packages/web-components/examples/components/content-switcher/src/styles.scss b/packages/web-components/examples/components/content-switcher/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/content-switcher/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/content-switcher/vite.config.js b/packages/web-components/examples/components/content-switcher/vite.config.js new file mode 100644 index 000000000000..e4af9f51b170 --- /dev/null +++ b/packages/web-components/examples/components/content-switcher/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/copy-button/.gitignore b/packages/web-components/examples/components/copy-button/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/copy-button/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/copy-button/.sassrc b/packages/web-components/examples/components/copy-button/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/copy-button/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/copy-button/cdn.html b/packages/web-components/examples/components/copy-button/cdn.html new file mode 100644 index 000000000000..870457ed1da0 --- /dev/null +++ b/packages/web-components/examples/components/copy-button/cdn.html @@ -0,0 +1,31 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + Copy to Clipboard + + + diff --git a/packages/web-components/examples/components/copy-button/index.html b/packages/web-components/examples/components/copy-button/index.html new file mode 100644 index 000000000000..29b6be78b981 --- /dev/null +++ b/packages/web-components/examples/components/copy-button/index.html @@ -0,0 +1,31 @@ + + + + + carbon-web-components example + + + + + + + + + + Copy to Clipboard! + + + diff --git a/packages/web-components/examples/components/copy-button/package.json b/packages/web-components/examples/components/copy-button/package.json new file mode 100644 index 000000000000..e07f70164b8c --- /dev/null +++ b/packages/web-components/examples/components/copy-button/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-copy-button-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/copy-button/sandbox.config.json b/packages/web-components/examples/components/copy-button/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/copy-button/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/copy-button/src/index.js b/packages/web-components/examples/components/copy-button/src/index.js new file mode 100644 index 000000000000..660f88613c7d --- /dev/null +++ b/packages/web-components/examples/components/copy-button/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/copy-button/index.js'; diff --git a/packages/web-components/examples/components/copy-button/src/styles.scss b/packages/web-components/examples/components/copy-button/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/copy-button/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/copy-button/vite.config.js b/packages/web-components/examples/components/copy-button/vite.config.js new file mode 100644 index 000000000000..e4af9f51b170 --- /dev/null +++ b/packages/web-components/examples/components/copy-button/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/data-table/.gitignore b/packages/web-components/examples/components/data-table/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/data-table/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/data-table/.sassrc b/packages/web-components/examples/components/data-table/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/data-table/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/data-table/cdn.html b/packages/web-components/examples/components/data-table/cdn.html new file mode 100644 index 000000000000..39760104961e --- /dev/null +++ b/packages/web-components/examples/components/data-table/cdn.html @@ -0,0 +1,79 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + Name + Status + + + + + Load Balancer 1 + Disabled + + + Load Balancer 2 + Starting + + + Load Balancer 3 + Active + + + + +
+
+
+ +

Sortable table

+
+ + + + Name + Status + + + + + Load Balancer 1 + Disabled + + + Load Balancer 2 + Starting + + + Load Balancer 3 + Active + + + + + diff --git a/packages/web-components/examples/components/data-table/index.html b/packages/web-components/examples/components/data-table/index.html new file mode 100644 index 000000000000..95c02b6f1618 --- /dev/null +++ b/packages/web-components/examples/components/data-table/index.html @@ -0,0 +1,79 @@ + + + + + carbon-web-components example + + + + + + + + +

Default tabe

+ + + + Name + Status + + + + + Load Balancer 1 + Disabled + + + Load Balancer 2 + Starting + + + Load Balancer 3 + Active + + + + +
+
+
+ +

Sortable table

+
+ + + + Name + Status + + + + + Load Balancer 1 + Disabled + + + Load Balancer 2 + Starting + + + Load Balancer 3 + Active + + + + + diff --git a/packages/web-components/examples/components/data-table/package.json b/packages/web-components/examples/components/data-table/package.json new file mode 100644 index 000000000000..50264a9314e3 --- /dev/null +++ b/packages/web-components/examples/components/data-table/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-data-table-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/data-table/sandbox.config.json b/packages/web-components/examples/components/data-table/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/data-table/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/data-table/src/index.js b/packages/web-components/examples/components/data-table/src/index.js new file mode 100644 index 000000000000..2584d14f0aa1 --- /dev/null +++ b/packages/web-components/examples/components/data-table/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/data-table/index.js'; \ No newline at end of file diff --git a/packages/web-components/examples/components/data-table/src/styles.scss b/packages/web-components/examples/components/data-table/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/data-table/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/data-table/vite.config.js b/packages/web-components/examples/components/data-table/vite.config.js new file mode 100644 index 000000000000..e4af9f51b170 --- /dev/null +++ b/packages/web-components/examples/components/data-table/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/date-picker/.gitignore b/packages/web-components/examples/components/date-picker/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/date-picker/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/date-picker/.sassrc b/packages/web-components/examples/components/date-picker/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/date-picker/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/date-picker/cdn.html b/packages/web-components/examples/components/date-picker/cdn.html new file mode 100644 index 000000000000..ce990d2b2e88 --- /dev/null +++ b/packages/web-components/examples/components/date-picker/cdn.html @@ -0,0 +1,36 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/date-picker/index.html b/packages/web-components/examples/components/date-picker/index.html new file mode 100644 index 000000000000..b55141de9701 --- /dev/null +++ b/packages/web-components/examples/components/date-picker/index.html @@ -0,0 +1,36 @@ + + + + + carbon-web-components example + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/date-picker/package.json b/packages/web-components/examples/components/date-picker/package.json new file mode 100644 index 000000000000..66cac619bef1 --- /dev/null +++ b/packages/web-components/examples/components/date-picker/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-date-picker-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/date-picker/sandbox.config.json b/packages/web-components/examples/components/date-picker/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/date-picker/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/date-picker/src/index.js b/packages/web-components/examples/components/date-picker/src/index.js new file mode 100644 index 000000000000..d3f9f751f647 --- /dev/null +++ b/packages/web-components/examples/components/date-picker/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/date-picker/index.js'; diff --git a/packages/web-components/examples/components/date-picker/src/styles.scss b/packages/web-components/examples/components/date-picker/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/date-picker/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/date-picker/vite.config.js b/packages/web-components/examples/components/date-picker/vite.config.js new file mode 100644 index 000000000000..e4af9f51b170 --- /dev/null +++ b/packages/web-components/examples/components/date-picker/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/dropdown/.gitignore b/packages/web-components/examples/components/dropdown/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/dropdown/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/dropdown/.sassrc b/packages/web-components/examples/components/dropdown/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/dropdown/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/dropdown/cdn.html b/packages/web-components/examples/components/dropdown/cdn.html new file mode 100644 index 000000000000..f7d0ae8507d4 --- /dev/null +++ b/packages/web-components/examples/components/dropdown/cdn.html @@ -0,0 +1,33 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + Foo + Bar + Baz + + + diff --git a/packages/web-components/examples/components/dropdown/index.html b/packages/web-components/examples/components/dropdown/index.html new file mode 100644 index 000000000000..0525577929a8 --- /dev/null +++ b/packages/web-components/examples/components/dropdown/index.html @@ -0,0 +1,34 @@ + + + + + carbon-web-components example + + + + + + + + + Foo + Bar + Baz + + + diff --git a/packages/web-components/examples/components/dropdown/package.json b/packages/web-components/examples/components/dropdown/package.json new file mode 100644 index 000000000000..1612a40d73dd --- /dev/null +++ b/packages/web-components/examples/components/dropdown/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-dropdown-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/dropdown/sandbox.config.json b/packages/web-components/examples/components/dropdown/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/dropdown/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/dropdown/src/index.js b/packages/web-components/examples/components/dropdown/src/index.js new file mode 100644 index 000000000000..65d36e655a10 --- /dev/null +++ b/packages/web-components/examples/components/dropdown/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/dropdown/index.js'; diff --git a/packages/web-components/examples/components/dropdown/src/styles.scss b/packages/web-components/examples/components/dropdown/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/dropdown/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/dropdown/vite.config.js b/packages/web-components/examples/components/dropdown/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/dropdown/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/file-uploader/.gitignore b/packages/web-components/examples/components/file-uploader/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/file-uploader/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/file-uploader/.sassrc b/packages/web-components/examples/components/file-uploader/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/file-uploader/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/file-uploader/cdn.html b/packages/web-components/examples/components/file-uploader/cdn.html new file mode 100644 index 000000000000..b39951bd3954 --- /dev/null +++ b/packages/web-components/examples/components/file-uploader/cdn.html @@ -0,0 +1,36 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + Drag and drop files here or click to upload + + + + diff --git a/packages/web-components/examples/components/file-uploader/index.html b/packages/web-components/examples/components/file-uploader/index.html new file mode 100644 index 000000000000..a8488d483cd0 --- /dev/null +++ b/packages/web-components/examples/components/file-uploader/index.html @@ -0,0 +1,36 @@ + + + + + carbon-web-components example + + + + + + + + + + + Drag and drop files here or click to upload + + + + diff --git a/packages/web-components/examples/components/file-uploader/package.json b/packages/web-components/examples/components/file-uploader/package.json new file mode 100644 index 000000000000..36fe715ee7aa --- /dev/null +++ b/packages/web-components/examples/components/file-uploader/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-file-uploader-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/file-uploader/sandbox.config.json b/packages/web-components/examples/components/file-uploader/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/file-uploader/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/file-uploader/src/index.js b/packages/web-components/examples/components/file-uploader/src/index.js new file mode 100644 index 000000000000..8e7aad49b7c6 --- /dev/null +++ b/packages/web-components/examples/components/file-uploader/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/file-uploader/index.js'; diff --git a/packages/web-components/examples/components/file-uploader/src/styles.scss b/packages/web-components/examples/components/file-uploader/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/file-uploader/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/file-uploader/vite.config.js b/packages/web-components/examples/components/file-uploader/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/file-uploader/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/form-group/.gitignore b/packages/web-components/examples/components/form-group/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/form-group/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/form-group/.sassrc b/packages/web-components/examples/components/form-group/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/form-group/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/form-group/cdn.html b/packages/web-components/examples/components/form-group/cdn.html new file mode 100644 index 000000000000..4fd1693d3bf9 --- /dev/null +++ b/packages/web-components/examples/components/form-group/cdn.html @@ -0,0 +1,56 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + + + + + + + + + + + Submit + + + + diff --git a/packages/web-components/examples/components/form-group/index.html b/packages/web-components/examples/components/form-group/index.html new file mode 100644 index 000000000000..9758c866515c --- /dev/null +++ b/packages/web-components/examples/components/form-group/index.html @@ -0,0 +1,58 @@ + + + + + carbon-web-components example + + + + + + + + + + + + + + + + + + Submit + + + + diff --git a/packages/web-components/examples/components/form-group/package.json b/packages/web-components/examples/components/form-group/package.json new file mode 100644 index 000000000000..147c2faea2b6 --- /dev/null +++ b/packages/web-components/examples/components/form-group/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-form-group-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/form-group/sandbox.config.json b/packages/web-components/examples/components/form-group/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/form-group/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/form-group/src/index.js b/packages/web-components/examples/components/form-group/src/index.js new file mode 100644 index 000000000000..21b41d83923a --- /dev/null +++ b/packages/web-components/examples/components/form-group/src/index.js @@ -0,0 +1,14 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/form-group/index.js'; +import '@carbon/web-components/es/components/radio-button/index.js'; +import '@carbon/web-components/es/components/text-input/index.js'; +import '@carbon/web-components/es/components/button/index.js'; +import '@carbon/web-components/es/components/stack/index.js'; diff --git a/packages/web-components/examples/components/form-group/src/styles.scss b/packages/web-components/examples/components/form-group/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/form-group/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/form-group/vite.config.js b/packages/web-components/examples/components/form-group/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/form-group/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/icon-button/.gitignore b/packages/web-components/examples/components/icon-button/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/icon-button/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/icon-button/.sassrc b/packages/web-components/examples/components/icon-button/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/icon-button/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/icon-button/cdn.html b/packages/web-components/examples/components/icon-button/cdn.html new file mode 100644 index 000000000000..be7c1719e06d --- /dev/null +++ b/packages/web-components/examples/components/icon-button/cdn.html @@ -0,0 +1,58 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + Tooltip text + + + diff --git a/packages/web-components/examples/components/icon-button/index.html b/packages/web-components/examples/components/icon-button/index.html new file mode 100644 index 000000000000..e08e2d8f5e07 --- /dev/null +++ b/packages/web-components/examples/components/icon-button/index.html @@ -0,0 +1,49 @@ + + + + + carbon-web-components example + + + + + + + + + + + Tooltip text + + + diff --git a/packages/web-components/examples/components/icon-button/package.json b/packages/web-components/examples/components/icon-button/package.json new file mode 100644 index 000000000000..ce3e7ff17fe7 --- /dev/null +++ b/packages/web-components/examples/components/icon-button/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-icon-button-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/icon-button/src/index.js b/packages/web-components/examples/components/icon-button/src/index.js new file mode 100644 index 000000000000..3135a9bdfede --- /dev/null +++ b/packages/web-components/examples/components/icon-button/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/icon-button/index.js'; diff --git a/packages/web-components/examples/components/icon-button/src/styles.scss b/packages/web-components/examples/components/icon-button/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/icon-button/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/icon-button/vite.config.js b/packages/web-components/examples/components/icon-button/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/icon-button/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/inline-loading/.gitignore b/packages/web-components/examples/components/inline-loading/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/inline-loading/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/inline-loading/.sassrc b/packages/web-components/examples/components/inline-loading/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/inline-loading/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/inline-loading/cdn.html b/packages/web-components/examples/components/inline-loading/cdn.html new file mode 100644 index 000000000000..baf1931f2098 --- /dev/null +++ b/packages/web-components/examples/components/inline-loading/cdn.html @@ -0,0 +1,29 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + +Loading data... + + diff --git a/packages/web-components/examples/components/inline-loading/index.html b/packages/web-components/examples/components/inline-loading/index.html new file mode 100644 index 000000000000..fbaee41caa30 --- /dev/null +++ b/packages/web-components/examples/components/inline-loading/index.html @@ -0,0 +1,29 @@ + + + + + carbon-web-components example + + + + + + + + + Loading data... + + diff --git a/packages/web-components/examples/components/inline-loading/package.json b/packages/web-components/examples/components/inline-loading/package.json new file mode 100644 index 000000000000..6ee0d3a94eff --- /dev/null +++ b/packages/web-components/examples/components/inline-loading/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-inline-loading-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/inline-loading/sandbox.config.json b/packages/web-components/examples/components/inline-loading/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/inline-loading/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/inline-loading/src/index.js b/packages/web-components/examples/components/inline-loading/src/index.js new file mode 100644 index 000000000000..eab15d638ec9 --- /dev/null +++ b/packages/web-components/examples/components/inline-loading/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/inline-loading/index.js'; diff --git a/packages/web-components/examples/components/inline-loading/src/styles.scss b/packages/web-components/examples/components/inline-loading/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/inline-loading/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/inline-loading/vite.config.js b/packages/web-components/examples/components/inline-loading/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/inline-loading/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/layer/.gitignore b/packages/web-components/examples/components/layer/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/layer/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/layer/.sassrc b/packages/web-components/examples/components/layer/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/layer/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/layer/cdn.html b/packages/web-components/examples/components/layer/cdn.html new file mode 100644 index 000000000000..ca8c23399870 --- /dev/null +++ b/packages/web-components/examples/components/layer/cdn.html @@ -0,0 +1,36 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + +
Test component
+ +
Test component
+ +
Test component
+
+
+
+ + diff --git a/packages/web-components/examples/components/layer/index.html b/packages/web-components/examples/components/layer/index.html new file mode 100644 index 000000000000..401b8969d93c --- /dev/null +++ b/packages/web-components/examples/components/layer/index.html @@ -0,0 +1,38 @@ + + + + + carbon-web-components example + + + + + + + + + +
Test component
+ +
Test component
+ +
Test component
+
+
+
+ + diff --git a/packages/web-components/examples/components/layer/package.json b/packages/web-components/examples/components/layer/package.json new file mode 100644 index 000000000000..1e1e8f42dc5a --- /dev/null +++ b/packages/web-components/examples/components/layer/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-layer-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/layer/sandbox.config.json b/packages/web-components/examples/components/layer/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/layer/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/layer/src/index.js b/packages/web-components/examples/components/layer/src/index.js new file mode 100644 index 000000000000..4850a09407d5 --- /dev/null +++ b/packages/web-components/examples/components/layer/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/layer/index.js'; diff --git a/packages/web-components/examples/components/layer/src/styles.scss b/packages/web-components/examples/components/layer/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/layer/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/layer/vite.config.js b/packages/web-components/examples/components/layer/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/layer/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/link/.gitignore b/packages/web-components/examples/components/link/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/link/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/link/.sassrc b/packages/web-components/examples/components/link/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/link/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/link/cdn.html b/packages/web-components/examples/components/link/cdn.html new file mode 100644 index 000000000000..d9a534e01672 --- /dev/null +++ b/packages/web-components/examples/components/link/cdn.html @@ -0,0 +1,40 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + Link + + diff --git a/packages/web-components/examples/components/link/index.html b/packages/web-components/examples/components/link/index.html new file mode 100644 index 000000000000..60187261845b --- /dev/null +++ b/packages/web-components/examples/components/link/index.html @@ -0,0 +1,31 @@ + + + + + carbon-web-components example + + + + + + + + + + Link + + + diff --git a/packages/web-components/examples/components/link/package.json b/packages/web-components/examples/components/link/package.json new file mode 100644 index 000000000000..a3502469eb05 --- /dev/null +++ b/packages/web-components/examples/components/link/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-link-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/link/sandbox.config.json b/packages/web-components/examples/components/link/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/link/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/link/src/index.js b/packages/web-components/examples/components/link/src/index.js new file mode 100644 index 000000000000..a7fd3decfabb --- /dev/null +++ b/packages/web-components/examples/components/link/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/link/index.js'; diff --git a/packages/web-components/examples/components/link/src/styles.scss b/packages/web-components/examples/components/link/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/link/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/list/.gitignore b/packages/web-components/examples/components/list/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/list/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/list/.sassrc b/packages/web-components/examples/components/list/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/list/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/list/cdn.html b/packages/web-components/examples/components/list/cdn.html new file mode 100644 index 000000000000..2c254aaf2bff --- /dev/null +++ b/packages/web-components/examples/components/list/cdn.html @@ -0,0 +1,73 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + +

cds-ordered-list

+ + + + Ordered List level 1 + + Ordered List level 2 + + Ordered List level 2 + + Ordered List level 2 + Ordered List level 2 + + + + + Ordered List level 1 + Ordered List level 1 + + +
+ +

cds-unordered-list

+ + + + Unordered List level 1 + + Unordered List level 2 + + Unordered List level 2 + + Unordered List level 2 + Unordered List level 2 + + + + + Unordered List level 1 + Unordered List level 1 + + + diff --git a/packages/web-components/examples/components/list/index.html b/packages/web-components/examples/components/list/index.html new file mode 100644 index 000000000000..9fde9a476655 --- /dev/null +++ b/packages/web-components/examples/components/list/index.html @@ -0,0 +1,73 @@ + + + + + carbon-web-components example + + + + + + + + +

cds-ordered-list

+ + + + Ordered List level 1 + + Ordered List level 2 + + Ordered List level 2 + + Ordered List level 2 + Ordered List level 2 + + + + + Ordered List level 1 + Ordered List level 1 + + +
+ +

cds-unordered-list

+ + + + Unordered List level 1 + + Unordered List level 2 + + Unordered List level 2 + + Unordered List level 2 + Unordered List level 2 + + + + + Unordered List level 1 + Unordered List level 1 + + + diff --git a/packages/web-components/examples/components/list/package.json b/packages/web-components/examples/components/list/package.json new file mode 100644 index 000000000000..fd2323be722c --- /dev/null +++ b/packages/web-components/examples/components/list/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-list-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/list/sandbox.config.json b/packages/web-components/examples/components/list/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/list/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/list/src/index.js b/packages/web-components/examples/components/list/src/index.js new file mode 100644 index 000000000000..e8f24ec4e304 --- /dev/null +++ b/packages/web-components/examples/components/list/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/list/index.js'; diff --git a/packages/web-components/examples/components/list/src/styles.scss b/packages/web-components/examples/components/list/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/list/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/list/vite.config.js b/packages/web-components/examples/components/list/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/list/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/loading/.gitignore b/packages/web-components/examples/components/loading/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/loading/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/loading/.sassrc b/packages/web-components/examples/components/loading/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/loading/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/loading/cdn.html b/packages/web-components/examples/components/loading/cdn.html new file mode 100644 index 000000000000..d196d874e84c --- /dev/null +++ b/packages/web-components/examples/components/loading/cdn.html @@ -0,0 +1,31 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + +
+ +
+ + diff --git a/packages/web-components/examples/components/loading/index.html b/packages/web-components/examples/components/loading/index.html new file mode 100644 index 000000000000..96a73071871a --- /dev/null +++ b/packages/web-components/examples/components/loading/index.html @@ -0,0 +1,30 @@ + + + + + carbon-web-components example + + + + + + + +
+ +
+ + diff --git a/packages/web-components/examples/components/loading/package.json b/packages/web-components/examples/components/loading/package.json new file mode 100644 index 000000000000..8f0aee0e33c3 --- /dev/null +++ b/packages/web-components/examples/components/loading/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-loading-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/loading/sandbox.config.json b/packages/web-components/examples/components/loading/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/loading/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/loading/src/index.js b/packages/web-components/examples/components/loading/src/index.js new file mode 100644 index 000000000000..5c0e2a05929d --- /dev/null +++ b/packages/web-components/examples/components/loading/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/loading/index.js'; diff --git a/packages/web-components/examples/components/loading/src/styles.scss b/packages/web-components/examples/components/loading/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/loading/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/loading/vite.config.js b/packages/web-components/examples/components/loading/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/loading/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/modal/.gitignore b/packages/web-components/examples/components/modal/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/modal/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/modal/.sassrc b/packages/web-components/examples/components/modal/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/modal/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/modal/cdn.html b/packages/web-components/examples/components/modal/cdn.html new file mode 100644 index 000000000000..dbc3449bbb32 --- /dev/null +++ b/packages/web-components/examples/components/modal/cdn.html @@ -0,0 +1,50 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + Open Modal + + + + + + Label (Optional) + Modal Title + +

Modal text description

+ + Cancel + Save + +
+ + + + diff --git a/packages/web-components/examples/components/modal/index.html b/packages/web-components/examples/components/modal/index.html new file mode 100644 index 000000000000..55deb5d3ac12 --- /dev/null +++ b/packages/web-components/examples/components/modal/index.html @@ -0,0 +1,49 @@ + + + + + carbon-web-components example + + + + + + + + + Open Modal + + + + + + Label (Optional) + Modal Title + +

Modal text description

+ + Cancel + Save + +
+ + + + diff --git a/packages/web-components/examples/components/modal/package.json b/packages/web-components/examples/components/modal/package.json new file mode 100644 index 000000000000..029802ea379f --- /dev/null +++ b/packages/web-components/examples/components/modal/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-modal-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/modal/sandbox.config.json b/packages/web-components/examples/components/modal/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/modal/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/modal/src/index.js b/packages/web-components/examples/components/modal/src/index.js new file mode 100644 index 000000000000..26736b5ce654 --- /dev/null +++ b/packages/web-components/examples/components/modal/src/index.js @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/modal/index.js'; +import '@carbon/web-components/es/components/button/index.js'; diff --git a/packages/web-components/examples/components/modal/src/styles.scss b/packages/web-components/examples/components/modal/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/modal/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/modal/vite.config.js b/packages/web-components/examples/components/modal/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/modal/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/multi-select/.gitignore b/packages/web-components/examples/components/multi-select/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/multi-select/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/multi-select/.sassrc b/packages/web-components/examples/components/multi-select/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/multi-select/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/multi-select/cdn.html b/packages/web-components/examples/components/multi-select/cdn.html new file mode 100644 index 000000000000..05216a8aadd5 --- /dev/null +++ b/packages/web-components/examples/components/multi-select/cdn.html @@ -0,0 +1,58 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + An example option that is really long to show what should be done to + handle long text + Option 1 + Option 2 + Option 3 - a disabled item + Option 4 + Option 5 + + + diff --git a/packages/web-components/examples/components/multi-select/index.html b/packages/web-components/examples/components/multi-select/index.html new file mode 100644 index 000000000000..af834e339d1e --- /dev/null +++ b/packages/web-components/examples/components/multi-select/index.html @@ -0,0 +1,49 @@ + + + + + carbon-web-components example + + + + + + + + + + An example option that is really long to show what should be done to + handle long text + Option 1 + Option 2 + Option 3 - a disabled item + Option 4 + Option 5 + + + diff --git a/packages/web-components/examples/components/multi-select/package.json b/packages/web-components/examples/components/multi-select/package.json new file mode 100644 index 000000000000..76aa1383b532 --- /dev/null +++ b/packages/web-components/examples/components/multi-select/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-multi-select-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/multi-select/sandbox.config.json b/packages/web-components/examples/components/multi-select/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/multi-select/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/multi-select/src/index.js b/packages/web-components/examples/components/multi-select/src/index.js new file mode 100644 index 000000000000..9f4a0f9cce3a --- /dev/null +++ b/packages/web-components/examples/components/multi-select/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/multi-select/index.js'; diff --git a/packages/web-components/examples/components/multi-select/src/styles.scss b/packages/web-components/examples/components/multi-select/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/multi-select/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/multi-select/vite.config.js b/packages/web-components/examples/components/multi-select/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/multi-select/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/notification/.gitignore b/packages/web-components/examples/components/notification/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/notification/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/notification/.sassrc b/packages/web-components/examples/components/notification/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/notification/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/notification/cdn.html b/packages/web-components/examples/components/notification/cdn.html new file mode 100644 index 000000000000..7d51aee13dbc --- /dev/null +++ b/packages/web-components/examples/components/notification/cdn.html @@ -0,0 +1,34 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/notification/index.html b/packages/web-components/examples/components/notification/index.html new file mode 100644 index 000000000000..5f3d04946aee --- /dev/null +++ b/packages/web-components/examples/components/notification/index.html @@ -0,0 +1,33 @@ + + + + + carbon-web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/notification/package.json b/packages/web-components/examples/components/notification/package.json new file mode 100644 index 000000000000..6fd2272b7044 --- /dev/null +++ b/packages/web-components/examples/components/notification/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-notification-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/notification/sandbox.config.json b/packages/web-components/examples/components/notification/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/notification/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/notification/src/index.js b/packages/web-components/examples/components/notification/src/index.js new file mode 100644 index 000000000000..507b425ebce2 --- /dev/null +++ b/packages/web-components/examples/components/notification/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/notification/index.js'; diff --git a/packages/web-components/examples/components/notification/src/styles.scss b/packages/web-components/examples/components/notification/src/styles.scss new file mode 100644 index 000000000000..b8e4ab9de12b --- /dev/null +++ b/packages/web-components/examples/components/notification/src/styles.scss @@ -0,0 +1,12 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +@use '@carbon/styles/scss/components/notification/tokens' as notification-tokens; +@include theme.add-component-tokens(notification-tokens.$notification-tokens); + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/notification/vite.config.js b/packages/web-components/examples/components/notification/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/notification/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/number-input/.gitignore b/packages/web-components/examples/components/number-input/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/number-input/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/number-input/.sassrc b/packages/web-components/examples/components/number-input/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/number-input/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/number-input/cdn.html b/packages/web-components/examples/components/number-input/cdn.html new file mode 100644 index 000000000000..9ae794173baf --- /dev/null +++ b/packages/web-components/examples/components/number-input/cdn.html @@ -0,0 +1,29 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/number-input/index.html b/packages/web-components/examples/components/number-input/index.html new file mode 100644 index 000000000000..97ecc18c80a8 --- /dev/null +++ b/packages/web-components/examples/components/number-input/index.html @@ -0,0 +1,28 @@ + + + + + carbon-web-components example + + + + + + + + + + diff --git a/packages/web-components/examples/components/number-input/package.json b/packages/web-components/examples/components/number-input/package.json new file mode 100644 index 000000000000..d9fac4e65ec4 --- /dev/null +++ b/packages/web-components/examples/components/number-input/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-number-input-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/number-input/sandbox.config.json b/packages/web-components/examples/components/number-input/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/number-input/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/number-input/src/index.js b/packages/web-components/examples/components/number-input/src/index.js new file mode 100644 index 000000000000..4525cda82a1a --- /dev/null +++ b/packages/web-components/examples/components/number-input/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/number-input/index.js'; diff --git a/packages/web-components/examples/components/number-input/src/styles.scss b/packages/web-components/examples/components/number-input/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/number-input/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/number-input/vite.config.js b/packages/web-components/examples/components/number-input/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/number-input/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/overflow-menu/.gitignore b/packages/web-components/examples/components/overflow-menu/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/overflow-menu/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/overflow-menu/.sassrc b/packages/web-components/examples/components/overflow-menu/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/overflow-menu/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/overflow-menu/cdn.html b/packages/web-components/examples/components/overflow-menu/cdn.html new file mode 100644 index 000000000000..efc9b5d2d108 --- /dev/null +++ b/packages/web-components/examples/components/overflow-menu/cdn.html @@ -0,0 +1,70 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + +
+ + + Options + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + + +
+ + diff --git a/packages/web-components/examples/components/overflow-menu/index.html b/packages/web-components/examples/components/overflow-menu/index.html new file mode 100644 index 000000000000..bd0ca7ab7226 --- /dev/null +++ b/packages/web-components/examples/components/overflow-menu/index.html @@ -0,0 +1,74 @@ + + + + + carbon-web-components example + + + + + + + + +
+ + + Options + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + + +
+ + diff --git a/packages/web-components/examples/components/overflow-menu/package.json b/packages/web-components/examples/components/overflow-menu/package.json new file mode 100644 index 000000000000..161dbccab1cc --- /dev/null +++ b/packages/web-components/examples/components/overflow-menu/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-overflow-menu-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/overflow-menu/sandbox.config.json b/packages/web-components/examples/components/overflow-menu/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/overflow-menu/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/overflow-menu/src/index.js b/packages/web-components/examples/components/overflow-menu/src/index.js new file mode 100644 index 000000000000..d184ca2d71d1 --- /dev/null +++ b/packages/web-components/examples/components/overflow-menu/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/overflow-menu/index.js'; diff --git a/packages/web-components/examples/components/overflow-menu/src/styles.scss b/packages/web-components/examples/components/overflow-menu/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/overflow-menu/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/overflow-menu/vite.config.js b/packages/web-components/examples/components/overflow-menu/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/overflow-menu/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/pagination/.gitignore b/packages/web-components/examples/components/pagination/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/pagination/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/pagination/.sassrc b/packages/web-components/examples/components/pagination/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/pagination/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/pagination/cdn.html b/packages/web-components/examples/components/pagination/cdn.html new file mode 100644 index 000000000000..adb4e7bea4bb --- /dev/null +++ b/packages/web-components/examples/components/pagination/cdn.html @@ -0,0 +1,47 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + 10 + 20 + 30 + 40 + 50 + + + diff --git a/packages/web-components/examples/components/pagination/index.html b/packages/web-components/examples/components/pagination/index.html new file mode 100644 index 000000000000..76cc85eaa88e --- /dev/null +++ b/packages/web-components/examples/components/pagination/index.html @@ -0,0 +1,36 @@ + + + + + carbon-web-components example + + + + + + + + + 10 + 20 + 30 + 40 + 50 + + + diff --git a/packages/web-components/examples/components/pagination/package.json b/packages/web-components/examples/components/pagination/package.json new file mode 100644 index 000000000000..b9975af90774 --- /dev/null +++ b/packages/web-components/examples/components/pagination/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-pagination-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/pagination/sandbox.config.json b/packages/web-components/examples/components/pagination/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/pagination/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/pagination/src/index.js b/packages/web-components/examples/components/pagination/src/index.js new file mode 100644 index 000000000000..ac8d2f629762 --- /dev/null +++ b/packages/web-components/examples/components/pagination/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/pagination/index.js'; diff --git a/packages/web-components/examples/components/pagination/src/styles.scss b/packages/web-components/examples/components/pagination/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/pagination/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/pagination/vite.config.js b/packages/web-components/examples/components/pagination/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/pagination/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/popover/.gitignore b/packages/web-components/examples/components/popover/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/popover/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/popover/.sassrc b/packages/web-components/examples/components/popover/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/popover/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/popover/cdn.html b/packages/web-components/examples/components/popover/cdn.html new file mode 100644 index 000000000000..6b36e8429408 --- /dev/null +++ b/packages/web-components/examples/components/popover/cdn.html @@ -0,0 +1,69 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + +
+ +
+ +
+ +
+

Available storage

+

+ This server has 150 GB of block storage remaining. +

+
+
+
+
+ + diff --git a/packages/web-components/examples/components/popover/index.html b/packages/web-components/examples/components/popover/index.html new file mode 100644 index 000000000000..257095e7c9cd --- /dev/null +++ b/packages/web-components/examples/components/popover/index.html @@ -0,0 +1,58 @@ + + + + + carbon-web-components example + + + + + + + +
+ +
+ +
+ +
+

Available storage

+

+ This server has 150 GB of block storage remaining. +

+
+
+
+
+ + diff --git a/packages/web-components/examples/components/popover/package.json b/packages/web-components/examples/components/popover/package.json new file mode 100644 index 000000000000..858773d2b655 --- /dev/null +++ b/packages/web-components/examples/components/popover/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-popover-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/popover/sandbox.config.json b/packages/web-components/examples/components/popover/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/popover/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/popover/src/index.js b/packages/web-components/examples/components/popover/src/index.js new file mode 100644 index 000000000000..c7e8a0327931 --- /dev/null +++ b/packages/web-components/examples/components/popover/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/popover/index.js'; diff --git a/packages/web-components/examples/components/popover/src/styles.scss b/packages/web-components/examples/components/popover/src/styles.scss new file mode 100644 index 000000000000..06ec6db992e2 --- /dev/null +++ b/packages/web-components/examples/components/popover/src/styles.scss @@ -0,0 +1,51 @@ +@use "@carbon/styles/scss/reset"; +@use "@carbon/styles/scss/theme"; +@use "@carbon/styles/scss/themes"; +@use "@carbon/styles/scss/type"; +@use "@carbon/styles/scss/spacing" as *; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} + +// Utilities +.flex { + display: flex; +} + +.justify-center { + justify-content: center; +} + +.mt-10 { + padding-block-start: $spacing-10; +} + +.p-3 { + padding: $spacing-05; +} + +.playground-trigger { + display: flex; + align-items: center; + justify-content: center; + border: 1px solid theme.$border-subtle; + block-size: $spacing-07; + inline-size: $spacing-07; +} + +.playground-trigger svg { + fill: theme.$background-inverse; +} + +.popover-title { + @include type.type-style("heading-compact-01"); + + margin-block-end: $spacing-01; +} + +.popover-details { + @include type.type-style("body-compact-01"); +} diff --git a/packages/web-components/examples/components/popover/vite.config.js b/packages/web-components/examples/components/popover/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/popover/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/progress-bar/.gitignore b/packages/web-components/examples/components/progress-bar/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/progress-bar/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/progress-bar/.sassrc b/packages/web-components/examples/components/progress-bar/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/progress-bar/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/progress-bar/cdn.html b/packages/web-components/examples/components/progress-bar/cdn.html new file mode 100644 index 000000000000..6344fe72bacf --- /dev/null +++ b/packages/web-components/examples/components/progress-bar/cdn.html @@ -0,0 +1,33 @@ + + + + + @carbon/web-components example + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/progress-bar/index.html b/packages/web-components/examples/components/progress-bar/index.html new file mode 100644 index 000000000000..6e610f6c7ca7 --- /dev/null +++ b/packages/web-components/examples/components/progress-bar/index.html @@ -0,0 +1,35 @@ + + + + + @carbon/web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/progress-bar/package.json b/packages/web-components/examples/components/progress-bar/package.json new file mode 100644 index 000000000000..7ba94bbf7707 --- /dev/null +++ b/packages/web-components/examples/components/progress-bar/package.json @@ -0,0 +1,22 @@ +{ + "name": "@carbon/web-components-progress-bar-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/progress-bar/sandbox.config.json b/packages/web-components/examples/components/progress-bar/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/progress-bar/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/progress-bar/src/index.js b/packages/web-components/examples/components/progress-bar/src/index.js new file mode 100644 index 000000000000..fdf4146c18e2 --- /dev/null +++ b/packages/web-components/examples/components/progress-bar/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import "@carbon/web-components/es/components/progress-bar/index.js"; diff --git a/packages/web-components/examples/components/progress-bar/src/styles.scss b/packages/web-components/examples/components/progress-bar/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/progress-bar/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/progress-bar/vite.config.js b/packages/web-components/examples/components/progress-bar/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/progress-bar/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/progress-indicator/.gitignore b/packages/web-components/examples/components/progress-indicator/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/progress-indicator/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/progress-indicator/.sassrc b/packages/web-components/examples/components/progress-indicator/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/progress-indicator/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/progress-indicator/cdn.html b/packages/web-components/examples/components/progress-indicator/cdn.html new file mode 100644 index 000000000000..fcfe48ae3103 --- /dev/null +++ b/packages/web-components/examples/components/progress-indicator/cdn.html @@ -0,0 +1,54 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/progress-indicator/index.html b/packages/web-components/examples/components/progress-indicator/index.html new file mode 100644 index 000000000000..b185f7b8945f --- /dev/null +++ b/packages/web-components/examples/components/progress-indicator/index.html @@ -0,0 +1,53 @@ + + + + + carbon-web-components example + + + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/progress-indicator/package.json b/packages/web-components/examples/components/progress-indicator/package.json new file mode 100644 index 000000000000..83782c23f401 --- /dev/null +++ b/packages/web-components/examples/components/progress-indicator/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-progress-indicator-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/progress-indicator/sandbox.config.json b/packages/web-components/examples/components/progress-indicator/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/progress-indicator/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/progress-indicator/src/index.js b/packages/web-components/examples/components/progress-indicator/src/index.js new file mode 100644 index 000000000000..15ae8f08ec7c --- /dev/null +++ b/packages/web-components/examples/components/progress-indicator/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/progress-indicator/index.js'; diff --git a/packages/web-components/examples/components/progress-indicator/src/styles.scss b/packages/web-components/examples/components/progress-indicator/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/progress-indicator/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/progress-indicator/vite.config.js b/packages/web-components/examples/components/progress-indicator/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/progress-indicator/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/radio-button/.gitignore b/packages/web-components/examples/components/radio-button/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/radio-button/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/radio-button/.sassrc b/packages/web-components/examples/components/radio-button/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/radio-button/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/radio-button/cdn.html b/packages/web-components/examples/components/radio-button/cdn.html new file mode 100644 index 000000000000..f87277655d8b --- /dev/null +++ b/packages/web-components/examples/components/radio-button/cdn.html @@ -0,0 +1,37 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/radio-button/index.html b/packages/web-components/examples/components/radio-button/index.html new file mode 100644 index 000000000000..a0563bca959e --- /dev/null +++ b/packages/web-components/examples/components/radio-button/index.html @@ -0,0 +1,36 @@ + + + + + carbon-web-components example + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/radio-button/package.json b/packages/web-components/examples/components/radio-button/package.json new file mode 100644 index 000000000000..ed5b3482bd3b --- /dev/null +++ b/packages/web-components/examples/components/radio-button/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-radio-button-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/radio-button/sandbox.config.json b/packages/web-components/examples/components/radio-button/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/radio-button/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/radio-button/src/index.js b/packages/web-components/examples/components/radio-button/src/index.js new file mode 100644 index 000000000000..a13a1691d132 --- /dev/null +++ b/packages/web-components/examples/components/radio-button/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/radio-button/index.js'; diff --git a/packages/web-components/examples/components/radio-button/src/styles.scss b/packages/web-components/examples/components/radio-button/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/radio-button/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/radio-button/vite.config.js b/packages/web-components/examples/components/radio-button/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/radio-button/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/search/.gitignore b/packages/web-components/examples/components/search/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/search/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/search/.sassrc b/packages/web-components/examples/components/search/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/search/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/search/cdn.html b/packages/web-components/examples/components/search/cdn.html new file mode 100644 index 000000000000..fdd0df3edfe3 --- /dev/null +++ b/packages/web-components/examples/components/search/cdn.html @@ -0,0 +1,29 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/search/index.html b/packages/web-components/examples/components/search/index.html new file mode 100644 index 000000000000..eb5c15db355b --- /dev/null +++ b/packages/web-components/examples/components/search/index.html @@ -0,0 +1,28 @@ + + + + + carbon-web-components example + + + + + + + + + + diff --git a/packages/web-components/examples/components/search/package.json b/packages/web-components/examples/components/search/package.json new file mode 100644 index 000000000000..11ce1c751bbc --- /dev/null +++ b/packages/web-components/examples/components/search/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-search-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/search/sandbox.config.json b/packages/web-components/examples/components/search/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/search/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/search/src/index.js b/packages/web-components/examples/components/search/src/index.js new file mode 100644 index 000000000000..658287d766b5 --- /dev/null +++ b/packages/web-components/examples/components/search/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/search/index.js'; diff --git a/packages/web-components/examples/components/search/src/styles.scss b/packages/web-components/examples/components/search/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/search/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/search/vite.config.js b/packages/web-components/examples/components/search/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/search/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/select/.gitignore b/packages/web-components/examples/components/select/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/select/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/select/.sassrc b/packages/web-components/examples/components/select/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/select/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/select/cdn.html b/packages/web-components/examples/components/select/cdn.html new file mode 100644 index 000000000000..45374848e56e --- /dev/null +++ b/packages/web-components/examples/components/select/cdn.html @@ -0,0 +1,43 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + Option 1 + Option 2 + + + Option 3 + Option 4 + Option 5 + + + + diff --git a/packages/web-components/examples/components/select/index.html b/packages/web-components/examples/components/select/index.html new file mode 100644 index 000000000000..a3977ba3e838 --- /dev/null +++ b/packages/web-components/examples/components/select/index.html @@ -0,0 +1,42 @@ + + + + + carbon-web-components example + + + + + + + + + + Option 1 + Option 2 + + + Option 3 + Option 4 + Option 5 + + + + diff --git a/packages/web-components/examples/components/select/package.json b/packages/web-components/examples/components/select/package.json new file mode 100644 index 000000000000..d475e52bd958 --- /dev/null +++ b/packages/web-components/examples/components/select/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-select-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/select/sandbox.config.json b/packages/web-components/examples/components/select/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/select/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/select/src/index.js b/packages/web-components/examples/components/select/src/index.js new file mode 100644 index 000000000000..6b8c93d7f387 --- /dev/null +++ b/packages/web-components/examples/components/select/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/select/index.js'; diff --git a/packages/web-components/examples/components/select/src/styles.scss b/packages/web-components/examples/components/select/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/select/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/select/vite.config.js b/packages/web-components/examples/components/select/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/select/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/side-panel/.gitignore b/packages/web-components/examples/components/side-panel/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/side-panel/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/side-panel/.sassrc b/packages/web-components/examples/components/side-panel/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/side-panel/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/side-panel/cdn.html b/packages/web-components/examples/components/side-panel/cdn.html new file mode 100644 index 000000000000..7f1f9dfbb52e --- /dev/null +++ b/packages/web-components/examples/components/side-panel/cdn.html @@ -0,0 +1,127 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + + + +
+ Toggle side panel + + + +
Section
+
+ + +
+
+ + +
+
+ + + +
+ + +
This is your subtitle slot.
+ + + Copy + + + + + + + + + + Ghost + + + Secondary + + + Primary + + + + +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed + do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+
+
+ + + diff --git a/packages/web-components/examples/components/side-panel/index.html b/packages/web-components/examples/components/side-panel/index.html new file mode 100644 index 000000000000..b87e66330b15 --- /dev/null +++ b/packages/web-components/examples/components/side-panel/index.html @@ -0,0 +1,122 @@ + + + + + carbon-web-components example + + + + + + + + +
+ Toggle side panel + + + +
Section
+
+ + +
+
+ + +
+
+ + + +
+ + +
This is your subtitle slot.
+ + + Copy + + + + + + + + + + Ghost + + + Secondary + + + Primary + + + + +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed + do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+
+
+ + + + diff --git a/packages/web-components/examples/components/side-panel/package.json b/packages/web-components/examples/components/side-panel/package.json new file mode 100644 index 000000000000..18ba9a722c54 --- /dev/null +++ b/packages/web-components/examples/components/side-panel/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-side-panel-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/side-panel/sandbox.config.json b/packages/web-components/examples/components/side-panel/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/side-panel/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/side-panel/src/index.js b/packages/web-components/examples/components/side-panel/src/index.js new file mode 100644 index 000000000000..c023444b19ca --- /dev/null +++ b/packages/web-components/examples/components/side-panel/src/index.js @@ -0,0 +1,15 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/side-panel/index.js'; +import '@carbon/web-components/es/components/button/index.js'; +import '@carbon/web-components/es/components/text-input/index.js'; +import '@carbon/web-components/es/components/textarea/index.js'; +import '@carbon/web-components/es/components/slug/index.js'; +import '@carbon/web-components/es/components/tabs/index.js'; diff --git a/packages/web-components/examples/components/side-panel/src/styles.scss b/packages/web-components/examples/components/side-panel/src/styles.scss new file mode 100644 index 000000000000..24a9e7b4df3d --- /dev/null +++ b/packages/web-components/examples/components/side-panel/src/styles.scss @@ -0,0 +1,31 @@ +/** + * Copyright IBM Corp. 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} + +.container-header{ + background: var(--cds-background-inverse); + height: 3rem; +} + +.text-inputs { + display: flex; + gap: 1rem; + + > * { + flex-basis: 50%; + } +} + diff --git a/packages/web-components/examples/components/side-panel/vite.config.js b/packages/web-components/examples/components/side-panel/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/side-panel/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/skeleton-icon/.gitignore b/packages/web-components/examples/components/skeleton-icon/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-icon/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/skeleton-icon/.sassrc b/packages/web-components/examples/components/skeleton-icon/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/skeleton-icon/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/skeleton-icon/cdn.html b/packages/web-components/examples/components/skeleton-icon/cdn.html new file mode 100644 index 000000000000..c802985c24e4 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-icon/cdn.html @@ -0,0 +1,29 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/skeleton-icon/index.html b/packages/web-components/examples/components/skeleton-icon/index.html new file mode 100644 index 000000000000..a6aec86c2754 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-icon/index.html @@ -0,0 +1,28 @@ + + + + + carbon-web-components example + + + + + + + + + + diff --git a/packages/web-components/examples/components/skeleton-icon/package.json b/packages/web-components/examples/components/skeleton-icon/package.json new file mode 100644 index 000000000000..478b1a95266a --- /dev/null +++ b/packages/web-components/examples/components/skeleton-icon/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-skeleton-icon-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/skeleton-icon/sandbox.config.json b/packages/web-components/examples/components/skeleton-icon/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/skeleton-icon/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/skeleton-icon/src/index.js b/packages/web-components/examples/components/skeleton-icon/src/index.js new file mode 100644 index 000000000000..65b3fe28c085 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-icon/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/skeleton-icon/index.js'; diff --git a/packages/web-components/examples/components/skeleton-icon/src/styles.scss b/packages/web-components/examples/components/skeleton-icon/src/styles.scss new file mode 100644 index 000000000000..2183124956e2 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-icon/src/styles.scss @@ -0,0 +1,18 @@ +/** + * @license + * + * Copyright IBM Corp. 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/skeleton-icon/vite.config.js b/packages/web-components/examples/components/skeleton-icon/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/skeleton-icon/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/skeleton-placeholder/.gitignore b/packages/web-components/examples/components/skeleton-placeholder/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-placeholder/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/skeleton-placeholder/.sassrc b/packages/web-components/examples/components/skeleton-placeholder/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/skeleton-placeholder/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/skeleton-placeholder/cdn.html b/packages/web-components/examples/components/skeleton-placeholder/cdn.html new file mode 100644 index 000000000000..433a7d069feb --- /dev/null +++ b/packages/web-components/examples/components/skeleton-placeholder/cdn.html @@ -0,0 +1,29 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/skeleton-placeholder/index.html b/packages/web-components/examples/components/skeleton-placeholder/index.html new file mode 100644 index 000000000000..7e125475fd33 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-placeholder/index.html @@ -0,0 +1,28 @@ + + + + + carbon-web-components example + + + + + + + + + + diff --git a/packages/web-components/examples/components/skeleton-placeholder/package.json b/packages/web-components/examples/components/skeleton-placeholder/package.json new file mode 100644 index 000000000000..be55adf5a413 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-placeholder/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-skeleton-placeholder-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/skeleton-placeholder/sandbox.config.json b/packages/web-components/examples/components/skeleton-placeholder/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/skeleton-placeholder/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/skeleton-placeholder/src/index.js b/packages/web-components/examples/components/skeleton-placeholder/src/index.js new file mode 100644 index 000000000000..4cb7090c667c --- /dev/null +++ b/packages/web-components/examples/components/skeleton-placeholder/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/skeleton-placeholder/index.js'; diff --git a/packages/web-components/examples/components/skeleton-placeholder/src/styles.scss b/packages/web-components/examples/components/skeleton-placeholder/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-placeholder/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/skeleton-placeholder/vite.config.js b/packages/web-components/examples/components/skeleton-placeholder/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/skeleton-placeholder/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/skeleton-text/.gitignore b/packages/web-components/examples/components/skeleton-text/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-text/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/skeleton-text/.sassrc b/packages/web-components/examples/components/skeleton-text/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/skeleton-text/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/skeleton-text/cdn.html b/packages/web-components/examples/components/skeleton-text/cdn.html new file mode 100644 index 000000000000..007e581f5052 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-text/cdn.html @@ -0,0 +1,29 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/skeleton-text/index.html b/packages/web-components/examples/components/skeleton-text/index.html new file mode 100644 index 000000000000..c25bd619f299 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-text/index.html @@ -0,0 +1,28 @@ + + + + + carbon-web-components example + + + + + + + + + + diff --git a/packages/web-components/examples/components/skeleton-text/package.json b/packages/web-components/examples/components/skeleton-text/package.json new file mode 100644 index 000000000000..4839defc8700 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-text/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-skeleton-text-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/skeleton-text/sandbox.config.json b/packages/web-components/examples/components/skeleton-text/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/skeleton-text/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/skeleton-text/src/index.js b/packages/web-components/examples/components/skeleton-text/src/index.js new file mode 100644 index 000000000000..8ca45e3ed11b --- /dev/null +++ b/packages/web-components/examples/components/skeleton-text/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/skeleton-text/index.js'; diff --git a/packages/web-components/examples/components/skeleton-text/src/styles.scss b/packages/web-components/examples/components/skeleton-text/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/skeleton-text/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/skeleton-text/vite.config.js b/packages/web-components/examples/components/skeleton-text/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/skeleton-text/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/skip-to-content/.gitignore b/packages/web-components/examples/components/skip-to-content/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/skip-to-content/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/skip-to-content/.sassrc b/packages/web-components/examples/components/skip-to-content/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/skip-to-content/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/skip-to-content/cdn.html b/packages/web-components/examples/components/skip-to-content/cdn.html new file mode 100644 index 000000000000..49313554667c --- /dev/null +++ b/packages/web-components/examples/components/skip-to-content/cdn.html @@ -0,0 +1,37 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + +
+ + Button + +
+ + diff --git a/packages/web-components/examples/components/skip-to-content/index.html b/packages/web-components/examples/components/skip-to-content/index.html new file mode 100644 index 000000000000..07d37eafa84b --- /dev/null +++ b/packages/web-components/examples/components/skip-to-content/index.html @@ -0,0 +1,35 @@ + + + + + carbon-web-components example + + + + + + + + +
+ + Button + +
+ + diff --git a/packages/web-components/examples/components/skip-to-content/package.json b/packages/web-components/examples/components/skip-to-content/package.json new file mode 100644 index 000000000000..dd109d15680a --- /dev/null +++ b/packages/web-components/examples/components/skip-to-content/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-skip-to-content-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/skip-to-content/sandbox.config.json b/packages/web-components/examples/components/skip-to-content/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/skip-to-content/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/skip-to-content/src/index.js b/packages/web-components/examples/components/skip-to-content/src/index.js new file mode 100644 index 000000000000..f47771c6db60 --- /dev/null +++ b/packages/web-components/examples/components/skip-to-content/src/index.js @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/skip-to-content/index.js'; +import '@carbon/web-components/es/components/button/index.js'; diff --git a/packages/web-components/examples/components/skip-to-content/src/styles.scss b/packages/web-components/examples/components/skip-to-content/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/skip-to-content/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/skip-to-content/vite.config.js b/packages/web-components/examples/components/skip-to-content/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/skip-to-content/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/slider/.gitignore b/packages/web-components/examples/components/slider/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/slider/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/slider/.sassrc b/packages/web-components/examples/components/slider/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/slider/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/slider/cdn.html b/packages/web-components/examples/components/slider/cdn.html new file mode 100644 index 000000000000..fc6c8334cc74 --- /dev/null +++ b/packages/web-components/examples/components/slider/cdn.html @@ -0,0 +1,57 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/slider/index.html b/packages/web-components/examples/components/slider/index.html new file mode 100644 index 000000000000..03583f5a5f4d --- /dev/null +++ b/packages/web-components/examples/components/slider/index.html @@ -0,0 +1,44 @@ + + + + + carbon-web-components example + + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/slider/package.json b/packages/web-components/examples/components/slider/package.json new file mode 100644 index 000000000000..88ba2b4137ae --- /dev/null +++ b/packages/web-components/examples/components/slider/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-slider-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/slider/sandbox.config.json b/packages/web-components/examples/components/slider/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/slider/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/slider/src/index.js b/packages/web-components/examples/components/slider/src/index.js new file mode 100644 index 000000000000..3fee4668c557 --- /dev/null +++ b/packages/web-components/examples/components/slider/src/index.js @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import "@carbon/web-components/es/components/slider/index.js"; +import "@carbon/web-components/es/components/form/index.js"; diff --git a/packages/web-components/examples/components/slider/src/styles.scss b/packages/web-components/examples/components/slider/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/slider/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/slider/vite.config.js b/packages/web-components/examples/components/slider/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/slider/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/slug/.gitignore b/packages/web-components/examples/components/slug/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/slug/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/slug/.sassrc b/packages/web-components/examples/components/slug/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/slug/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/slug/cdn.html b/packages/web-components/examples/components/slug/cdn.html new file mode 100644 index 000000000000..e2c5aa2f77fb --- /dev/null +++ b/packages/web-components/examples/components/slug/cdn.html @@ -0,0 +1,31 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + AI was used to generate this content + + + diff --git a/packages/web-components/examples/components/slug/index.html b/packages/web-components/examples/components/slug/index.html new file mode 100644 index 000000000000..eb01c58adb51 --- /dev/null +++ b/packages/web-components/examples/components/slug/index.html @@ -0,0 +1,31 @@ + + + + + carbon-web-components example + + + + + + + + + + AI was used to generate this content + + + diff --git a/packages/web-components/examples/components/slug/package.json b/packages/web-components/examples/components/slug/package.json new file mode 100644 index 000000000000..0f295992e6ad --- /dev/null +++ b/packages/web-components/examples/components/slug/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-slug-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/slug/sandbox.config.json b/packages/web-components/examples/components/slug/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/slug/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/slug/src/index.js b/packages/web-components/examples/components/slug/src/index.js new file mode 100644 index 000000000000..9610c2d9c73f --- /dev/null +++ b/packages/web-components/examples/components/slug/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/slug/index.js'; diff --git a/packages/web-components/examples/components/slug/src/styles.scss b/packages/web-components/examples/components/slug/src/styles.scss new file mode 100644 index 000000000000..fc85d018b465 --- /dev/null +++ b/packages/web-components/examples/components/slug/src/styles.scss @@ -0,0 +1,10 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} + diff --git a/packages/web-components/examples/components/slug/vite.config.js b/packages/web-components/examples/components/slug/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/slug/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/stack/.gitignore b/packages/web-components/examples/components/stack/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/stack/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/stack/.sassrc b/packages/web-components/examples/components/stack/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/stack/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/stack/cdn.html b/packages/web-components/examples/components/stack/cdn.html new file mode 100644 index 000000000000..b886bee928f3 --- /dev/null +++ b/packages/web-components/examples/components/stack/cdn.html @@ -0,0 +1,33 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + +
Item 1
+
Item 2
+
Item 3
+
+ + diff --git a/packages/web-components/examples/components/stack/index.html b/packages/web-components/examples/components/stack/index.html new file mode 100644 index 000000000000..2b80c7ab0693 --- /dev/null +++ b/packages/web-components/examples/components/stack/index.html @@ -0,0 +1,26 @@ + + + + + carbon-web-components example + + + + + + + +
Item 1
+
Item 2
+
Item 3
+
+ + diff --git a/packages/web-components/examples/components/stack/package.json b/packages/web-components/examples/components/stack/package.json new file mode 100644 index 000000000000..6cf26e773ec2 --- /dev/null +++ b/packages/web-components/examples/components/stack/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-stack-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/stack/sandbox.config.json b/packages/web-components/examples/components/stack/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/stack/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/stack/src/index.js b/packages/web-components/examples/components/stack/src/index.js new file mode 100644 index 000000000000..88f82e236abf --- /dev/null +++ b/packages/web-components/examples/components/stack/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/stack/index.js'; diff --git a/packages/web-components/examples/components/stack/src/styles.scss b/packages/web-components/examples/components/stack/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/stack/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/stack/vite.config.js b/packages/web-components/examples/components/stack/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/stack/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/structured-list/.gitignore b/packages/web-components/examples/components/structured-list/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/structured-list/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/structured-list/.sassrc b/packages/web-components/examples/components/structured-list/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/structured-list/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/structured-list/cdn.html b/packages/web-components/examples/components/structured-list/cdn.html new file mode 100644 index 000000000000..3e5ff22820ae --- /dev/null +++ b/packages/web-components/examples/components/structured-list/cdn.html @@ -0,0 +1,63 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + ColumnA + ColumnB + ColumnC + + + + + Row 1 + Row 1 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc dui magna, finibus id tortor sed, aliquet bibendum + augue. Aenean posuere sem vel euismod dignissim. + + + Row 2 + Row 2 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc dui magna, finibus id tortor sed, aliquet bibendum + augue. Aenean posuere sem vel euismod dignissim. + + + Row 3 + Row 3 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc dui magna, finibus id tortor sed, aliquet bibendum + augue. Aenean posuere sem vel euismod dignissim. + + + + + diff --git a/packages/web-components/examples/components/structured-list/index.html b/packages/web-components/examples/components/structured-list/index.html new file mode 100644 index 000000000000..cb84dd3dd4e1 --- /dev/null +++ b/packages/web-components/examples/components/structured-list/index.html @@ -0,0 +1,63 @@ + + + + + carbon-web-components example + + + + + + + + + + + + ColumnA + ColumnB + ColumnC + + + + + Row 1 + Row 1 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc dui magna, finibus id tortor sed, aliquet bibendum + augue. Aenean posuere sem vel euismod dignissim. + + + Row 2 + Row 2 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc dui magna, finibus id tortor sed, aliquet bibendum + augue. Aenean posuere sem vel euismod dignissim. + + + Row 3 + Row 3 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc dui magna, finibus id tortor sed, aliquet bibendum + augue. Aenean posuere sem vel euismod dignissim. + + + + + diff --git a/packages/web-components/examples/components/structured-list/package.json b/packages/web-components/examples/components/structured-list/package.json new file mode 100644 index 000000000000..3539f92d4549 --- /dev/null +++ b/packages/web-components/examples/components/structured-list/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-structured-list-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/structured-list/sandbox.config.json b/packages/web-components/examples/components/structured-list/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/structured-list/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/structured-list/src/index.js b/packages/web-components/examples/components/structured-list/src/index.js new file mode 100644 index 000000000000..1e83b957c597 --- /dev/null +++ b/packages/web-components/examples/components/structured-list/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/structured-list/index.js'; diff --git a/packages/web-components/examples/components/structured-list/src/styles.scss b/packages/web-components/examples/components/structured-list/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/structured-list/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/structured-list/vite.config.js b/packages/web-components/examples/components/structured-list/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/structured-list/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/tabs/.gitignore b/packages/web-components/examples/components/tabs/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/tabs/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/tabs/.sassrc b/packages/web-components/examples/components/tabs/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/tabs/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/tabs/cdn.html b/packages/web-components/examples/components/tabs/cdn.html new file mode 100644 index 000000000000..8d6c3b5e4902 --- /dev/null +++ b/packages/web-components/examples/components/tabs/cdn.html @@ -0,0 +1,75 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + +
+ + + + + +
+ + diff --git a/packages/web-components/examples/components/tabs/index.html b/packages/web-components/examples/components/tabs/index.html new file mode 100644 index 000000000000..8b404d0133b2 --- /dev/null +++ b/packages/web-components/examples/components/tabs/index.html @@ -0,0 +1,75 @@ + + + + + carbon-web-components example + + + + + + + + + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + +
+ + + + + +
+ + diff --git a/packages/web-components/examples/components/tabs/package.json b/packages/web-components/examples/components/tabs/package.json new file mode 100644 index 000000000000..5d6534515fa7 --- /dev/null +++ b/packages/web-components/examples/components/tabs/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-tabs-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/tabs/sandbox.config.json b/packages/web-components/examples/components/tabs/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/tabs/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/tabs/src/index.js b/packages/web-components/examples/components/tabs/src/index.js new file mode 100644 index 000000000000..ee86f214ffbb --- /dev/null +++ b/packages/web-components/examples/components/tabs/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/tabs/index.js'; diff --git a/packages/web-components/examples/components/tabs/src/styles.scss b/packages/web-components/examples/components/tabs/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/tabs/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/tabs/vite.config.js b/packages/web-components/examples/components/tabs/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/tabs/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/tag/.gitignore b/packages/web-components/examples/components/tag/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/tag/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/tag/.sassrc b/packages/web-components/examples/components/tag/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/tag/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/tag/cdn.html b/packages/web-components/examples/components/tag/cdn.html new file mode 100644 index 000000000000..fc643fca2f72 --- /dev/null +++ b/packages/web-components/examples/components/tag/cdn.html @@ -0,0 +1,31 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + This is a tag + + + diff --git a/packages/web-components/examples/components/tag/index.html b/packages/web-components/examples/components/tag/index.html new file mode 100644 index 000000000000..f205bf4f7742 --- /dev/null +++ b/packages/web-components/examples/components/tag/index.html @@ -0,0 +1,31 @@ + + + + + carbon-web-components example + + + + + + + + + + This is a tag + + + diff --git a/packages/web-components/examples/components/tag/package.json b/packages/web-components/examples/components/tag/package.json new file mode 100644 index 000000000000..0934e63db509 --- /dev/null +++ b/packages/web-components/examples/components/tag/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-tag-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/tag/sandbox.config.json b/packages/web-components/examples/components/tag/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/tag/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/tag/src/index.js b/packages/web-components/examples/components/tag/src/index.js new file mode 100644 index 000000000000..c87b9a59c0ab --- /dev/null +++ b/packages/web-components/examples/components/tag/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/tag/index.js'; diff --git a/packages/web-components/examples/components/tag/src/styles.scss b/packages/web-components/examples/components/tag/src/styles.scss new file mode 100644 index 000000000000..b2ebf32cbeb8 --- /dev/null +++ b/packages/web-components/examples/components/tag/src/styles.scss @@ -0,0 +1,12 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +@use '@carbon/styles/scss/components/tag/tokens' as tag-tokens; +@include theme.add-component-tokens(tag-tokens.$tag-tokens); + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/tag/vite.config.js b/packages/web-components/examples/components/tag/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/tag/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/tearsheet/.gitignore b/packages/web-components/examples/components/tearsheet/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/tearsheet/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/tearsheet/.sassrc b/packages/web-components/examples/components/tearsheet/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/tearsheet/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/tearsheet/cdn.html b/packages/web-components/examples/components/tearsheet/cdn.html new file mode 100644 index 000000000000..e08bae284aa7 --- /dev/null +++ b/packages/web-components/examples/components/tearsheet/cdn.html @@ -0,0 +1,162 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + + + Toggle tearsheet + + + +
+
Section
+
+ + +
+
+ + +
+
+ + + +
+
+ + + Optional label for context + + + Title used to designate the overarching flow of the tearsheet. + + + Description used to describe the flow if need be. + + + Ghost + + Secondary + + + Primary + + + + +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed + do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+
+ + +
+ + Tab 1 + Tab 2 + Tab 3 + Tab 4 + +
+
+ + + diff --git a/packages/web-components/examples/components/tearsheet/index.html b/packages/web-components/examples/components/tearsheet/index.html new file mode 100644 index 000000000000..a93abd9b0b58 --- /dev/null +++ b/packages/web-components/examples/components/tearsheet/index.html @@ -0,0 +1,133 @@ + + + + + carbon-web-components example + + + + + + + + + Toggle tearsheet + + + +
+
Section
+
+ + +
+
+ + +
+
+ + + +
+
+ + + Optional label for context + + + Title used to designate the overarching flow of the tearsheet. + + + Description used to describe the flow if need be. + + + Ghost + + Secondary + + + Primary + + + + +
+

AI Explained

+

84%

+

Confidence score

+

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed + do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+
+

Model type

+

Foundation model

+
+
+ + +
+ + Tab 1 + Tab 2 + Tab 3 + Tab 4 + +
+
+ + + diff --git a/packages/web-components/examples/components/tearsheet/package.json b/packages/web-components/examples/components/tearsheet/package.json new file mode 100644 index 000000000000..180cfe33a78b --- /dev/null +++ b/packages/web-components/examples/components/tearsheet/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-tearsheet-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/tearsheet/sandbox.config.json b/packages/web-components/examples/components/tearsheet/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/tearsheet/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/tearsheet/src/index.js b/packages/web-components/examples/components/tearsheet/src/index.js new file mode 100644 index 000000000000..bcd182156ddf --- /dev/null +++ b/packages/web-components/examples/components/tearsheet/src/index.js @@ -0,0 +1,15 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/tearsheet/index.js'; +import '@carbon/web-components/es/components/button/index.js'; +import '@carbon/web-components/es/components/text-input/index.js'; +import '@carbon/web-components/es/components/textarea/index.js'; +import '@carbon/web-components/es/components/slug/index.js'; +import '@carbon/web-components/es/components/tabs/index.js'; diff --git a/packages/web-components/examples/components/tearsheet/src/styles.scss b/packages/web-components/examples/components/tearsheet/src/styles.scss new file mode 100644 index 000000000000..e44f676edaf2 --- /dev/null +++ b/packages/web-components/examples/components/tearsheet/src/styles.scss @@ -0,0 +1,16 @@ +/** + * Copyright IBM Corp. 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/tearsheet/vite.config.js b/packages/web-components/examples/components/tearsheet/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/tearsheet/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/text-input/.gitignore b/packages/web-components/examples/components/text-input/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/text-input/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/text-input/.sassrc b/packages/web-components/examples/components/text-input/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/text-input/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/text-input/cdn.html b/packages/web-components/examples/components/text-input/cdn.html new file mode 100644 index 000000000000..46964b85d2c0 --- /dev/null +++ b/packages/web-components/examples/components/text-input/cdn.html @@ -0,0 +1,47 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/text-input/index.html b/packages/web-components/examples/components/text-input/index.html new file mode 100644 index 000000000000..3ffecc9473aa --- /dev/null +++ b/packages/web-components/examples/components/text-input/index.html @@ -0,0 +1,38 @@ + + + + + carbon-web-components example + + + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/text-input/package.json b/packages/web-components/examples/components/text-input/package.json new file mode 100644 index 000000000000..837de421f69b --- /dev/null +++ b/packages/web-components/examples/components/text-input/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-input-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/text-input/sandbox.config.json b/packages/web-components/examples/components/text-input/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/text-input/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/text-input/src/index.js b/packages/web-components/examples/components/text-input/src/index.js new file mode 100644 index 000000000000..9528c65cb098 --- /dev/null +++ b/packages/web-components/examples/components/text-input/src/index.js @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import "@carbon/web-components/es/components/form/index.js"; +import "@carbon/web-components/es/components/text-input/index.js"; diff --git a/packages/web-components/examples/components/text-input/src/styles.scss b/packages/web-components/examples/components/text-input/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/text-input/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/text-input/vite.config.js b/packages/web-components/examples/components/text-input/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/text-input/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/textarea/.gitignore b/packages/web-components/examples/components/textarea/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/textarea/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/textarea/.sassrc b/packages/web-components/examples/components/textarea/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/textarea/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/textarea/cdn.html b/packages/web-components/examples/components/textarea/cdn.html new file mode 100644 index 000000000000..22154dca0312 --- /dev/null +++ b/packages/web-components/examples/components/textarea/cdn.html @@ -0,0 +1,29 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/textarea/index.html b/packages/web-components/examples/components/textarea/index.html new file mode 100644 index 000000000000..dd166a8b6032 --- /dev/null +++ b/packages/web-components/examples/components/textarea/index.html @@ -0,0 +1,29 @@ + + + + + carbon-web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/textarea/package.json b/packages/web-components/examples/components/textarea/package.json new file mode 100644 index 000000000000..2856a4b88939 --- /dev/null +++ b/packages/web-components/examples/components/textarea/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-textarea-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/textarea/sandbox.config.json b/packages/web-components/examples/components/textarea/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/textarea/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/textarea/src/index.js b/packages/web-components/examples/components/textarea/src/index.js new file mode 100644 index 000000000000..613f3468f3c5 --- /dev/null +++ b/packages/web-components/examples/components/textarea/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/textarea/index.js'; diff --git a/packages/web-components/examples/components/textarea/src/styles.scss b/packages/web-components/examples/components/textarea/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/textarea/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/textarea/vite.config.js b/packages/web-components/examples/components/textarea/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/textarea/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/tile/.gitignore b/packages/web-components/examples/components/tile/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/tile/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/tile/.sassrc b/packages/web-components/examples/components/tile/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/tile/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/tile/cdn.html b/packages/web-components/examples/components/tile/cdn.html new file mode 100644 index 000000000000..363f962f23d3 --- /dev/null +++ b/packages/web-components/examples/components/tile/cdn.html @@ -0,0 +1,31 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + Clickable tile + + + diff --git a/packages/web-components/examples/components/tile/index.html b/packages/web-components/examples/components/tile/index.html new file mode 100644 index 000000000000..d7f75fe7b34c --- /dev/null +++ b/packages/web-components/examples/components/tile/index.html @@ -0,0 +1,32 @@ + + + + + carbon-web-components example + + + + + + + + + + + Clickable tile + + + diff --git a/packages/web-components/examples/components/tile/package.json b/packages/web-components/examples/components/tile/package.json new file mode 100644 index 000000000000..afe82f00699d --- /dev/null +++ b/packages/web-components/examples/components/tile/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-tile-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/tile/sandbox.config.json b/packages/web-components/examples/components/tile/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/tile/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/tile/src/index.js b/packages/web-components/examples/components/tile/src/index.js new file mode 100644 index 000000000000..4b82297648c0 --- /dev/null +++ b/packages/web-components/examples/components/tile/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/tile/index.js'; diff --git a/packages/web-components/examples/components/tile/src/styles.scss b/packages/web-components/examples/components/tile/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/tile/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/tile/vite.config.js b/packages/web-components/examples/components/tile/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/tile/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/toggle/.gitignore b/packages/web-components/examples/components/toggle/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/toggle/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/toggle/.sassrc b/packages/web-components/examples/components/toggle/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/toggle/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/toggle/cdn.html b/packages/web-components/examples/components/toggle/cdn.html new file mode 100644 index 000000000000..70b45948dbd1 --- /dev/null +++ b/packages/web-components/examples/components/toggle/cdn.html @@ -0,0 +1,33 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/toggle/index.html b/packages/web-components/examples/components/toggle/index.html new file mode 100644 index 000000000000..9e4c06a42fa6 --- /dev/null +++ b/packages/web-components/examples/components/toggle/index.html @@ -0,0 +1,33 @@ + + + + + carbon-web-components example + + + + + + + + + + + diff --git a/packages/web-components/examples/components/toggle/package.json b/packages/web-components/examples/components/toggle/package.json new file mode 100644 index 000000000000..4416dac46ba3 --- /dev/null +++ b/packages/web-components/examples/components/toggle/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-toggle-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/toggle/sandbox.config.json b/packages/web-components/examples/components/toggle/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/toggle/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/toggle/src/index.js b/packages/web-components/examples/components/toggle/src/index.js new file mode 100644 index 000000000000..e3da67b6af5c --- /dev/null +++ b/packages/web-components/examples/components/toggle/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/toggle/index.js'; diff --git a/packages/web-components/examples/components/toggle/src/styles.scss b/packages/web-components/examples/components/toggle/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/toggle/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/toggle/vite.config.js b/packages/web-components/examples/components/toggle/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/toggle/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/toggletip/.gitignore b/packages/web-components/examples/components/toggletip/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/toggletip/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/toggletip/.sassrc b/packages/web-components/examples/components/toggletip/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/toggletip/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/toggletip/cdn.html b/packages/web-components/examples/components/toggletip/cdn.html new file mode 100644 index 000000000000..7e2efd9a3897 --- /dev/null +++ b/packages/web-components/examples/components/toggletip/cdn.html @@ -0,0 +1,39 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + +
+ + Toggletip label + +

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+ Test + Button +
+
+ + diff --git a/packages/web-components/examples/components/toggletip/index.html b/packages/web-components/examples/components/toggletip/index.html new file mode 100644 index 000000000000..cbbe0139af48 --- /dev/null +++ b/packages/web-components/examples/components/toggletip/index.html @@ -0,0 +1,49 @@ + + + + + carbon-web-components example + + + + + + + + +
+ + Toggletip label + +

+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

+ Test + Button +
+
+ + diff --git a/packages/web-components/examples/components/toggletip/package.json b/packages/web-components/examples/components/toggletip/package.json new file mode 100644 index 000000000000..e94364b07208 --- /dev/null +++ b/packages/web-components/examples/components/toggletip/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-toggletip-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/toggletip/sandbox.config.json b/packages/web-components/examples/components/toggletip/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/toggletip/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/toggletip/src/index.js b/packages/web-components/examples/components/toggletip/src/index.js new file mode 100644 index 000000000000..b9404739cdfb --- /dev/null +++ b/packages/web-components/examples/components/toggletip/src/index.js @@ -0,0 +1,12 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/toggle-tip/index.js'; +import '@carbon/web-components/es/components/link/index.js'; +import '@carbon/web-components/es/components/button/index.js'; diff --git a/packages/web-components/examples/components/toggletip/src/styles.scss b/packages/web-components/examples/components/toggletip/src/styles.scss new file mode 100644 index 000000000000..2183124956e2 --- /dev/null +++ b/packages/web-components/examples/components/toggletip/src/styles.scss @@ -0,0 +1,18 @@ +/** + * @license + * + * Copyright IBM Corp. 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/toggletip/vite.config.js b/packages/web-components/examples/components/toggletip/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/toggletip/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/tooltip/.gitignore b/packages/web-components/examples/components/tooltip/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/tooltip/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/tooltip/.sassrc b/packages/web-components/examples/components/tooltip/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/tooltip/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/tooltip/cdn.html b/packages/web-components/examples/components/tooltip/cdn.html new file mode 100644 index 000000000000..ffe62d9e2097 --- /dev/null +++ b/packages/web-components/examples/components/tooltip/cdn.html @@ -0,0 +1,76 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + +
+ +
+ +
+ + Occassionally, services are updated in a specified time window to + ensure no down time for customers. + +
+
+ + diff --git a/packages/web-components/examples/components/tooltip/index.html b/packages/web-components/examples/components/tooltip/index.html new file mode 100644 index 000000000000..7238a2825a56 --- /dev/null +++ b/packages/web-components/examples/components/tooltip/index.html @@ -0,0 +1,67 @@ + + + + + carbon-web-components example + + + + + + + + +
+ +
+ +
+ + Occassionally, services are updated in a specified time window to + ensure no down time for customers. + +
+
+ + diff --git a/packages/web-components/examples/components/tooltip/package.json b/packages/web-components/examples/components/tooltip/package.json new file mode 100644 index 000000000000..57c0874b052d --- /dev/null +++ b/packages/web-components/examples/components/tooltip/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-tooltip-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/tooltip/sandbox.config.json b/packages/web-components/examples/components/tooltip/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/tooltip/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/tooltip/src/index.js b/packages/web-components/examples/components/tooltip/src/index.js new file mode 100644 index 000000000000..e60b6e18fe5b --- /dev/null +++ b/packages/web-components/examples/components/tooltip/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/tooltip/index.js'; diff --git a/packages/web-components/examples/components/tooltip/src/styles.scss b/packages/web-components/examples/components/tooltip/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/tooltip/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/tooltip/vite.config.js b/packages/web-components/examples/components/tooltip/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/tooltip/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/examples/components/ui-shell/.gitignore b/packages/web-components/examples/components/ui-shell/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/ui-shell/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/ui-shell/.sassrc b/packages/web-components/examples/components/ui-shell/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/ui-shell/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/ui-shell/cdn.html b/packages/web-components/examples/components/ui-shell/cdn.html new file mode 100644 index 000000000000..dfabf59d9d6e --- /dev/null +++ b/packages/web-components/examples/components/ui-shell/cdn.html @@ -0,0 +1,44 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + [Platform] + + Link 1 + Link 2 + Link 3 + + Sub-link 1 + Sub-link 2 + Sub-link 3 + + + + + diff --git a/packages/web-components/examples/components/ui-shell/index.html b/packages/web-components/examples/components/ui-shell/index.html new file mode 100644 index 000000000000..73c0682befe6 --- /dev/null +++ b/packages/web-components/examples/components/ui-shell/index.html @@ -0,0 +1,45 @@ + + + + + carbon-web-components example + + + + + + + + + + + [Platform] + + Link 1 + Link 2 + Link 3 + + Sub-link 1 + Sub-link 2 + Sub-link 3 + + + + + diff --git a/packages/web-components/examples/components/ui-shell/package.json b/packages/web-components/examples/components/ui-shell/package.json new file mode 100644 index 000000000000..36f99b33d95f --- /dev/null +++ b/packages/web-components/examples/components/ui-shell/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-ui-shell-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/ui-shell/src/index.js b/packages/web-components/examples/components/ui-shell/src/index.js new file mode 100644 index 000000000000..6d44e3a84268 --- /dev/null +++ b/packages/web-components/examples/components/ui-shell/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/ui-shell/index.js'; diff --git a/packages/web-components/examples/components/ui-shell/src/styles.scss b/packages/web-components/examples/components/ui-shell/src/styles.scss new file mode 100644 index 000000000000..5bde587c9b52 --- /dev/null +++ b/packages/web-components/examples/components/ui-shell/src/styles.scss @@ -0,0 +1,9 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/ui-shell/vite.config.js b/packages/web-components/examples/components/ui-shell/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/ui-shell/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/package.json b/packages/web-components/package.json new file mode 100644 index 000000000000..61e6aaaab8dd --- /dev/null +++ b/packages/web-components/package.json @@ -0,0 +1,142 @@ +{ + "name": "@carbon/web-components", + "description": "Web components for the Carbon Design System", + "version": "2.13.1", + "license": "Apache-2.0", + "main": "es/index.js", + "module": "es/index.js", + "repository": { + "type": "git", + "url": "https://github.com/carbon-design-system/carbon.git", + "directory": "packages/web-components" + }, + "bugs": "https://github.com/carbon-design-system/carbon/issues", + "files": [ + "custom-elements.json", + "dist/**/*", + "es/**/*", + "lib/**/*", + "scss/**/*", + "telemetry.yml" + ], + "keywords": [ + "ibm", + "carbon", + "carbon-design-system", + "components", + "web components" + ], + "publishConfig": { + "access": "public", + "provenance": true + }, + "type": "module", + "exports": { + "./es/components/*": { + "default": "./es/components/*" + }, + "./es/globals/": { + "default": "./es/globals/" + }, + "./es": "./es/index.js", + "./es/": "./es/", + "./lib/": "./lib/", + "./dist/": "./dist/", + "./scss/": "./scss/", + "./custom-elements.json": "./custom-elements.json", + "./package.json": "./package.json" + }, + "scripts": { + "prebuild": "node tools/fix-carbon-sass-imports.js", + "build": "yarn clean && node tasks/build-dist.js && node tasks/build.js && yarn wca", + "ci-check": "yarn wca && yarn typecheck", + "clean": "rimraf es lib scss dist storybook-static", + "postinstall": "ibmtelemetry --config=telemetry.yml", + "serve": "node tasks/build.js --serve", + "start": "yarn storybook", + "storybook": "storybook dev -p 6006", + "storybook:build": "storybook build", + "//test": "gulp test && yarn test:integration", + "//test:integration": "yarn test:integration:build && yarn test:integration:ui", + "//test:integration:build": "jest -c tests/integration/build/jest.config.js --runInBand", + "//test:integration:ui": "jest -c tests/integration/ui/jest.config.js --runInBand", + "//test:unit": "gulp test:unit", + "//test:unit:updateSnapshot": "gulp test:unit --update-snapshot", + "typecheck": "tsc --noEmit -p tsconfig.json", + "visual-snapshot": "yarn percy storybook:start ./storybook-static", + "wca": "web-component-analyzer analyze src --outFile custom-elements.json" + }, + "dependencies": { + "@carbon/ibm-products-styles": "^2.30.1", + "@carbon/styles": "1.63.1", + "@floating-ui/dom": "^1.6.3", + "@ibm/telemetry-js": "^1.5.0", + "flatpickr": "4.6.13", + "lit": "^3.1.0", + "lodash-es": "^4.17.21", + "tslib": "^2.6.3" + }, + "devDependencies": { + "@carbon/icon-helpers": "10.47.0", + "@carbon/icons": "^11.31.0", + "@carbon/layout": "^11.26.0", + "@carbon/motion": "^11.22.0", + "@juggle/resize-observer": "^3.4.0", + "@mordech/vite-lit-loader": "^0.31.3", + "@rollup/plugin-alias": "^5.1.0", + "@rollup/plugin-commonjs": "^26.0.0", + "@rollup/plugin-node-resolve": "^15.0.0", + "@rollup/plugin-replace": "^5.0.0", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.0.0", + "@rollup/pluginutils": "^4.2.0", + "@storybook/addon-essentials": "^8.2.8", + "@storybook/addon-links": "^8.2.8", + "@storybook/addon-storysource": "^8.2.8", + "@storybook/blocks": "^8.2.8", + "@storybook/web-components": "^8.2.8", + "@storybook/web-components-vite": "^8.2.8", + "@types/bluebird": "^3.5.36", + "@types/jasmine": "^3.10.2", + "@types/jest": "^29.2.3", + "@types/lodash-es": "^4.17.5", + "@types/node": "^18.11.9", + "@webcomponents/webcomponentsjs": "^2.8.0", + "autoprefixer": "^10.4.0", + "babel-loader": "^8.0.4", + "cssnano": "^7.0.0", + "globby": "^14.0.2", + "is-port-reachable": "^3.1.0", + "null-loader": "^4.0.0", + "prop-types": "^15.7.2", + "read-package-up": "^11.0.0", + "remark-gfm": "^4.0.0", + "rimraf": "^6.0.0", + "rollup": "^2.79.1", + "rollup-plugin-copy": "^3.5.0", + "rollup-plugin-multi-input": "^1.3.1", + "sass": "^1.51.0", + "storybook": "^8.2.8", + "storybook-addon-accessibility-checker": "^3.1.61-rc.3", + "temp": "^0.9.0", + "typescript-config-carbon": "^0.2.0", + "vite": "^5.0.7", + "web-component-analyzer": "2.0.0" + }, + "typings": "es/index.d.ts", + "stylelint": { + "extends": [ + "../../config/stylelint-config-carbon" + ], + "overrides": [ + { + "files": [ + "src/components/**/*.scss" + ], + "rules": { + "max-nesting-depth": null + } + } + ] + } +} diff --git a/packages/web-components/src/coding-conventions.md b/packages/web-components/src/coding-conventions.md new file mode 100644 index 000000000000..1be5f1e17638 --- /dev/null +++ b/packages/web-components/src/coding-conventions.md @@ -0,0 +1,302 @@ + + + +- [Coding conventions](#coding-conventions) + - [Linters/formatters](#lintersformatters) + - [TSDoc comments](#tsdoc-comments) + - [No kitchen-sink "base" class and using mix-in](#no-kitchen-sink-base-class-and-using-mix-in) + - [Lifecycle management](#lifecycle-management) + - [Component styles for different component states/variants](#component-styles-for-different-component-statesvariants) + - [Customizing components](#customizing-components) + - [Defining (default) component options](#defining-default-component-options) + - [Component variants with different options](#component-variants-with-different-options) + - [Areas to make them configurable as component options](#areas-to-make-them-configurable-as-component-options) + - [Areas where component optinos are _not_ applied](#areas-where-component-optinos-are-_not_-applied) + - [Creating inherited components](#creating-inherited-components) + - [Polymorphism with static properties](#polymorphism-with-static-properties) + - [Custom events](#custom-events) + - [Globalization](#globalization) + - [Translation](#translation) + - [Collation](#collation) + - [Null checks](#null-checks) + - [Updating view upon change in `private`/`protected` properties](#updating-view-upon-change-in-privateprotected-properties) + - [CSS considerations with IE11](#css-considerations-with-ie11) + - [Custom element registration](#custom-element-registration) + - [Propagating misc attributes from shadow host to an element in shadow DOM](#propagating-misc-attributes-from-shadow-host-to-an-element-in-shadow-dom) + - [Private properties](#private-properties) + - [Component-specific considerations](#component-specific-considerations) + + + +# Coding conventions + +## Linters/formatters + +`carbon-web-components` uses ESLint with `typescript-eslint` for linting, and +Prettier for code formatting. Most of ESLint configurations are same as ones in +`carbon-components`. + +## TSDoc comments + +In addition to using TypeScript, we try to leverage editors' code assistance +feature as much as possible. + +For that purpose, we add TSDoc comments to the following: + +- All classes +- All properties/methods (including private properties), only exception here is + one being overriden +- All type definitions (e.g. `interface`, `enum`) + +## No kitchen-sink "base" class and using mix-in + +We strive to avoid kitchen-sink "base" class, for the sake of maintenability and +avoiding code bloat. Toward that goal, we use mix-in classes. Instead of +manipulating prototype, we simply use ECMAScript class feature +([Subclass Factory Pattern](https://github.com/justinfagnani/proposal-mixins#subclass-factory-pattern)), +which is, something like: + +```typescript +const Mixin = >(Base: T) => class extends Base { + ... + + someProperty = someValue; + someMethod() { ... } + + ... +}; +``` + +## Lifecycle management + +To avoid memory leaks and zombie event listeners, we ensure the event listeners +on custom elements themselves (hosts) and ones on `document`, etc. are released +when they get out of render tree. + +For that purpose, `carbon-web-components` uses `@HostListener(type, options)` +decorator. `@HostListener(type, options)` decorator works with a custom element +class inheriting `HostListenerMixin()` and attaches an event listener using the +target method as the listener. The `type` argument can be something like +`document:click` so the `click` event listener is attached to `document`. + +Here's an example seen in `` code: + +```typescript +... +import HostListener from '../../globals/decorators/HostListener'; +import HostListenerMixin from '../../globals/mixins/HostListener'; +... + +@customElement(`${prefix}-modal` as any) +class CDSModal extends HostListenerMixin(LitElement) { + ... + + @HostListener('click') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleClick = (event: MouseEvent) => { + ... + }; + + ... +} +``` + +## Component styles for different component states/variants + +Carbon core CSS uses BEM modifier like `cds--btn--danger` to style different +states/variants of a component. + +OTOH `carbon-web-components` uses attributes to represent different +states/variants (e.g. ``), in a similar manner as how +attributes influence states/variants of native elements (e.g. +``). + +If such states/variants should affect the style of custom element (shadow host), +we define attribute styles from the following reasons: + +- Taking a cue from native elements with user agent shadow DOM (e.g. UA + stylesheet for ``) +- [Adding CSS classes on our custom elements by ourselves may conflict with CSS classes set by consumers](https://developers.google.com/web/fundamentals/web-components/best-practices#do-not-self-apply-classes) + +## Customizing components + +Like `carbon-components` library does, `carbon-web-components` ensures +components are written in a flexible manner enough to support use cases +different applications have. + +### Defining (default) component options + +Component options are defined as static properties of custom element class, +instead of in `options` object seen in `carbon-components`. + +The primary reason for the difference is that +[there is no support for constructor arguments in Custom Elements](https://github.com/w3c/webcomponents/issues/605) +and the use case for using constructor for Custom Elements is rare. It makes +instance-level configuration unrealistic. + +### Component variants with different options + +A component variant with different options can be created by creating a derived +class which overrides static properties of component options. + +#### Areas to make them configurable as component options + +| Area | Example of component option (static property) name | Remarks | +| ------------------------------------------------------------------------------------------------------ | -------------------------------------------------- | ---------------------------------------------------------------------- | +| CSS selectors/classes used in imperative DOM API calls (Doing so allows overriding `.render()` method) | `selectorNonSelectedItem` | An exception is where `lit-element`'s `@query` decorator is applicable | +| [Custom event](#custom-events) names | `eventBeforeSelect` | | + +#### Areas where component optinos are _not_ applied + +- CSS classes used in template (Should be done by overriding `.render()` method) + +### Creating inherited components + +This codebase intends to support the components being inherited, to some extent. +e.g. Compoennts with different options described above. To support that, it's +easier for all properties/methods exposed as `protected`, but it exposes a risk +of the component internals being poked around. The current guideline for using +`protected` is the following: + +- Ones where override happens within this component library (e.g. + `` inheriting ``) +- Element ID's auto-generation logic +- (Possibly some more, e.g. ones whose API are stable enough) + +## Polymorphism with static properties + +To support +[polymorphism with static properties](https://github.com/Microsoft/TypeScript/issues/3841)... + +We do: + +```typescript +(this.constructor as typeof CustomElementClass).staticPropName; +``` + +```typescript +(customElementInstance.constructor as typeof CustomElementClass).staticPropName; +``` + +We don't: + +```typescript +CustomElementClass.staticPropName; +``` + +## Custom events + +Wherever it makes sense, `carbon-web-components` translates user-initiated +events to something that gives event listeners more context of what they mean. +For example, `` translates `click` event on +`` to `cds-modal-beingclosed` and `cds-modal-closed` +custom events. + +`cds-modal-beingclosed` is cancelable in a similar manner as how `click` event +on `` is cancelable; If `cds-modal-beingclosed` is canceled, +`` stops closing itself. + +We define custom event names as static properties so derived classes can +customize them. + +## Globalization + +### Translation + +Like what most of native elements do, the primary means to handle translatable +strings is let user put them in DOM, e.g. in attributes, child (text) nodes. + +Some translatable strings are specified as a property, whose value is a function +that takes a key-value map (object) as the arguments and returns the +translatable string, e.g. +`` ({ start, end, total }) => `${start}–${end} of ${total} item${total <= 1 ? '' : 's'}` ``. +This is for supporting locale-specific pluralization, etc. that require string +interpolation as well as the logic to dictate the locale-specific rule of +pluralization. + +The only exception to the above rules is `` which uses the +`locale` property for all locale-specific info since there is a huge amount of +translatable strings. + +### Collation + +To avoid problems with collation, the primary means for user to determine order +in list item is ordering them in DOM, for example: + +```html + + Option 1 + Option 2 + Option 3 + +``` + +## Null checks + +If you get TypeScript "may be null" errors, think twice to see if there is such +edge case: + +- If some other portion of your code ensures the `null` condition won't happen + and nothing else is likely to break it, use the non-null assertion operator + (`!`) - But don't blindly do so. +- Otherwise, add code to perform a `null` check by doing one of the following: + - Throw an exception that explains why the `null` value won't be acceptable + and (if applicable) what mistake may cause that wrong condition + - Make the code no-op for `null` value, e.g. with optional chaining (`?.`) + - Provide a fallback value, e.g. with null coalescing (`??`) + +## Updating view upon change in `private`/`protected` properties + +`lit-element` observes for changes in declared properties for updating the view. +`carbon-web-components` codebase doesn't use this feature simply to get +properties observed. Specifically, `carbon-web-components` doesn't set +`private`/`protected` properties as declared. Whenever change in +`private`/`protected` should cause update in the view, we take manual approach +(`.requestUpdate()`). + +## CSS considerations with IE11 + +We use ShadyCSS shim as the emulation of scoped CSS in shadow DOM in IE11. There +is one notable limitation with that; It appears that +`:host(cds-foo) ::slotted(cds-bar)` selector does not work in ShadyCSS unless +`` is a direct child of the shadow root. There was an issue in ShadyCSS +repo (https://github.com/webcomponents/shadycss/issues/5) that seems to have +explained that in detail, but the repository has been deleted somehow. + +To make such case work for ShadyCSS, we add a CSS class to an ancestor of +`` in shadow DOM, and use `.cds-ce--some-class ::slotted(cds-bar)` +selector. + +## Custom element registration + +This library registers custom elements to global `window` automatically upon +importing the corresponding modules. It may not be desirable in two scenarios: + +- One is when consumer wants to customize our custom element's behavior before + it's registered. In such case, consumer can create a derived class and + register it with a different custom element name. +- Another, though the use case is rare, is using our custom element in a + different realm. In such case, consumer can re-register the custom element in + the realm. + +## Propagating misc attributes from shadow host to an element in shadow DOM + +Some components, e.g. ``, simply represent the content in shadow +DOM, e.g. ` +
+
+ +
+
+ `; + } + + /** + * The CSS classes for breakpoints. + * + * @private + */ + static get _classesBreakpoints() { + return { + [ACCORDION_ITEM_BREAKPOINT.SMALL]: `${prefix}-ce--accordion__content--${ACCORDION_ITEM_BREAKPOINT.SMALL}`, + [ACCORDION_ITEM_BREAKPOINT.MEDIUM]: `${prefix}-ce--accordion__content--${ACCORDION_ITEM_BREAKPOINT.MEDIUM}`, + }; + } + + /** + * The breakpoints. + * + * @private + */ + static get _sizesBreakpoints() { + return { + [ACCORDION_ITEM_BREAKPOINT.SMALL]: 480, + [ACCORDION_ITEM_BREAKPOINT.MEDIUM]: 640, + }; + } + + /** + * The name of the custom event fired before this accordion item is being toggled upon a user gesture. + * Cancellation of this event stops the user-initiated action of toggling this accordion item. + */ + static get eventBeforeToggle() { + return `${prefix}-accordion-item-beingtoggled`; + } + + /** + * The name of the custom event fired after this accordion item is toggled upon a user gesture. + */ + static get eventToggle() { + return `${prefix}-accordion-item-toggled`; + } + + static get selectorAccordionContent() { + return `.${prefix}--accordion__content`; + } + + static styles = styles; +} + +export default CDSAccordionItem; diff --git a/packages/web-components/src/components/accordion/accordion-skeleton.ts b/packages/web-components/src/components/accordion/accordion-skeleton.ts new file mode 100644 index 000000000000..84ba24ebe6dd --- /dev/null +++ b/packages/web-components/src/components/accordion/accordion-skeleton.ts @@ -0,0 +1,130 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { ACCORDION_ALIGNMENT } from './accordion'; +import { forEach } from '../../globals/internal/collection-helpers'; +import ChevronRight16 from '@carbon/icons/lib/chevron--right/16'; +import './accordion-item-skeleton'; +import '../skeleton-text/index'; +import styles from './accordion.scss?lit'; + +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Skeleton of code snippet. + */ +@customElement(`${prefix}-accordion-skeleton`) +class CDSAccordionSkeleton extends LitElement { + /** + * Specify the alignment of the accordion heading title and chevron + */ + @property({ reflect: true }) + alignment = ACCORDION_ALIGNMENT.END; + + /** + * Set number of items to render + */ + @property({ type: Number, attribute: 'count' }) + count = 4; + + /** + * Specify whether Accordion text should be flush, default is false, does not work with align="start" + */ + @property({ type: Boolean, reflect: true }) + isFlush = false; + + /** + * `true` if the first accordion item should be open. + */ + @property({ type: Boolean, reflect: true }) + open = true; + + updated(changedProperties) { + if (changedProperties.has('alignment')) { + // Propagate `alignment` attribute to descendants until `:host-context()` gets supported in all major browsers + forEach( + this.shadowRoot!.querySelectorAll( + (this.constructor as typeof CDSAccordionSkeleton) + .selectorAccordionItemSkeletons + ), + (elem) => { + elem.setAttribute('alignment', this.alignment); + } + ); + } + if ( + changedProperties.has('isFlush') || + changedProperties.has('alignment') + ) { + // Propagate `isFlush` attribute to descendants until `:host-context()` gets supported in all major browsers + forEach( + this.shadowRoot!.querySelectorAll( + (this.constructor as typeof CDSAccordionSkeleton) + .selectorAccordionItemSkeletons + ), + (elem) => { + this.isFlush && this.alignment !== 'start' + ? elem.setAttribute('isFlush', '') + : elem.removeAttribute('isFlush'); + } + ); + } + } + + render() { + const classes = classMap({ + [`${prefix}--accordion__item`]: true, + [`${prefix}--accordion__item--active`]: true, + [`${prefix}--accordion--${this.alignment}`]: this.alignment, + [`${prefix}--accordion--flush`]: + this.isFlush && this.alignment !== 'start', + }); + const numSkeletonItems = this.open ? this.count - 1 : this.count; + return html` + ${this.open + ? html` +
  • + + ${ChevronRight16({ + part: 'expando-icon', + class: `${prefix}--accordion__arrow`, + })} + + +
    + + + +
    +
  • + ` + : ``} + ${Array.from(new Array(numSkeletonItems)).map( + (_, index) => + html` + + ` + )} + `; + } + + static get selectorAccordionItemSkeletons() { + return `${prefix}-accordion-item-skeleton`; + } + + static styles = styles; +} + +export default CDSAccordionSkeleton; diff --git a/packages/web-components/src/components/accordion/accordion.mdx b/packages/web-components/src/components/accordion/accordion.mdx new file mode 100644 index 000000000000..3ba5527286e6 --- /dev/null +++ b/packages/web-components/src/components/accordion/accordion.mdx @@ -0,0 +1,93 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as AccordionStories from './accordion.stories'; + + + +# Accordion + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/accordion) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/accordion) + +The accordion component delivers large amounts of content in a small space +through progressive disclosure. That is, the user gets key details about the +underlying content and can choose to expand that content within the constraints +of the accordion. Accordions work especially well on mobile interfaces or +whenever vertical space is at a premium. + +Avoid “nested” accordions—that is, collapsible content within collapsible +content. This type of pattern goes against UX best practices. + +The Carbon accordion allows for multiple sections to be expanded simultaneously. + +A chevron is used to indicate the “expand/collapse” action, though the entire +header area is clickable for the same action. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/accordion/index.js'; +``` + +{`${cdnJs({ components: ['accordion'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim + veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea + commodo consequat. +

    +
    + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim + veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea + commodo consequat. +

    +
    + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim + veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea + commodo consequat. +

    +
    + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim + veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea + commodo consequat. +

    +
    +
    +``` + +### HTML (skeleton) + +```html + +``` + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `open` attribute). + + diff --git a/packages/web-components/src/components/accordion/accordion.scss b/packages/web-components/src/components/accordion/accordion.scss new file mode 100644 index 000000000000..62eb8df21263 --- /dev/null +++ b/packages/web-components/src/components/accordion/accordion.scss @@ -0,0 +1,101 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/type' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/components/accordion'; +@use '@carbon/styles/scss/layout' as *; + +:host(#{$prefix}-accordion), +:host(#{$prefix}-accordion-skeleton) { + @extend .#{$prefix}--accordion; + @include emit-layout-tokens(); +} + +:host(#{$prefix}-accordion-item), +:host(#{$prefix}-accordion-item-skeleton) { + @extend .#{$prefix}--accordion__item; + + display: block; + outline: none; + .#{$prefix}--accordion__content { + @extend .#{$prefix}--accordion__content; + + ::slotted(p) { + @include type-style('body-01'); + + margin: 0; + } + } +} + +:host(#{$prefix}-accordion-item[size='sm']), +:host(#{$prefix}-accordion-item-skeleton[size='sm']) { + button { + @extend .#{$prefix}--layout--size-sm; + + min-block-size: var(--cds-layout-size-height-context); + } +} + +:host(#{$prefix}-accordion-item[size='lg']), +:host(#{$prefix}-accordion-item-skeleton[size='lg']) { + button { + @extend .#{$prefix}--layout--size-lg; + + min-block-size: var(--cds-layout-size-height-context); + } +} + +:host(#{$prefix}-accordion-item[alignment='start']), +:host(#{$prefix}-accordion-item-skeleton[alignment='start']) { + @extend .#{$prefix}--accordion--start; +} + +:host(#{$prefix}-accordion-item[isFlush]), +:host(#{$prefix}-accordion-item-skeleton[isFlush]) { + @extend .#{$prefix}--accordion--flush; +} + +:host(#{$prefix}-accordion-item[expanding]) { + @extend .#{$prefix}--accordion__item--expanding; +} + +:host(#{$prefix}-accordion-item[collapsing]) { + @extend .#{$prefix}--accordion__item--collapsing; +} + +:host(#{$prefix}-accordion-item[open]:not([disabled])) { + @extend .#{$prefix}--accordion__item--active; + + .#{$prefix}--accordion__content { + padding-inline-end: $spacing-05; + } + + .#{$prefix}-ce--accordion__content--sm { + padding-inline-end: $spacing-09; + } + + .#{$prefix}-ce--accordion__content--md { + padding-inline-end: 25%; + } +} + +:host(#{$prefix}-accordion-skeleton), +:host(#{$prefix}-accordion-item-skeleton) { + .#{$prefix}--accordion__heading { + cursor: default; + + &:hover::before { + background: transparent; + } + } +} diff --git a/packages/web-components/src/components/accordion/accordion.stories.ts b/packages/web-components/src/components/accordion/accordion.stories.ts new file mode 100644 index 000000000000..d879af158362 --- /dev/null +++ b/packages/web-components/src/components/accordion/accordion.stories.ts @@ -0,0 +1,209 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../globals/settings'; +import { ACCORDION_SIZE } from './accordion'; +import './index'; +import '../button/index'; + +const sizes = { + [`Small size (${ACCORDION_SIZE.SMALL})`]: ACCORDION_SIZE.SMALL, + [`Medium size (${ACCORDION_SIZE.MEDIUM})`]: ACCORDION_SIZE.MEDIUM, + [`Large size (${ACCORDION_SIZE.LARGE})`]: ACCORDION_SIZE.LARGE, +}; + +const args = { + alignment: 'end', + disabled: false, + isFlush: false, + size: ACCORDION_SIZE.MEDIUM, + disableToggle: false, +}; + +const argTypes = { + alignment: { + control: 'select', + description: + 'Specify the alignment of the accordion heading title and chevron.', + options: ['start', 'end'], + }, + disabled: { + control: 'boolean', + description: + 'Specify whether an individual AccordionItem should be disabled.', + }, + isFlush: { + control: 'boolean', + description: + 'Specify whether Accordion text should be flush, default is false, does not work with align="start".', + }, + size: { + control: 'select', + description: 'Specify the size of the Accordion.', + options: sizes, + }, + disableToggle: { + control: 'boolean', + description: `Disable user-initiated toggle action (Call event.preventDefault() in ${prefix}-accordion-beingtoggled event).`, + }, + onBeforeToggle: { + action: `${prefix}-accordion-item-beingtoggled`, + }, + onToggle: { + action: `${prefix}-accordion-item-toggled`, + }, +}; + +export const Default = { + // This story doesn't accept any args. + args: {}, + argTypes: {}, + render: () => { + return html` + + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim + ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

    +
    + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim + ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

    +
    + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim + ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

    +
    + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim + ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

    +
    +
    + `; + }, +}; + +export const Skeleton = { + args: { + alignment: args['alignment'], + isFlush: args['isFlush'], + }, + argTypes: { + alignment: argTypes['alignment'], + isFlush: argTypes['isFlush'], + }, + decorators: [ + (story) => { + return html`
    ${story()}
    `; + }, + ], + parameters: { + percy: { + skip: true, + }, + }, + render: (args) => { + const { alignment, isFlush } = args ?? {}; + return html` + + + `; + }, +}; + +const noop = () => {}; + +export const Playground = { + args, + argTypes, + parameters: { + percy: { + skip: true, + }, + }, + render: (args) => { + const { + disabled, + disableToggle, + onBeforeToggle = noop, + onToggle = noop, + size, + alignment, + isFlush, + } = args ?? {}; + const handleBeforeToggle = (event: CustomEvent) => { + onBeforeToggle(event); + if (disableToggle) { + event.preventDefault(); + } + }; + + return html` + + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim + ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

    +
    + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim + ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

    +
    + + This is a button. + + + + Section 4 title (the title can be a node) + +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim + ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat. +

    +
    +
    + `; + }, +}; + +const meta = { + title: 'Components/Accordion', +}; + +export default meta; diff --git a/packages/web-components/src/components/accordion/accordion.ts b/packages/web-components/src/components/accordion/accordion.ts new file mode 100644 index 000000000000..f4f43b99a797 --- /dev/null +++ b/packages/web-components/src/components/accordion/accordion.ts @@ -0,0 +1,104 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { forEach } from '../../globals/internal/collection-helpers'; +import { ACCORDION_SIZE, ACCORDION_ALIGNMENT } from './defs'; +import styles from './accordion.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { ACCORDION_SIZE, ACCORDION_ALIGNMENT }; + +/** + * Accordion container. + * + * @element cds-accordion + */ +@customElement(`${prefix}-accordion`) +class CDSAccordion extends LitElement { + /** + * Accordion size should be sm, md, lg. + */ + @property({ reflect: true }) + size = ACCORDION_SIZE.MEDIUM; + + /** + * Specify the alignment of the accordion heading title and chevron + */ + @property({ reflect: true }) + alignment = ACCORDION_ALIGNMENT.END; + + /** + * Specify whether Accordion text should be flush, default is false, does not work with align="start" + */ + @property({ type: Boolean, reflect: true }) + isFlush = false; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'list'); + } + super.connectedCallback(); + } + + updated(changedProperties) { + if (changedProperties.has('size')) { + // Propagate `size` attribute to descendants until `:host-context()` gets supported in all major browsers + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSAccordion).selectorAccordionItems + ), + (elem) => { + elem.setAttribute('size', this.size); + } + ); + } + if (changedProperties.has('alignment')) { + // Propagate `alignment` attribute to descendants until `:host-context()` gets supported in all major browsers + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSAccordion).selectorAccordionItems + ), + (elem) => { + elem.setAttribute('alignment', this.alignment); + } + ); + } + if ( + changedProperties.has('isFlush') || + changedProperties.has('alignment') + ) { + // Propagate `isFlush` attribute to descendants until `:host-context()` gets supported in all major browsers + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSAccordion).selectorAccordionItems + ), + (elem) => { + this.isFlush && this.alignment !== 'start' + ? elem.setAttribute('isFlush', '') + : elem.removeAttribute('isFlush'); + } + ); + } + } + + render() { + return html` `; + } + + static get selectorAccordionItems() { + return `${prefix}-accordion-item`; + } + + static styles = styles; +} + +export default CDSAccordion; diff --git a/packages/web-components/src/components/accordion/defs.ts b/packages/web-components/src/components/accordion/defs.ts new file mode 100644 index 000000000000..e5667704b6fa --- /dev/null +++ b/packages/web-components/src/components/accordion/defs.ts @@ -0,0 +1,58 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Breakpoints for accordion items. It's different from one in `@carbon/layout` library. + */ +export enum ACCORDION_ITEM_BREAKPOINT { + /** + * Small breakpoint. + */ + SMALL = 'sm', + + /** + * Medium breakpoint. + */ + MEDIUM = 'md', +} + +/** + * Accordion size. + */ +export enum ACCORDION_SIZE { + /** + * Small size. + */ + SMALL = 'sm', + + /** + * Medium size. + */ + MEDIUM = 'md', + + /** + * Large size. + */ + LARGE = 'lg', +} + +/** + * Specify the alignment of the accordion heading title and chevron. + */ +export enum ACCORDION_ALIGNMENT { + /** + * Alignment to the start + */ + START = 'start', + + /** + * Alignment to the end + */ + END = 'END', +} diff --git a/packages/web-components/src/components/accordion/docs/overview.mdx b/packages/web-components/src/components/accordion/docs/overview.mdx new file mode 100644 index 000000000000..b0fbd2b91ee0 --- /dev/null +++ b/packages/web-components/src/components/accordion/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/accordion/index.ts b/packages/web-components/src/components/accordion/index.ts new file mode 100644 index 000000000000..0857ea9a9db5 --- /dev/null +++ b/packages/web-components/src/components/accordion/index.ts @@ -0,0 +1,13 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './accordion'; +import './accordion-item'; +import './accordion-item-skeleton'; +import './accordion-skeleton'; diff --git a/packages/web-components/src/components/ai-skeleton/ai-skeleton-icon.stories.ts b/packages/web-components/src/components/ai-skeleton/ai-skeleton-icon.stories.ts new file mode 100644 index 000000000000..ee212db5bd6e --- /dev/null +++ b/packages/web-components/src/components/ai-skeleton/ai-skeleton-icon.stories.ts @@ -0,0 +1,34 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './ai-skeleton-icon'; + +export const Default = { + // This story doesn't accept any args. + args: {}, + argTypes: {}, + parameters: { + percy: { + skip: true, + }, + }, + render: () => { + return html` + `; + }, +}; + +const meta = { + title: 'Experimental/AISkeleton/AISkeletonIcon', +}; + +export default meta; diff --git a/packages/web-components/src/components/ai-skeleton/ai-skeleton-icon.ts b/packages/web-components/src/components/ai-skeleton/ai-skeleton-icon.ts new file mode 100644 index 000000000000..484771536033 --- /dev/null +++ b/packages/web-components/src/components/ai-skeleton/ai-skeleton-icon.ts @@ -0,0 +1,39 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import { property } from 'lit/decorators.js'; +import styles from './ai-skeleton.scss?lit'; +import '../skeleton-icon/skeleton-icon'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * AI skeleton icon. + * + * @element cds-ai-skeleton-icon + */ +@customElement(`${prefix}-ai-skeleton-icon`) +class CDSAISkeletonIcon extends LitElement { + /** + * Custom styles to apply to skeleton icon + */ + @property({ attribute: 'custom-styles' }) + customStyles = ''; + + render() { + return html``; + } + + static styles = styles; +} + +export default CDSAISkeletonIcon; diff --git a/packages/web-components/src/components/ai-skeleton/ai-skeleton-placeholder.stories.ts b/packages/web-components/src/components/ai-skeleton/ai-skeleton-placeholder.stories.ts new file mode 100644 index 000000000000..ddea410efd92 --- /dev/null +++ b/packages/web-components/src/components/ai-skeleton/ai-skeleton-placeholder.stories.ts @@ -0,0 +1,32 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './ai-skeleton-placeholder'; + +export const Default = { + // This story doesn't accept any args. + args: {}, + argTypes: {}, + parameters: { + percy: { + skip: true, + }, + }, + render: () => { + return html``; + }, +}; + +const meta = { + title: 'Experimental/AISkeleton/AISkeletonPlaceholder', +}; + +export default meta; diff --git a/packages/web-components/src/components/ai-skeleton/ai-skeleton-placeholder.ts b/packages/web-components/src/components/ai-skeleton/ai-skeleton-placeholder.ts new file mode 100644 index 000000000000..4591bf54d021 --- /dev/null +++ b/packages/web-components/src/components/ai-skeleton/ai-skeleton-placeholder.ts @@ -0,0 +1,31 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './ai-skeleton.scss?lit'; +import '../skeleton-placeholder/skeleton-placeholder'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * AI skeleton placeholder. + * + * @element cds-ai-skeleton-placeholder + */ +@customElement(`${prefix}-ai-skeleton-placeholder`) +class CDSAISkeletonPlaceholder extends LitElement { + render() { + return html``; + } + + static styles = styles; +} + +export default CDSAISkeletonPlaceholder; diff --git a/packages/web-components/src/components/ai-skeleton/ai-skeleton-text.stories.ts b/packages/web-components/src/components/ai-skeleton/ai-skeleton-text.stories.ts new file mode 100644 index 000000000000..0f0c6bc27021 --- /dev/null +++ b/packages/web-components/src/components/ai-skeleton/ai-skeleton-text.stories.ts @@ -0,0 +1,76 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './ai-skeleton-text'; + +const args = { + heading: false, + paragraph: false, + width: '100%', + lineCount: 3, +}; + +const argTypes = { + heading: { + control: 'boolean', + description: 'Heading (heading)', + }, + paragraph: { + control: 'boolean', + description: 'Paragraph (paragraph)', + }, + width: { + control: 'text', + description: 'Width (width)', + }, + lineCount: { + control: 'number', + description: 'Line count (linecount)', + }, +}; + +export const Default = { + // This story doesn't accept any args. + args: {}, + argTypes: {}, + parameters: { + percy: { + skip: true, + }, + }, + render: () => { + return html``; + }, +}; + +export const Playground = { + args, + argTypes, + parameters: { + percy: { + skip: true, + }, + }, + render: (args) => { + const { heading, paragraph, width, lineCount } = args ?? {}; + + return html``; + }, +}; + +const meta = { + title: 'Experimental/AISkeleton/AISkeletonText', +}; + +export default meta; diff --git a/packages/web-components/src/components/ai-skeleton/ai-skeleton-text.ts b/packages/web-components/src/components/ai-skeleton/ai-skeleton-text.ts new file mode 100644 index 000000000000..bb4473366761 --- /dev/null +++ b/packages/web-components/src/components/ai-skeleton/ai-skeleton-text.ts @@ -0,0 +1,61 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './ai-skeleton.scss?lit'; +import '../skeleton-text/skeleton-text'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * AI skeleton text. + * + * @element cds-ai-skeleton-text + */ +@customElement(`${prefix}-ai-skeleton-text`) +class CDSAISkeletonText extends LitElement { + /** + * Generates skeleton text at a larger size. + */ + @property({ type: Boolean, reflect: true }) + heading = false; + + /** + * width (in px or %) of single line of text or max-width of paragraph lines + */ + @property({ reflect: true }) + width = '100%'; + + /** + * will generate multiple lines of text + */ + @property({ type: Boolean, reflect: true }) + paragraph = false; + + /** + * the number of lines in a paragraph + */ + @property({ type: Number, reflect: true }) + lineCount = 3; + + render() { + const { heading, width, lineCount, paragraph } = this; + return html``; + } + + static styles = styles; +} + +export default CDSAISkeletonText; diff --git a/packages/web-components/src/components/ai-skeleton/ai-skeleton.mdx b/packages/web-components/src/components/ai-skeleton/ai-skeleton.mdx new file mode 100644 index 000000000000..37d66d58e7a5 --- /dev/null +++ b/packages/web-components/src/components/ai-skeleton/ai-skeleton.mdx @@ -0,0 +1,46 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as AISkeletonStories from './ai-skeleton-placeholder.stories'; + + + +# AI Skeleton placeholder + +> 💡 Check our +> [CodeSandbox](https://codesandbox.io/s/github/carbon-design-system/carbon-for-ibm-dotcom/tree/main/packages/carbon-web-components/examples/codesandbox/basic/components/ai-skeleton) +> example implementation. + +[![Edit carbon-web-components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/carbon-design-system/carbon-for-ibm-dotcom/tree/main/packages/carbon-web-components/examples/codesandbox/basic/components/ai-skeleton) + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/ai-skeleton/index.js'; +``` + +{`${cdnJs({ components: ['ai-skeleton'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + + +``` + +## `` attributes, properties and events + + + +## `` attributes, properties and events + + + +## `` attributes, properties and events + + diff --git a/packages/web-components/src/components/ai-skeleton/ai-skeleton.scss b/packages/web-components/src/components/ai-skeleton/ai-skeleton.scss new file mode 100644 index 000000000000..27ac2961a6c1 --- /dev/null +++ b/packages/web-components/src/components/ai-skeleton/ai-skeleton.scss @@ -0,0 +1,10 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '../skeleton-text/skeleton-text'; +@use '../skeleton-icon/skeleton-icon'; +@use '../skeleton-placeholder/skeleton-placeholder'; diff --git a/packages/web-components/src/components/ai-skeleton/docs/overview.mdx b/packages/web-components/src/components/ai-skeleton/docs/overview.mdx new file mode 100644 index 000000000000..f2dfc95813f3 --- /dev/null +++ b/packages/web-components/src/components/ai-skeleton/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/ai-skeleton/index.ts b/packages/web-components/src/components/ai-skeleton/index.ts new file mode 100644 index 000000000000..38e06095938e --- /dev/null +++ b/packages/web-components/src/components/ai-skeleton/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './ai-skeleton-icon'; +import './ai-skeleton-placeholder'; +import './ai-skeleton-text'; diff --git a/packages/web-components/src/components/breadcrumb/breadcrumb-item.ts b/packages/web-components/src/components/breadcrumb/breadcrumb-item.ts new file mode 100644 index 000000000000..248d072ad63d --- /dev/null +++ b/packages/web-components/src/components/breadcrumb/breadcrumb-item.ts @@ -0,0 +1,36 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './breadcrumb.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Breadcrumb item. + * + * @element cds-breadcrumb-item + */ +@customElement(`${prefix}-breadcrumb-item`) +class CDSBreadcrumbItem extends LitElement { + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'listitem'); + } + super.connectedCallback(); + } + + render() { + return html` `; + } + + static styles = styles; +} + +export default CDSBreadcrumbItem; diff --git a/packages/web-components/src/components/breadcrumb/breadcrumb-link.ts b/packages/web-components/src/components/breadcrumb/breadcrumb-link.ts new file mode 100644 index 000000000000..0d0f2f0d4c54 --- /dev/null +++ b/packages/web-components/src/components/breadcrumb/breadcrumb-link.ts @@ -0,0 +1,33 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../globals/settings'; +import CDSLink from '../link/link'; +import styles from './breadcrumb.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Link in breadcrumb. + * + * @element cds-breadcrumb-link + */ +@customElement(`${prefix}-breadcrumb-link`) +class CDSBreadcrumbLink extends CDSLink { + render() { + return html` + ${this.href + ? super.render() + : html``} + `; + } + static styles = styles; +} + +export default CDSBreadcrumbLink; diff --git a/packages/web-components/src/components/breadcrumb/breadcrumb-overflow-menu.ts b/packages/web-components/src/components/breadcrumb/breadcrumb-overflow-menu.ts new file mode 100644 index 000000000000..b5479589ae48 --- /dev/null +++ b/packages/web-components/src/components/breadcrumb/breadcrumb-overflow-menu.ts @@ -0,0 +1,37 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../globals/settings'; +import OverflowMenuHorizontal16 from '@carbon/icons/lib/overflow-menu--horizontal/16'; +import CDSOverflowMenu from '../overflow-menu/overflow-menu'; +import styles from './breadcrumb.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Overflow menu in breadcrumb. + * + * @element cds-breadcrumb-overflow-menu + */ +@customElement(`${prefix}-breadcrumb-overflow-menu`) +class CDSBreadcrumbOverflowMenu extends CDSOverflowMenu { + render() { + return html` + + ${OverflowMenuHorizontal16({ + class: `${prefix}--overflow-menu__icon`, + })} + + `; + } + + static styles = styles; +} + +export default CDSBreadcrumbOverflowMenu; diff --git a/packages/web-components/src/components/breadcrumb/breadcrumb-skeleton.ts b/packages/web-components/src/components/breadcrumb/breadcrumb-skeleton.ts new file mode 100644 index 000000000000..409dee39b0eb --- /dev/null +++ b/packages/web-components/src/components/breadcrumb/breadcrumb-skeleton.ts @@ -0,0 +1,39 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './breadcrumb.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +const renderItem = () => { + return html` +
    +   +
    + `; +}; + +/** + * Skeleton of breadcrumb. + */ +@customElement(`${prefix}-breadcrumb-skeleton`) +class CDSBreadcrumbSkeleton extends LitElement { + render() { + return html` +
    + ${renderItem()} ${renderItem()} ${renderItem()} +
    + `; + } + + static styles = styles; +} + +export default CDSBreadcrumbSkeleton; diff --git a/packages/web-components/src/components/breadcrumb/breadcrumb.mdx b/packages/web-components/src/components/breadcrumb/breadcrumb.mdx new file mode 100644 index 000000000000..723bec12abb0 --- /dev/null +++ b/packages/web-components/src/components/breadcrumb/breadcrumb.mdx @@ -0,0 +1,126 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as BreadcrumbStories from './breadcrumb.stories'; + + + +# Breadcrumb + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/breadcrumb) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/breadcrumb) + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/breadcrumb/index.js'; +``` + +{`${cdnJs({ components: ['breadcrumb'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + + Breadcrumb 1 + + + Breadcrumb 2 + + + Breadcrumb 3 + + + Breadcrumb 4 + + +``` + +### HTML (with overflow-menu) + +```html + + + Breadcrumb 1 + + + Breadcrumb 2 + + + + + Breadcrumb 3 + Breadcrumb 4 + + + + + Breadcrumb 5 + + + Breadcrumb 6 + + +``` + +### HTML (skeleton) + +```html + +``` + +### HTML (no-trailing-slash) + +```html + + + Breadcrumb 1 + + + Breadcrumb 2 + + + Breadcrumb 3 + + + Breadcrumb 4 + + +``` + +### HTML (aria-current="page") + +```html + + + Breadcrumb 1 + + + Breadcrumb 2 + + + Breadcrumb 3 + + + Breadcrumb 4 + + +``` + +## `` attributes, properties and events + + + +## `` attributes, properties and events + + diff --git a/packages/web-components/src/components/breadcrumb/breadcrumb.scss b/packages/web-components/src/components/breadcrumb/breadcrumb.scss new file mode 100644 index 000000000000..20dc9c731acd --- /dev/null +++ b/packages/web-components/src/components/breadcrumb/breadcrumb.scss @@ -0,0 +1,113 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/motion' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/components/breadcrumb'; +@import '../overflow-menu/overflow-menu'; + +:host(#{$prefix}-breadcrumb), +:host(#{$prefix}-breadcrumb-skeleton) { + @extend .#{$prefix}--breadcrumb; + + .#{$prefix}--breadcrumb { + padding: 0; + margin: 0; + } +} + +:host(#{$prefix}-breadcrumb-item), +:host(#{$prefix}-breadcrumb-item-skeleton) { + @extend .#{$prefix}--breadcrumb-item; + + &::after { + color: $text-primary; + content: '/'; + margin-inline-start: $spacing-03; + } +} + +:host(#{$prefix}-breadcrumb-overflow-menu) { + position: relative; + block-size: rem(18px); + inline-size: rem(20px); + + &:focus { + outline: 1px solid $focus; + } + + &:hover { + background: transparent; + + ::after { + opacity: 1; + } + } + + // Used to mimic link underline + ::after { + position: absolute; + background: $link-primary-hover; + block-size: 1px; + content: ''; + inline-size: $spacing-04; + inset-block-end: $spacing-01; + opacity: 0; + transition: opacity $duration-fast-01 motion(standard, productive); + + @media screen and (prefers-reduced-motion: reduce) { + transition: none; + } + } +} + +:host(#{$prefix}-breadcrumb-overflow-menu[open]) { + background: transparent; + box-shadow: none; +} + +:host(#{$prefix}-breadcrumb-overflow-menu) svg { + position: relative; + fill: $link-primary; + transform: translateY(4px); +} + +:host(#{$prefix}-breadcrumb-overflow-menu):hover svg { + fill: $link-primary-hover; +} + +:host(#{$prefix}-breadcrumb[no-trailing-slash]) + ::slotted(#{$prefix}-breadcrumb-item:last-of-type)::after { + content: ''; +} + +:host(#{$prefix}-breadcrumb-link) { + outline: none; + + // Re-define the ruleset so this wins over `.#{$prefix}--link:visited`, etc. + .#{$prefix}--link--disabled { + color: $text-disabled; + } + + .#{$prefix}--link__icon[hidden] { + display: none; + } +} + +:host(#{$prefix}-breadcrumb-link[aria-current='page']) .#{$prefix}--link { + color: $text-primary; + cursor: auto; + + &:hover { + text-decoration: none; + } +} diff --git a/packages/web-components/src/components/breadcrumb/breadcrumb.stories.ts b/packages/web-components/src/components/breadcrumb/breadcrumb.stories.ts new file mode 100644 index 000000000000..42190f50828f --- /dev/null +++ b/packages/web-components/src/components/breadcrumb/breadcrumb.stories.ts @@ -0,0 +1,127 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './breadcrumb'; +import './breadcrumb-item'; +import './breadcrumb-link'; +import './breadcrumb-overflow-menu'; +import '../overflow-menu/overflow-menu-body'; +import './breadcrumb-skeleton'; + +const args = { + ariaLabel: '', + classes: '', + noTrailingSlash: false, +}; + +const argTypes = { + ariaLabel: { + control: 'text', + description: 'Specify the label for the breadcrumb container.', + name: 'aria-label', + }, + classes: { + control: 'text', + description: + 'Specify an optional className to be applied to the container node.', + }, + noTrailingSlash: { + control: 'boolean', + description: + 'Optional prop to omit the trailing slash for the breadcrumbs.', + }, +}; + +export const Default = { + render: () => { + return html` + + + Breadcrumb 1 + + + Breadcrumb 2 + + + Breadcrumb 3 + + + Breadcrumb 4 + + + `; + }, +}; + +export const BreadcrumbWithOverflowMenu = { + render: () => html` + + + Breadcrumb 1 + + + Breadcrumb 2 + + + + + Breadcrumb 3 + Breadcrumb 4 + + + + + Breadcrumb 5 + + + Breadcrumb 6 + + + `, +}; + +export const Skeleton = { + render: () => { + return html` `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { ariaLabel, classes, noTrailingSlash } = args ?? {}; + return html` + + + Breadcrumb 1 + + + Breadcrumb 2 + + + Breadcrumb 3 + + + Breadcrumb 4 + + + `; + }, +}; + +const meta = { + title: 'Components/Breadcrumb', +}; + +export default meta; diff --git a/packages/web-components/src/components/breadcrumb/breadcrumb.ts b/packages/web-components/src/components/breadcrumb/breadcrumb.ts new file mode 100644 index 000000000000..ccb2c49c1511 --- /dev/null +++ b/packages/web-components/src/components/breadcrumb/breadcrumb.ts @@ -0,0 +1,52 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './breadcrumb.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Breadcrumb. + * + * @element cds-breadcrumb + */ +@customElement(`${prefix}-breadcrumb`) +class CDSBreadcrumb extends LitElement { + /** + * Optional prop to omit the trailing slash for the breadcrumbs + */ + @property({ type: Boolean, reflect: true, attribute: 'no-trailing-slash' }) + noTrailingSlash = false; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'navigation'); + } + super.connectedCallback(); + } + + render() { + const classes = classMap({ + [`${prefix}--breadcrumb`]: true, + [`${prefix}--breadcrumb--no-trailing-slash`]: this.noTrailingSlash, + }); + return html` +
      + +
    + `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSBreadcrumb; diff --git a/packages/web-components/src/components/breadcrumb/docs/overview.mdx b/packages/web-components/src/components/breadcrumb/docs/overview.mdx new file mode 100644 index 000000000000..d427cbce2a31 --- /dev/null +++ b/packages/web-components/src/components/breadcrumb/docs/overview.mdx @@ -0,0 +1,16 @@ +## Live demo + + diff --git a/packages/web-components/src/components/breadcrumb/index.ts b/packages/web-components/src/components/breadcrumb/index.ts new file mode 100644 index 000000000000..14d98fa3855a --- /dev/null +++ b/packages/web-components/src/components/breadcrumb/index.ts @@ -0,0 +1,13 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './breadcrumb'; +import './breadcrumb-item'; +import './breadcrumb-link'; +import './breadcrumb-skeleton'; diff --git a/packages/web-components/src/components/button/button-set-base.ts b/packages/web-components/src/components/button/button-set-base.ts new file mode 100644 index 000000000000..f2a3323f2fed --- /dev/null +++ b/packages/web-components/src/components/button/button-set-base.ts @@ -0,0 +1,34 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import styles from './button.scss?lit'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Button set without button checks + * + * @element cds-button-set-base + */ +@customElement(`${prefix}-button-set-base`) +class CDSButtonSetBase extends LitElement { + render() { + return html``; + } + + connectedCallback() { + super.connectedCallback(); + this.setAttribute('role', 'list'); + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom WebPack loader +} +/* @__GENERATE_REACT_CUSTOM_ELEMENT_TYPE__ */ +export default CDSButtonSetBase; diff --git a/packages/web-components/src/components/button/button-set.ts b/packages/web-components/src/components/button/button-set.ts new file mode 100644 index 000000000000..96b01ccb5cff --- /dev/null +++ b/packages/web-components/src/components/button/button-set.ts @@ -0,0 +1,69 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { BUTTON_KIND } from './defs'; +import styles from './button.scss?lit'; +import { prefix } from '../../globals/settings'; +import CDSButtonSetBase from './button-set-base'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Button set. + * + * @element cds-button-set + */ +@customElement(`${prefix}-button-set`) +class CDSButtonSet extends CDSButtonSetBase { + /** + * Handler for @slotchange, set the first cds-button to kind secondary and primary for the remaining ones + * + * @private + */ + protected _handleSlotChange(event: Event) { + const childItems = (event.target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSButtonSet).selectorItem + ) + : false + ); + + childItems.forEach((elem, index) => { + (elem as HTMLElement).setAttribute( + 'kind', + index === 0 ? BUTTON_KIND.SECONDARY : BUTTON_KIND.PRIMARY + ); + }); + + const update = new CustomEvent(`${prefix}-btn-set-update`, { + bubbles: true, + cancelable: true, + composed: true, + }); + + this.dispatchEvent(update); + } + + render() { + return html` `; + } + /** + * A selector that will return the child items. + */ + static get selectorItem() { + return `${prefix}-button`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSButtonSet; diff --git a/packages/web-components/src/components/button/button-skeleton.ts b/packages/web-components/src/components/button/button-skeleton.ts new file mode 100644 index 000000000000..80f933d8c9dd --- /dev/null +++ b/packages/web-components/src/components/button/button-skeleton.ts @@ -0,0 +1,81 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { html } from 'lit'; +import { prefix } from '../../globals/settings'; +import CDSButton from './button'; +import styles from './button.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Button skeleton. + */ +@customElement(`${prefix}-button-skeleton`) +class CDSButtonSkeleton extends CDSButton { + /** + * Handles `click` event on the `
    . + * + * @param event The event. + */ + private _handleClickLinkSkeleton(event: MouseEvent) { + if (this.disabled) { + event.preventDefault(); // Stop following the link + event.stopPropagation(); // Stop firing `onClick` + } + } + + render() { + const { + autofocus, + disabled, + download, + href, + hreflang, + ping, + rel, + size, + target, + type, + } = this; + const classes = classMap({ + [`${prefix}--btn`]: true, + [`${prefix}--skeleton`]: true, + [`${prefix}--btn--${size}`]: size, + }); + return href + ? html` + + ` + : html` + + `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSButtonSkeleton; diff --git a/packages/web-components/src/components/button/button.mdx b/packages/web-components/src/components/button/button.mdx new file mode 100644 index 000000000000..69122ea2d0b8 --- /dev/null +++ b/packages/web-components/src/components/button/button.mdx @@ -0,0 +1,127 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import Add16 from '@carbon/icons/lib/add/16'; +import * as ButtonStories from './button.stories'; + + + +# Button + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/button) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/button) + +## Overview + +Buttons are clickable elements that are used to trigger actions. They +communicate calls to action to the user and allow users to interact with pages +in a variety of ways. `Button` labels express what action will occur when the +user interacts with it. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/button/index.js'; +``` + +### SCSS (must include with JS import) + +```css +@use '@carbon/styles/scss/components/button'; +``` + +{`${cdnJs({ components: ['button'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + Button +``` + +## Danger Buttons + +The danger button has three different styles: primary, tertiary, and ghost. +Determining which danger button style to use will depend on the level of +emphasis you want to give to the danger action. Destructive actions that are +considered a required or primary step in a workflow should use the primary +danger button style. However, if a destructive action is just one of several +actions a user could choose from, then a lower emphasis style like the tertiary +danger button or the ghost danger button may be more appropriate. + +```html + Button +``` + +## Icon-only Buttons + +Icon buttons allow users to take actions, and make choices, with a single tap. +Icon buttons can take the form of any of the seven types (Primary, Secondary, +Tertiary, Danger, Danger tertiary, Danger ghost and Ghost) but most commonly +will be styled as primary or ghost buttons. + +Our Storybook example also shows off the Tooltip feature, explained later. + +````html +import Add16 from '@carbon/icons/lib/add/16'; + + ${Add16({ slot: 'icon' })} ``` ## Set of Buttons You +can wrap two `Button` elements in a `ButtonSet` when an action required by the +user has more than one option. Always use a negative action button (secondary) +paired with a positive action button (primary) in that order. Negative action +buttons will be on the left. Positive action buttons should be on the right. +When these two types buttons are paired in the correct order, they will +automatically space themselves apart. ```html + + Secondary 1 + Primary 2 + +```` + +## Skeleton + +For the skeleton variation, utilize ``. + +```html + +``` + +## Component API + +### Button `size` + +This attribute specifies which size the `Button` should be rendered at. Valid +values are `sm`, `md`, `lg`, `xl` and `2xl`. If no `size` is specified, it +renders as `lg`. + +### Button `tooltipAlignment` + +The `tooltip-alignment` attribute is used to change where the tooltip text and +caret is rendered in relation to the `Button`. Accepted options are `start`, +`center`, and `end`. The default alignment is `center`. + +### Button `tooltipPosition` + +When using an icon-only button, you may be in a situation where you need to +change where the tooltip is positioned on the screen. `tooltip-position` takes +in a position and will render the tooltip accordingly. Accepted options are +`top`, `bottom`, `left`, and `right`. The default is position is `top`. + +### ButtonSet `stacked` + +By passing in `stacked` to the `cds-button-set` component, you can arrange your +two `Button` elements vertically + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `autofocus` attribute). + + diff --git a/packages/web-components/src/components/button/button.scss b/packages/web-components/src/components/button/button.scss new file mode 100644 index 000000000000..bc8116d0347b --- /dev/null +++ b/packages/web-components/src/components/button/button.scss @@ -0,0 +1,120 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/components/button' as *; +@use '@carbon/styles/scss/components/popover/index'; +@use '@carbon/styles/scss/components/code-snippet/code-snippet' as *; +@use '@carbon/styles/scss/components/tooltip'; +@use '@carbon/styles/scss/components/chat-button' as *; +@use '@carbon/styles/scss/layout' as *; + +@include code-snippet; + +:host(#{$prefix}-button), +:host(#{$prefix}-modal-footer-button) { + @include emit-layout-tokens(); + + display: inline-flex; + + ::slotted([slot='icon']) { + @extend .#{$prefix}--btn__icon; + } + + .#{$prefix}--btn { + flex-grow: 1; + max-inline-size: 100%; + } +} + +:host(#{$prefix}-button-skeleton) { + @include emit-layout-tokens(); +} + +:host(#{$prefix}-button[isExpressive]) ::slotted([slot='icon']), +:host(#{$prefix}-modal-footer-button[isExpressive]) ::slotted([slot='icon']) { + block-size: rem(20px); + inline-size: rem(20px); +} + +:host(#{$prefix}-button[pagination]), +:host(#{$prefix}-modal-footer-button[pagination]) { + .#{$prefix}--btn { + border: none; + border-inline-start: 1px solid $border-subtle; + transition: none; + + &:focus { + border-inline-start: 1px solid transparent; + box-shadow: none; + outline: $spacing-01 solid $focus; + outline-offset: -#{$spacing-01}; + } + } +} + +:host(#{$prefix}-button[pagination]:not([disabled])), +:host(#{$prefix}-modal-footer-button[pagination]:not([disabled])) { + .#{$prefix}--btn { + color: $icon-primary; + + &:active { + background-color: $layer-hover; + } + } +} + +:host(#{$prefix}-button[pagination][batch-action]:not([disabled])), +:host( + #{$prefix}-modal-footer-button[pagination][batch-action]:not([disabled]) + ) { + .#{$prefix}--btn { + padding: $button-padding-ghost; + + &:focus { + outline: $spacing-01 solid $layer; + outline-offset: -#{$spacing-01}; + } + } + + :host(#{$prefix}-button[pagination][has-main-content]:not([disabled])), + :host( + #{$prefix}-modal-footer-button[pagination][has-main-content]:not( + [disabled] + ) + ) { + ::slotted([slot='icon']) { + position: static; + margin-inline-start: $spacing-02; + } + } +} + +:host(#{$prefix}-button[kind='ghost']:hover) .#{$prefix}--btn--ghost, +:host(#{$prefix}-button[kind='ghost']) .#{$prefix}--btn--ghost:active { + outline: none; +} + +:host(#{$prefix}-button-set), +:host(#{$prefix}-side-panel-button-set) { + @extend .#{$prefix}--btn-set; + + ::slotted(#{$prefix}-button) { + inline-size: 100%; + // 196px from design kit + max-inline-size: rem(196px); + } +} + +:host(#{$prefix}-button-set[stacked]) { + @extend .#{$prefix}--btn-set--stacked; +} diff --git a/packages/web-components/src/components/button/button.stories.ts b/packages/web-components/src/components/button/button.stories.ts new file mode 100644 index 000000000000..f909c061140c --- /dev/null +++ b/packages/web-components/src/components/button/button.stories.ts @@ -0,0 +1,433 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +// Below path will be there when an application installs `carbon-web-components` package. +// In our dev env, we auto-generate the file and re-map below path to to point to the generated file. +// @ts-ignore +import Add16 from '@carbon/icons/lib/add/16'; +import { + BUTTON_KIND, + BUTTON_TYPE, + BUTTON_SIZE, + BUTTON_TOOLTIP_ALIGNMENT, + BUTTON_TOOLTIP_POSITION, +} from './button'; +import './index'; + +const kind = { + [`Primary button (${BUTTON_KIND.PRIMARY})`]: BUTTON_KIND.PRIMARY, + [`Secondary button (${BUTTON_KIND.SECONDARY})`]: BUTTON_KIND.SECONDARY, + [`Tertiary button (${BUTTON_KIND.TERTIARY})`]: BUTTON_KIND.TERTIARY, + [`Danger button (${BUTTON_KIND.DANGER})`]: BUTTON_KIND.DANGER, + [`Danger tertiary button (${BUTTON_KIND.DANGER_TERTIARY})`]: + BUTTON_KIND.DANGER_TERTIARY, + [`Danger ghost button (${BUTTON_KIND.DANGER_GHOST})`]: + BUTTON_KIND.DANGER_GHOST, + [`Ghost button (${BUTTON_KIND.GHOST})`]: BUTTON_KIND.GHOST, +}; + +const types = { + [`Button`]: BUTTON_TYPE.BUTTON, + [`Reset`]: BUTTON_TYPE.RESET, + [`Submit`]: BUTTON_TYPE.SUBMIT, +}; + +const alignmentOptions = { + ['Start']: BUTTON_TOOLTIP_ALIGNMENT.START, + ['Center']: BUTTON_TOOLTIP_ALIGNMENT.CENTER, + ['End']: BUTTON_TOOLTIP_ALIGNMENT.END, +}; + +const positionOptions = { + ['Top']: BUTTON_TOOLTIP_POSITION.TOP, + ['Right']: BUTTON_TOOLTIP_POSITION.RIGHT, + ['Bottom']: BUTTON_TOOLTIP_POSITION.BOTTOM, + ['Left']: BUTTON_TOOLTIP_POSITION.LEFT, +}; + +const sizes = { + [`Small size (${BUTTON_SIZE.SMALL})`]: BUTTON_SIZE.SMALL, + [`Medium size (${BUTTON_SIZE.MEDIUM})`]: BUTTON_SIZE.MEDIUM, + [`Large size (${BUTTON_SIZE.LARGE})`]: BUTTON_SIZE.LARGE, + [`XL size (${BUTTON_SIZE.EXTRA_LARGE})`]: BUTTON_SIZE.EXTRA_LARGE, + [`2XL size (${BUTTON_SIZE.EXTRA_EXTRA_LARGE})`]: + BUTTON_SIZE.EXTRA_EXTRA_LARGE, +}; + +const defaultArgs = { + kind: BUTTON_KIND.PRIMARY, + tooltipAlignment: BUTTON_TOOLTIP_ALIGNMENT.CENTER, + tooltipPosition: BUTTON_TOOLTIP_POSITION.TOP, +}; + +const controls = { + buttonClassName: { + control: 'text', + description: 'Specify an optional className to be added to your Button', + }, + dangerDescription: { + control: 'text', + description: + 'Specify the message read by screen readers for the danger button variant', + }, + disabled: { + control: 'boolean', + description: 'Specify whether the Button should be disabled, or not', + }, + href: { + control: 'string', + description: + 'Optionally specify an href for your Button to become an element', + }, + isExpressive: { + control: 'boolean', + description: 'Specify whether the Button is expressive, or not', + }, + isSelected: { + control: 'boolean', + description: + 'Specify whether the Button is currently selected. Only applies to the Ghost variant.', + }, + kind: { + control: 'select', + description: 'Specifiy the kind of Button you want to create', + options: kind, + }, + linkRole: { + control: 'text', + description: 'Optional prop to specify the role of the Button', + }, + size: { + control: 'select', + description: + 'Specify the size of the button, from the following list of sizes:', + options: sizes, + }, + tooltipAlignment: { + control: 'radio', + description: + 'Specify the alignment of the tooltip to the icon-only button. Can be one of: start, center, or end.', + options: alignmentOptions, + }, + tooltipPosition: { + control: 'radio', + description: + 'Specify the direction of the tooltip for icon-only buttons. Can be either top, right, bottom, or left.', + options: positionOptions, + }, + type: { + control: 'radio', + description: 'Optional prop to specify the type of the Button', + options: types, + }, + onClick: { + table: { + disable: true, + }, + }, +}; + +export const Default = { + argTypes: controls, + args: defaultArgs, + render: ({ + buttonClassName, + dangerDescription, + disabled, + href, + isExpressive, + isSelected, + kind, + linkRole, + size, + tooltipAlignment, + tooltipPosition, + type, + }) => + html` + Button + `, +}; + +export const Danger = { + argTypes: controls, + args: defaultArgs, + render: ({ + buttonClassName, + dangerDescription, + disabled, + href, + isExpressive, + isSelected, + linkRole, + size, + tooltipAlignment, + tooltipPosition, + type, + }) => + html` + Button + + + Tertiary Danger Button + + + Ghost Danger Button + `, +}; + +export const Ghost = { + argTypes: controls, + args: defaultArgs, + render: ({ + buttonClassName, + dangerDescription, + disabled, + href, + isExpressive, + isSelected, + linkRole, + size, + tooltipAlignment, + tooltipPosition, + type, + }) => + html` + Button + `, +}; + +export const IconButton = { + argTypes: controls, + args: defaultArgs, + render: ({ + buttonClassName, + dangerDescription, + disabled, + href, + isExpressive, + isSelected, + kind, + linkRole, + size, + tooltipAlignment, + tooltipPosition, + type, + onClick, + }) => + html` + ${Add16({ slot: 'icon' })} + `, +}; + +export const Secondary = { + argTypes: controls, + args: defaultArgs, + render: ({ + buttonClassName, + dangerDescription, + disabled, + href, + isExpressive, + isSelected, + linkRole, + size, + tooltipAlignment, + tooltipPosition, + type, + }) => + html` + Button + `, +}; + +export const SetOfButtons = { + argTypes: controls, + args: defaultArgs, + render: ({ + buttonClassName, + dangerDescription, + disabled, + href, + isExpressive, + isSelected, + linkRole, + size, + tooltipAlignment, + tooltipPosition, + type, + }) => + html` + + Secondary button + + + Primary button `, +}; + +export const Skeleton = { + render: () => + html` + `, +}; + +export const Tertiary = { + argTypes: controls, + args: defaultArgs, + render: ({ + buttonClassName, + dangerDescription, + disabled, + href, + isExpressive, + isSelected, + linkRole, + size, + tooltipAlignment, + tooltipPosition, + type, + }) => + html` + Button + `, +}; + +const meta = { + title: 'Components/Button', + parameters: { + actions: { argTypesRegex: '^on.*' }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/button/button.ts b/packages/web-components/src/components/button/button.ts new file mode 100644 index 000000000000..a680c592b1a2 --- /dev/null +++ b/packages/web-components/src/components/button/button.ts @@ -0,0 +1,386 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import { + BUTTON_KIND, + BUTTON_TYPE, + BUTTON_SIZE, + BUTTON_TOOLTIP_ALIGNMENT, + BUTTON_TOOLTIP_POSITION, +} from './defs'; +import styles from './button.scss?lit'; +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { + BUTTON_KIND, + BUTTON_TYPE, + BUTTON_SIZE, + BUTTON_TOOLTIP_ALIGNMENT, + BUTTON_TOOLTIP_POSITION, +}; + +/** + * Button. + * + * @element cds-button + * @csspart button The button. + */ +@customElement(`${prefix}-button`) +class CDSButton extends HostListenerMixin(FocusMixin(LitElement)) { + /** + * `true` if there is an icon. + */ + private _hasIcon = false; + + /** + * Handles `slotchange` event. + */ + private _handleSlotChange({ target }: Event) { + const { name } = target as HTMLSlotElement; + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .some( + (node) => node.nodeType !== Node.TEXT_NODE || node!.textContent!.trim() + ); + this[name === 'icon' ? '_hasIcon' : 'hasMainContent'] = hasContent; + this.requestUpdate(); + } + + @HostListener('click', { capture: true }) + // @ts-ignore + private _handleDisabledClick(event: Event) { + const { disabled } = this; + if (disabled) { + event.stopPropagation(); + } + } + + @HostListener('mouseover') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleOver = () => { + this.openTooltip = true; + }; + + /** + * Handles `keydown` event on this element. + */ + @HostListener('mouseout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleHoverOut = async () => { + this.openTooltip = false; + }; + + /** + * Handles `keydown` event on this element. + * Space & enter will toggle state, Escape will only close. + */ + @HostListener('focus') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleFocus = async () => { + this.openTooltip = true; + }; + + /** + * Handles `keydown` event on this element. + * Space & enter will toggle state, Escape will only close. + */ + @HostListener('focusout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleFocusout = async () => { + this.openTooltip = false; + }; + + /** + * `true` if the button should have input focus when the page loads. + */ + @property({ type: Boolean, reflect: true }) + autofocus = false; + + /** + * `true` if the button is being used within a data table batch action toolbar + */ + @property({ type: Boolean, reflect: true, attribute: 'batch-action' }) + batchAction = false; + + /** + * Specify an optional className to be added to your Button + */ + @property({ reflect: true, attribute: 'button-class-name' }) + buttonClassName; + + /** + * Specify the message read by screen readers for the danger button variant + */ + @property({ reflect: true, attribute: 'danger-descriptor' }) + dangerDescriptor; + + /** + * `true` if the button should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * The default file name, used if this button is rendered as ``. + */ + @property({ reflect: true }) + download!: string; + + /** + * `true` if there is a non-icon content. + */ + @property({ reflect: true, attribute: 'has-main-content', type: Boolean }) + hasMainContent = false; + + /** + * Link `href`. If present, this button is rendered as ``. + */ + @property({ reflect: true }) + href!: string; + + /** + * The language of what `href` points to, if this button is rendered as ``. + */ + @property({ reflect: true }) + hreflang!: string; + + /** + * `true` if expressive theme enabled. + */ + @property({ type: Boolean, reflect: true }) + isExpressive = false; + + /** + * Specify whether the Button is currently selected. + * Only applies to the Ghost variant. + */ + @property({ type: Boolean, reflect: true }) + isSelected = false; + + /** + * Button kind. + */ + @property({ reflect: true }) + kind = BUTTON_KIND.PRIMARY; + + /** + * The a11y role for ``. + */ + @property({ attribute: 'link-role' }) + linkRole = 'button'; + + /** + * Boolean to determine if tooltip is open. + */ + @property({ type: Boolean }) + openTooltip = false; + + /** + * URLs to ping, if this button is rendered as ``. + */ + @property({ reflect: true }) + ping!: string; + + /** + * The link type, if this button is rendered as ``. + */ + @property({ reflect: true }) + rel!: string; + + /** + * Button size. + */ + @property({ reflect: true }) + size = 'lg'; + + /** + * The link target, if this button is rendered as ``. + */ + @property({ reflect: true }) + target!: string; + + /** + * Specify the alignment of the tooltip to the icon-only button. + * Can be one of: start, center, or end. + */ + @property({ reflect: true, attribute: 'tooltip-alignment' }) + tooltipAlignment = BUTTON_TOOLTIP_ALIGNMENT.CENTER; + + /** + * Specify the direction of the tooltip for icon-only buttons. + * Can be either top, right, bottom, or left. + */ + @property({ reflect: true, attribute: 'tooltip-position' }) + tooltipPosition = BUTTON_TOOLTIP_POSITION.TOP; + + /** + * Specify the direction of the tooltip for icon-only buttons. + * Can be either top, right, bottom, or left. + */ + @property({ reflect: true, attribute: 'tooltip-text' }) + tooltipText!: string; + + /** + * Button type. + */ + @property({ reflect: true }) + type = BUTTON_TYPE.BUTTON; + + render() { + const { + autofocus, + buttonClassName, + dangerDescriptor, + disabled, + download, + href, + hreflang, + kind, + isExpressive, + isSelected, + linkRole, + openTooltip, + ping, + rel, + size, + target, + tooltipAlignment, + tooltipPosition, + tooltipText, + type, + _hasIcon: hasIcon, + hasMainContent, + _handleSlotChange: handleSlotChange, + } = this; + + let defaultClasses = { + [`${prefix}--btn`]: true, + [`${prefix}--btn--${kind}`]: kind, + [`${prefix}--btn--disabled`]: disabled, + [`${prefix}--btn--icon-only`]: hasIcon && !hasMainContent, + [`${prefix}--btn--${size}`]: size, + [`${prefix}--layout--size-${size}`]: size, + [`${prefix}-ce--btn--has-icon`]: hasIcon, + [`${prefix}--btn--expressive`]: isExpressive, + [`${prefix}--btn--selected`]: isSelected && kind === 'ghost', + }; + + if (buttonClassName) { + const outputObject = {}; + buttonClassName?.split(' ').forEach((element) => { + outputObject[element] = true; + }); + defaultClasses = { ...defaultClasses, ...outputObject }; + } + const classes = classMap(defaultClasses); + + const isDanger = kind.includes('danger'); + + if (href) { + return disabled + ? html` +

    + + +

    + ` + : html` +
    + + + + `; + } + + const alignmentClass = + tooltipAlignment && + (tooltipPosition === BUTTON_TOOLTIP_POSITION.TOP || + tooltipPosition === BUTTON_TOOLTIP_POSITION.BOTTOM) + ? `-${tooltipAlignment}` + : ''; + + const tooltipClasses = classMap({ + [`${prefix}--popover-container`]: true, + [`${prefix}--popover--caret`]: true, + [`${prefix}--popover--high-contrast`]: true, + [`${prefix}--tooltip`]: true, + [`${prefix}--icon-tooltip`]: hasIcon, + [`${prefix}--popover--open`]: openTooltip, + [`${prefix}--popover--${tooltipPosition}${alignmentClass}`]: tooltipText, + }); + + return tooltipText && !disabled + ? html` + + + + + ${tooltipText} + + + + + ` + : html` + + `; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSButton; diff --git a/packages/web-components/src/components/button/defs.ts b/packages/web-components/src/components/button/defs.ts new file mode 100644 index 000000000000..e035f19bf335 --- /dev/null +++ b/packages/web-components/src/components/button/defs.ts @@ -0,0 +1,148 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Button kind. + */ +export enum BUTTON_KIND { + /** + * Primary button. + */ + PRIMARY = 'primary', + + /** + * Secondary button. + */ + SECONDARY = 'secondary', + + /** + * Tertiary button. + */ + TERTIARY = 'tertiary', + + /** + * Ghost button. + */ + GHOST = 'ghost', + + /** + * Danger button. + */ + DANGER = 'danger', + + /** + * Danger primary button. + */ + DANGER_PRIMARY = 'danger-primary', + + /** + * Danger tertiary button. + */ + DANGER_TERTIARY = 'danger-tertiary', + + /** + * Danger ghost button, + */ + DANGER_GHOST = 'danger-ghost', +} + +/** + * Button type. + */ +export enum BUTTON_TYPE { + /** + * Default button type. + */ + BUTTON = 'button', + + /** + * Reset button type. + */ + RESET = 'reset', + + /** + * Submit button type. + */ + SUBMIT = 'submit', +} + +/** + * Button size. + */ +export enum BUTTON_SIZE { + /** + * Small size. + */ + SMALL = 'sm', + + /** + * Medium size. + */ + MEDIUM = 'md', + + /** + * Large size. + */ + LARGE = 'lg', + + /** + * X-Large size. + */ + EXTRA_LARGE = 'xl', + + /** + * 2X-Large size. + */ + EXTRA_EXTRA_LARGE = '2xl', +} + +/** + * Button tooltip alignment. + */ +export enum BUTTON_TOOLTIP_ALIGNMENT { + /** + * Aligned to the start. + */ + START = 'left', + + /** + * Aligned to the center. + */ + CENTER = '', + + /** + * Aligned to the end. + */ + END = 'right', +} + +/** + * Button tooltip position. + */ +export enum BUTTON_TOOLTIP_POSITION { + /** + * Positioned on the top. + */ + TOP = 'top', + + /** + * Positioned on the right. + */ + RIGHT = 'right', + + /** + * Positioned on the bottom. + */ + BOTTOM = 'bottom', + + /** + * Positined on the left. + */ + LEFT = 'left', +} diff --git a/packages/web-components/src/components/button/docs/overview.mdx b/packages/web-components/src/components/button/docs/overview.mdx new file mode 100644 index 000000000000..cdba1b636d4a --- /dev/null +++ b/packages/web-components/src/components/button/docs/overview.mdx @@ -0,0 +1,20 @@ +## Live demo + + diff --git a/packages/web-components/src/components/button/index.ts b/packages/web-components/src/components/button/index.ts new file mode 100644 index 000000000000..0b96983d47a3 --- /dev/null +++ b/packages/web-components/src/components/button/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './button'; +import './button-set'; +import './button-skeleton'; diff --git a/packages/web-components/src/components/chat-button/chat-button-skeleton.ts b/packages/web-components/src/components/chat-button/chat-button-skeleton.ts new file mode 100644 index 000000000000..0cbb43b053ab --- /dev/null +++ b/packages/web-components/src/components/chat-button/chat-button-skeleton.ts @@ -0,0 +1,46 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { CHAT_BUTTON_SIZE } from './defs'; +import styles from './chat-button.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { CHAT_BUTTON_SIZE }; +/** + * Chat button skeleton. + * + * @element cds-chat-button-skeleton + */ +@customElement(`${prefix}-chat-button-skeleton`) +class CDSChatButtonSkeleton extends LitElement { + /** + * Specify the size of the `ChatButtonSkeleton`, from the following list of sizes: 'sm', 'md', 'lg' + */ + @property({ reflect: true }) + size = CHAT_BUTTON_SIZE.LARGE; + + render() { + const skeletonClasses = classMap({ + [`${prefix}--skeleton`]: true, + [`${prefix}--btn`]: true, + [`${prefix}--chat-btn`]: true, + [`${prefix}--layout--size-${this.size}`]: this.size, + }); + + return html`
    `; + } + + static styles = styles; +} + +export default CDSChatButtonSkeleton; diff --git a/packages/web-components/src/components/chat-button/chat-button-story.scss b/packages/web-components/src/components/chat-button/chat-button-story.scss new file mode 100644 index 000000000000..8a898b942f54 --- /dev/null +++ b/packages/web-components/src/components/chat-button/chat-button-story.scss @@ -0,0 +1,15 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// +div[class*='test-button-'] { + margin-block-end: 4rem; + + /* stylelint-disable */ + & > * { + margin-inline-end: 2rem; + } + /* stylelint-enable */ +} diff --git a/packages/web-components/src/components/chat-button/chat-button.mdx b/packages/web-components/src/components/chat-button/chat-button.mdx new file mode 100644 index 000000000000..407a6c5cbba0 --- /dev/null +++ b/packages/web-components/src/components/chat-button/chat-button.mdx @@ -0,0 +1,42 @@ +import { ArgTypes, Markdown, Meta } from "@storybook/blocks"; +import { cdnJs, cdnCss } from "../../globals/internal/storybook-cdn"; +import * as ChatButtonStories from "./chat-button.stories"; + + + +# Chat Button + +> 💡 Check our +> [CodeSandbox](https://codesandbox.io/s/github/carbon-design-system/carbon-for-ibm-dotcom/tree/main/packages/carbon-web-components/examples/codesandbox/basic/components/chat-button) +> example implementation. + +[![Edit carbon-web-components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/carbon-design-system/carbon-for-ibm-dotcom/tree/main/packages/carbon-web-components/examples/codesandbox/basic/components/chat-button) + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import "@carbon/web-components/es/components/chat-button/index.js"; +``` + +{`${cdnJs({ components: ["chat-button"] })}`} +{`${cdnCss()}`} + +```javascript +import "@carbon/web-components/es/components/chat-button/index.js"; +import Add16 from "@carbon/icons/lib/add/16"; + +function App() { + return html` + Primary ${Add16({ slot: "icon" })} + `; +} +``` + +## `` attributes and properties + + +```` diff --git a/packages/web-components/src/components/chat-button/chat-button.scss b/packages/web-components/src/components/chat-button/chat-button.scss new file mode 100644 index 000000000000..88fc44d68cf9 --- /dev/null +++ b/packages/web-components/src/components/chat-button/chat-button.scss @@ -0,0 +1,16 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/layout' as *; +@use '../button/button'; + +:host(#{$prefix}-chat-button-skeleton) { + @include emit-layout-tokens(); +} diff --git a/packages/web-components/src/components/chat-button/chat-button.stories.ts b/packages/web-components/src/components/chat-button/chat-button.stories.ts new file mode 100644 index 000000000000..3953a1d96c24 --- /dev/null +++ b/packages/web-components/src/components/chat-button/chat-button.stories.ts @@ -0,0 +1,106 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './index'; +import Add16 from '@carbon/icons/lib/add/16'; +import styles from './chat-button-story.scss?lit'; + +export const Default = () => { + return html` + +
    +
    +

    Sizes

    +
    + + Primary ${Add16({ slot: 'icon' })} + + + Primary ${Add16({ slot: 'icon' })} + + + Primary ${Add16({ slot: 'icon' })} + +
    +
    + Primary + Primary + Primary +
    +
    +

    Kinds

    +
    + + Primary ${Add16({ slot: 'icon' })} + + + Secondary ${Add16({ slot: 'icon' })} + + + Tertiary ${Add16({ slot: 'icon' })} + + + Ghost ${Add16({ slot: 'icon' })} + + + Danger ${Add16({ slot: 'icon' })} + +
    +
    + Primary + Secondary + Tertiary + Ghost + Danger +
    +
    +

    Quick action

    +
    + + Quick action ${Add16({ slot: 'icon' })} + + + Selected and Enabled ${Add16({ slot: 'icon' })} + + + Selected and disabled ${Add16({ slot: 'icon' })} + + + Disabled ${Add16({ slot: 'icon' })} + +
    +
    + Quick action + + Selected and Enabled + + + Selected and disabled + + Disabled +
    +
    +

    Skeleton

    +
    + + + +
    +
    + `; +}; + +const meta = { + title: 'Experimental/Chat button', +}; + +export default meta; diff --git a/packages/web-components/src/components/chat-button/chat-button.ts b/packages/web-components/src/components/chat-button/chat-button.ts new file mode 100644 index 000000000000..4b961381d611 --- /dev/null +++ b/packages/web-components/src/components/chat-button/chat-button.ts @@ -0,0 +1,115 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html, LitElement } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import '../button/button'; +import { CHAT_BUTTON_SIZE, CHAT_BUTTON_KIND } from './defs'; +import styles from './chat-button.scss?lit'; + +export { CHAT_BUTTON_SIZE, CHAT_BUTTON_KIND }; + +/** + * Icon Button + * + */ +@customElement(`${prefix}-chat-button`) +class CDSChatButton extends LitElement { + /** + * `true` if there is an icon. + */ + private _hasIcon = false; + + /** + * Handles `slotchange` event. + */ + private _handleSlotChange({ target }: Event) { + this._hasIcon = (target as HTMLSlotElement) + .assignedNodes() + .some( + (node) => node.nodeType !== Node.TEXT_NODE || node!.textContent!.trim() + ); + this.requestUpdate(); + } + + /** + * `true` if the button should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * Specify whether the `ChatButton` should be disabled + */ + @property({ reflect: true }) + kind = CHAT_BUTTON_KIND.PRIMARY; + + /** + * Chat button size. + */ + @property({ reflect: true }) + size = CHAT_BUTTON_SIZE.LARGE; + + /** + * Specify whether the `ChatButton` should be rendered as a quick action button + */ + @property({ attribute: 'is-quick-action', type: Boolean }) + isQuickAction = false; + + /** + * Specify whether the quick action `ChatButton` should be rendered as selected. This disables the input + */ + @property({ attribute: 'is-selected', type: Boolean }) + isSelected = false; + + render() { + const allowedSizes = [ + CHAT_BUTTON_SIZE.SMALL, + CHAT_BUTTON_SIZE.MEDIUM, + CHAT_BUTTON_SIZE.LARGE, + ]; + + if (this.isQuickAction) { + this.kind = CHAT_BUTTON_KIND.GHOST; + this.size = CHAT_BUTTON_SIZE.SMALL; + } else { + // Do not allow size larger than `lg` + this.size = allowedSizes.includes(this.size) + ? this.size + : CHAT_BUTTON_SIZE.LARGE; + } + + let classes = `${prefix}--chat-btn`; + classes += this._hasIcon ? ` ${prefix}--chat-btn--with-icon` : ''; + classes += this.isQuickAction ? ` ${prefix}--chat-btn--quick-action` : ''; + classes += this.isSelected + ? ` ${prefix}--chat-btn--quick-action--selected` + : ''; + + return html` + + + + `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom WebPack loader +} + +export default CDSChatButton; diff --git a/packages/web-components/src/components/chat-button/defs.ts b/packages/web-components/src/components/chat-button/defs.ts new file mode 100644 index 000000000000..16df24bcf47a --- /dev/null +++ b/packages/web-components/src/components/chat-button/defs.ts @@ -0,0 +1,58 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Chat Button size. + */ +export enum CHAT_BUTTON_SIZE { + /** + * Small size. + */ + SMALL = 'sm', + + /** + * Medium size. + */ + MEDIUM = 'md', + + /** + * Large size. + */ + LARGE = 'lg', +} + +/** + * Chat button kind. + */ +export enum CHAT_BUTTON_KIND { + /** + * Primary button. + */ + PRIMARY = 'primary', + + /** + * Secondary button. + */ + SECONDARY = 'secondary', + + /** + * Tertiary button. + */ + TERTIARY = 'tertiary', + + /** + * Ghost button. + */ + GHOST = 'ghost', + + /** + * Danger button. + */ + DANGER = 'danger', +} diff --git a/packages/web-components/src/components/chat-button/index.ts b/packages/web-components/src/components/chat-button/index.ts new file mode 100644 index 000000000000..006d1c3a4b0b --- /dev/null +++ b/packages/web-components/src/components/chat-button/index.ts @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './chat-button'; +import './chat-button-skeleton'; diff --git a/packages/web-components/src/components/checkbox/checkbox-group.ts b/packages/web-components/src/components/checkbox/checkbox-group.ts new file mode 100644 index 000000000000..20ea32c7a967 --- /dev/null +++ b/packages/web-components/src/components/checkbox/checkbox-group.ts @@ -0,0 +1,235 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import WarningFilled16 from '@carbon/icons/lib/warning--filled/16'; +import WarningAltFilled16 from '@carbon/icons/lib/warning--alt--filled/16'; +import CDSCheckbox from './checkbox'; +import styles from './checkbox.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Check box. + * + * @element cds-checkbox + * @fires cds-checkbox-changed - The custom event fired after this changebox changes its checked state. + * @csspart input The checkbox. + * @csspart label The label. + */ +@customElement(`${prefix}-checkbox-group`) +class CDSCheckboxGroup extends LitElement { + /** + * fieldset `aria-labelledby` + */ + @property({ type: String, reflect: true, attribute: 'aria-labelledby' }) + ariaLabelledBy; + + /** + * Specify whether the form group is currently disabled + */ + @property({ type: Boolean }) + disabled; + + /** + * Provide text for the form group for additional help + */ + @property({ type: String, reflect: true, attribute: 'helper-text' }) + helperText; + + /** + * Specify whether the form group is currently invalid + */ + @property({ type: Boolean, attribute: 'invalid' }) + invalid; + + /** + * Provide the text that is displayed when the form group is in an invalid state + */ + @property({ type: String, reflect: true, attribute: 'invalid-text' }) + invalidText; + + /** + * Provide id for the fieldset which corresponds to the fieldset + * `aria-labelledby` + */ + @property({ type: String, reflect: true, attribute: 'legend-id' }) + legendId; + + /** + * Provide the text to be rendered inside of the fieldset + */ + @property({ type: String, reflect: true, attribute: 'legend-text' }) + legendText; + + /** + * Whether the CheckboxGroup should be read-only + */ + @property({ type: Boolean, reflect: true }) + readonly = false; + + /** + * Specify whether the form group is currently in warning state + */ + @property({ type: Boolean, reflect: true }) + warn = false; + + /** + * Provide the text that is displayed when the form group is in warning state + */ + @property({ type: String, reflect: true, attribute: 'warn-text' }) + warnText = ''; + + /* + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSCheckboxGroup).slugItem + ) + : false + ); + + this._hasSlug = Boolean(hasContent); + (hasContent[0] as HTMLElement).setAttribute('size', 'mini'); + this.requestUpdate(); + } + + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + updated(changedProperties) { + const { selectorCheckbox } = this.constructor as typeof CDSCheckboxGroup; + const checkboxes = this.querySelectorAll(selectorCheckbox); + ['disabled', 'readonly'].forEach((name) => { + if (changedProperties.has(name)) { + const { [name as keyof CDSCheckboxGroup]: value } = this; + // Propagate the property to descendants until `:host-context()` gets supported in all major browsers + checkboxes.forEach((elem) => { + (elem as CDSCheckbox)[name] = value; + }); + } + }); + if (changedProperties.has('invalid')) { + const { invalid } = this; + checkboxes.forEach((elem) => { + if (invalid) { + (elem as CDSCheckbox).setAttribute('invalid-group', ''); + } else { + (elem as CDSCheckbox).removeAttribute('invalid-group'); + } + }); + } + } + + render() { + const { + ariaLabelledBy, + disabled, + helperText, + invalid, + invalidText, + legendId, + legendText, + readonly, + warn, + warnText, + _hasSlug: hasSlug, + _handleSlotChange: handleSlotChange, + } = this; + + const showWarning = !readonly && !invalid && warn; + const showHelper = !invalid && !warn; + + const checkboxGroupInstanceId = Math.random().toString(16).slice(2); + + const helperId = !helperText + ? undefined + : `checkbox-group-helper-text-${checkboxGroupInstanceId}`; + + const helper = helperText + ? html`
    + ${helperText} +
    ` + : null; + + const fieldsetClasses = classMap({ + [`${prefix}--checkbox-group`]: true, + [`${prefix}--checkbox-group--readonly`]: readonly, + [`${prefix}--checkbox-group--invalid`]: !readonly && invalid, + [`${prefix}--checkbox-group--warning`]: showWarning, + [`${prefix}--checkbox-group--slug`]: hasSlug, + }); + + return html` +
    + + ${legendText} + + + +
    + ${!readonly && invalid + ? html` + ${WarningFilled16({ + class: `${prefix}--checkbox__invalid-icon`, + })} +
    ${invalidText}
    + ` + : null} + ${showWarning + ? html` + ${WarningAltFilled16({ + class: `${prefix}--checkbox__invalid-icon ${prefix}--checkbox__invalid-icon--warning`, + })} +
    ${warnText}
    + ` + : null} +
    + ${showHelper ? helper : null} +
    + `; + } + + /** + * A selector that will return the checkboxes. + */ + static get selectorCheckbox() { + return `${prefix}-checkbox`; + } + + /** + * A selector that will return the slug item. + */ + static get slugItem() { + return `${prefix}-slug`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSCheckboxGroup; diff --git a/packages/web-components/src/components/checkbox/checkbox-skeleton.ts b/packages/web-components/src/components/checkbox/checkbox-skeleton.ts new file mode 100644 index 000000000000..580a56d66663 --- /dev/null +++ b/packages/web-components/src/components/checkbox/checkbox-skeleton.ts @@ -0,0 +1,33 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './checkbox.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Skeleton of number input. + */ +@customElement(`${prefix}-checkbox-skeleton`) +class CDSCheckboxSkeleton extends LitElement { + render() { + return html` + + `; + } + + static styles = styles; +} + +export default CDSCheckboxSkeleton; diff --git a/packages/web-components/src/components/checkbox/checkbox.mdx b/packages/web-components/src/components/checkbox/checkbox.mdx new file mode 100644 index 000000000000..d12a3458b615 --- /dev/null +++ b/packages/web-components/src/components/checkbox/checkbox.mdx @@ -0,0 +1,55 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as CheckboxStories from './checkbox.stories'; + + + +# Check box + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/checkbox) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/checkbox) + +Check box in `carbon-web-components` represents a combination of a check box and +its label. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/checkbox/index.js'; +``` + +{`${cdnJs({ components: ['checkbox'] })}`} +{`${cdnCss()}`} + +### HTML + +```html +Lorem Ipsum +``` + +Use `cds-checkbox-group` when handling multiple checkboxes + +```html + + Lorem Ipsum 0 + Lorem Ipsum 1 + +``` + +## `` attributes, properties and events + +Unlike regular checkbox, `` does _not_ fire `change` event. Please +use `cds-checkbox-changed` event instead. + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `checked` attribute). + + diff --git a/packages/web-components/src/components/checkbox/checkbox.scss b/packages/web-components/src/components/checkbox/checkbox.scss new file mode 100644 index 000000000000..fbcc0ba5d78a --- /dev/null +++ b/packages/web-components/src/components/checkbox/checkbox.scss @@ -0,0 +1,90 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities'; +@use '@carbon/styles/scss/components/form'; +@use '@carbon/styles/scss/components/checkbox'; + +:host(#{$prefix}-checkbox) { + @extend .#{$prefix}--form-item; + @extend .#{$prefix}--checkbox-wrapper; +} + +// RTL overrides +:host(#{$prefix}-checkbox:dir(rtl)) { + .#{$prefix}--checkbox:checked + .#{$prefix}--checkbox-label::after, + .#{$prefix}--checkbox-label[data-contained-checkbox-state='true']::after { + margin-block-start: 0; + margin-inline-start: to-rem(-1px); + transform: scale(1.2) rotate3d(0.5, 1, 0, 158deg); + transform-origin: center; + } +} + +:host(#{$prefix}-checkbox[readonly]) { + @extend .#{$prefix}--checkbox-wrapper--readonly; +} + +:host(#{$prefix}-checkbox:not([readonly])[invalid]) { + @extend .#{$prefix}--checkbox-wrapper--invalid; +} + +:host(#{$prefix}-checkbox[invalid-group]) .#{$prefix}--checkbox-label::before { + border-color: $support-error; +} + +:host(#{$prefix}-checkbox:not([readonly]):not([invalid])[warn]) { + @extend .#{$prefix}--checkbox-wrapper--warning; +} + +:host(#{$prefix}-checkbox[data-table]) { + margin: 0; +} + +:host(#{$prefix}-checkbox[data-table][hide-checkbox]) { + pointer-events: none; + + .#{$prefix}--checkbox-label::before, + .#{$prefix}--checkbox-label::after { + border-color: transparent; + background-color: transparent; + } +} + +:host(#{$prefix}-checkbox-skeleton) { + .#{$prefix}--checkbox-label { + cursor: default; + } +} + +:host(#{$prefix}-checkbox-group) { + display: flex; +} + +:host(#{$prefix}-checkbox-group) .#{$prefix}--checkbox-group--slug, +:host(#{$prefix}-checkbox[slug]) { + ::slotted(#{$prefix}-slug) { + margin-inline-start: $spacing-03; + } +} + +:host(#{$prefix}-checkbox[slug]) { + flex-direction: row; + + .#{$prefix}--checkbox-label-text { + display: flex; + } +} + +:host(#{$prefix}-checkbox[slug]) ::slotted(#{$prefix}-slug) { + align-self: center; +} diff --git a/packages/web-components/src/components/checkbox/checkbox.stories.ts b/packages/web-components/src/components/checkbox/checkbox.stories.ts new file mode 100644 index 000000000000..dbba153574de --- /dev/null +++ b/packages/web-components/src/components/checkbox/checkbox.stories.ts @@ -0,0 +1,144 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../globals/settings'; +import './index'; + +const checkboxLabel = 'Checkbox label'; + +const defaultArgs = { + disabled: false, + helperText: 'Helper text goes here', + invalid: false, + invalidText: 'Invalid message goes here', + legendText: 'Group label', + readonly: false, + warn: false, + warnText: 'Warn message goes here', +}; + +const controls = { + disabled: { + control: 'boolean', + description: 'Specify whether the checkbox should be disabled.', + }, + helperText: { + control: 'textNullable', + description: 'Provide text for the form group for additional help.', + }, + invalid: { + control: 'boolean', + description: 'Specify whether the form group is currently invalid.', + }, + invalidText: { + control: 'textNullable', + description: + 'Provide the text that is displayed when the form group is in an invalid state.', + }, + legendText: { + control: 'textNullable', + description: 'Provide the text to be rendered inside of the fieldset.', + }, + readonly: { + control: 'boolean', + description: 'Specify whether the checkbox group is read-only.', + }, + warn: { + control: 'boolean', + description: + 'Specify whether the form group is currently in warning state.', + }, + warnText: { + control: 'textNullable', + description: + 'Provide the text that is displayed when the form group is in warning state.', + }, +}; + +export const Default = { + render: () => html` + + ${checkboxLabel} + ${checkboxLabel} + + `, +}; + +export const Skeleton = { + render: () => html` +
    + ${checkboxLabel} +
    + `, +}; + +export const Single = { + render: () => html` + ${checkboxLabel} +

    + ${checkboxLabel} +

    + ${checkboxLabel} +

    + ${checkboxLabel} + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ + disabled, + readonly, + onChange, + helperText, + invalid, + invalidText, + legendText, + warn, + warnText, + }) => + html` + + Checkbox label + Checkbox label + Checkbox label + + `, +}; + +const meta = { + title: 'Components/Checkbox', + parameters: { + actions: { argTypesRegex: '^on.*' }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/checkbox/checkbox.ts b/packages/web-components/src/components/checkbox/checkbox.ts new file mode 100644 index 000000000000..55022c635388 --- /dev/null +++ b/packages/web-components/src/components/checkbox/checkbox.ts @@ -0,0 +1,305 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import FormMixin from '../../globals/mixins/form'; +import WarningFilled16 from '@carbon/icons/lib/warning--filled/16'; +import WarningAltFilled16 from '@carbon/icons/lib/warning--alt--filled/16'; +import styles from './checkbox.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Check box. + * + * @element cds-checkbox + * @fires cds-checkbox-changed - The custom event fired after this changebox changes its checked state. + * @csspart input The checkbox. + * @csspart label The label. + */ +@customElement(`${prefix}-checkbox`) +class CDSCheckbox extends FocusMixin(FormMixin(LitElement)) { + @query('input') + protected _checkboxNode!: HTMLInputElement; + + /** + * Handles `click` event on the `` in the shadow DOM. + */ + protected _handleChange() { + const { checked, indeterminate } = this._checkboxNode; + this.checked = checked; + this.indeterminate = indeterminate; + const { eventChange } = this.constructor as typeof CDSCheckbox; + this.dispatchEvent( + new CustomEvent(eventChange, { + bubbles: true, + composed: true, + detail: { + checked, + indeterminate, + }, + }) + ); + } + + /** + * Prevent checkbox state from updating when readonly + */ + private _handleClick(event: MouseEvent) { + if (this.readonly) { + event.preventDefault(); + } + } + + _handleFormdata(event: Event) { + const { formData } = event as any; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const { checked, disabled, name, value = 'on' } = this; + if (!disabled && checked) { + formData.append(name, value); + } + } + + /** + * Specify whether the underlying input should be checked + */ + @property({ type: Boolean, reflect: true, attribute: 'checked' }) + checked = false; + + /** + * Specify if checkbox is being used in a data table + */ + @property({ type: Boolean, reflect: true, attribute: 'data-table' }) + dataTable = false; + + /** + * Specify whether the Checkbox should be disabled + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * Provide text for the form group for additional help + */ + @property({ type: String, reflect: true, attribute: 'helper-text' }) + helperText; + + /** + * Specify whether the checkbox should be present in the DOM, + * but invisible and uninteractable. Used for data-table purposes. + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-checkbox' }) + hideCheckbox = false; + + /** + * Specify whether the label should be hidden, or not + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-label' }) + hideLabel = false; + + /** + * Specify whether the Checkbox is in an indeterminate state + */ + @property({ type: Boolean, reflect: true }) + indeterminate = false; + + /** + * Provide a label to provide a description of the Checkbox input that you are + * exposing to the user + */ + @property({ attribute: 'label-text' }) + labelText = ''; + + /** + * The form name. + */ + @property() + name!: string; + + /** + * Specify whether the Checkbox is read-only + */ + @property({ type: Boolean, reflect: true }) + readonly = false; + + /** + * Specify whether the Checkbox is currently invalid + */ + @property({ type: Boolean }) + invalid = false; + + /** + * Provide the text that is displayed when the Checkbox is in an invalid state + */ + @property({ type: String, attribute: 'invalid-text' }) + invalidText; + + /** + * Specify a title for the node for the Checkbox + */ + @property({ attribute: 'title' }) + title = ''; + + /** + * The value. + */ + @property() + value!: string; + + /** + * Specify whether the Checkbox is in a warn state + */ + @property({ type: Boolean }) + warn = false; + + /** + * Provide the text that is displayed when the Checkbox is in a warn state + */ + @property({ type: String, attribute: 'warn-text' }) + warnText = false; + + /** + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSCheckbox).slugItem + ) + : false + ); + + this._hasSlug = Boolean(hasContent); + const type = (hasContent[0] as HTMLElement).getAttribute('kind'); + (hasContent[0] as HTMLElement).setAttribute( + 'size', + type === 'inline' ? 'md' : 'mini' + ); + this.requestUpdate(); + } + + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + updated() { + const { _hasSlug: hasSlug } = this; + hasSlug ? this.setAttribute('slug', '') : this.removeAttribute('slug'); + } + + render() { + const { + checked, + disabled, + helperText, + hideLabel, + indeterminate, + invalid, + invalidText, + labelText, + name, + readonly, + title, + value, + warn, + warnText, + _handleChange: handleChange, + _handleClick: handleClick, + } = this; + + const showWarning = !readonly && !invalid && warn; + const showHelper = !invalid && !warn; + + const helper = helperText + ? html`
    ${helperText}
    ` + : null; + + const labelClasses = classMap({ + [`${prefix}--checkbox-label`]: true, + }); + const labelTextClasses = classMap({ + [`${prefix}--checkbox-label-text`]: true, + [`${prefix}--visually-hidden`]: hideLabel, + }); + return html` + + + +
    + ${!readonly && invalid + ? html` + ${WarningFilled16({ + class: `${prefix}--checkbox__invalid-icon`, + })} +
    ${invalidText}
    + ` + : null} + ${showWarning + ? html` + ${WarningAltFilled16({ + class: `${prefix}--checkbox__invalid-icon ${prefix}--checkbox__invalid-icon--warning`, + })} +
    ${warnText}
    + ` + : null} +
    + ${showHelper ? helper : null} + `; + } + + /** + * The name of the custom event fired after this changebox changes its checked state. + */ + static get eventChange() { + return `${prefix}-checkbox-changed`; + } + + /** + * A selector that will return the slug item. + */ + static get slugItem() { + return `${prefix}-slug`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSCheckbox; diff --git a/packages/web-components/src/components/checkbox/docs/overview.mdx b/packages/web-components/src/components/checkbox/docs/overview.mdx new file mode 100644 index 000000000000..1a47bc2de0f2 --- /dev/null +++ b/packages/web-components/src/components/checkbox/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/checkbox/index.ts b/packages/web-components/src/components/checkbox/index.ts new file mode 100644 index 000000000000..281b674ea3f4 --- /dev/null +++ b/packages/web-components/src/components/checkbox/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './checkbox'; +import './checkbox-group'; +import './checkbox-skeleton'; diff --git a/packages/web-components/src/components/code-snippet/code-snippet-skeleton.ts b/packages/web-components/src/components/code-snippet/code-snippet-skeleton.ts new file mode 100644 index 000000000000..56bbac6cd918 --- /dev/null +++ b/packages/web-components/src/components/code-snippet/code-snippet-skeleton.ts @@ -0,0 +1,41 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { CODE_SNIPPET_TYPE } from './code-snippet'; +import styles from './code-snippet.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Skeleton of code snippet. + */ +@customElement(`${prefix}-code-snippet-skeleton`) +class CDSCodeSnippetSkeleton extends LitElement { + /** + * The type of code snippet. Corresponds to the attribute with the same name. + */ + @property({ reflect: true }) + type = CODE_SNIPPET_TYPE.SINGLE; + + render() { + return html` +
    + ${this.type !== CODE_SNIPPET_TYPE.MULTI + ? html` ` + : html` `} +
    + `; + } + + static styles = styles; +} + +export default CDSCodeSnippetSkeleton; diff --git a/packages/web-components/src/components/code-snippet/code-snippet.mdx b/packages/web-components/src/components/code-snippet/code-snippet.mdx new file mode 100644 index 000000000000..f1358cba11a4 --- /dev/null +++ b/packages/web-components/src/components/code-snippet/code-snippet.mdx @@ -0,0 +1,86 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as CodeSnippetStories from './code-snippet.stories'; + + + +# Code snippet + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/code-snippet) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/code-snippet) + +Code snippets are small blocks of reusable code that can be inserted in a code +file. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/code-snippet/index.js'; +``` + +{`${cdnJs({ components: ['code-snippet'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + node -v Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, + veritatis voluptate id incidunt molestiae officia possimus, quasi itaque + alias, architecto hic, dicta fugit? Debitis delectus quidem explicabo vitae + laboriosam! + +``` + +## Single line + +The Terminal style is for single-line. + +```html + + node -v Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, + veritatis voluptate id incidunt molestiae officia possimus, quasi itaque + alias, architecto hic, dicta fugit? Debitis delectus quidem explicabo vitae + laboriosam! + +``` + +## Multi line + +The Code style is for larger, multi-line code snippets. + +```html + + node -v Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, + veritatis voluptate id incidunt molestiae officia possimus, quasi itaque + alias, architecto hic, dicta fugit? Debitis delectus quidem explicabo vitae + laboriosam! + +``` + +## Inline + +The Inline style is for code used within a block of text. + +```html + node -v +``` + +## Skeleton + +For the skeleton variation, utilize ``. + +```html + +``` + +## `` attributes and properties + + diff --git a/packages/web-components/src/components/code-snippet/code-snippet.scss b/packages/web-components/src/components/code-snippet/code-snippet.scss new file mode 100644 index 000000000000..ee2981c71f0d --- /dev/null +++ b/packages/web-components/src/components/code-snippet/code-snippet.scss @@ -0,0 +1,168 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/type' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/motion' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/components/code-snippet/index'; +@use '@carbon/styles/scss/components/copy-button/copy-button'; + +:host(#{$prefix}-code-snippet), +:host(#{$prefix}-code-snippet-skeleton) { + @extend .#{$prefix}--snippet; + + .#{$prefix}--snippet-container { + @extend .#{$prefix}--snippet-container; + } +} + +:host(#{$prefix}-code-snippet[disabled]) { + @extend .#{$prefix}--snippet--disabled; +} + +:host(#{$prefix}-code-snippet[wrap-text]) { + pre { + white-space: pre-wrap; + word-wrap: break-word; + } +} + +:host(#{$prefix}-code-snippet[hide-copy-button]) { + @extend .#{$prefix}--snippet--no-copy; +} + +:host(#{$prefix}-code-snippet-skeleton[type='single']), +:host(#{$prefix}-code-snippet[type='single']) { + @extend .#{$prefix}--snippet--single; +} + +:host(#{$prefix}-code-snippet[type='single']) { + pre { + white-space: nowrap; + } + + #{$prefix}-copy-button { + @include font-family('sans'); + + position: absolute; + inset-block-start: 0; + inset-inline-end: 0; + + /* stylelint-disable-next-line */ + code: { + overflow: hidden; + } + } +} + +#{$prefix}-copy { + code { + padding: 0 $spacing-03; + @include type-style('code-01'); + } +} + +:host(#{$prefix}-code-snippet-skeleton[type='multi']), +:host(#{$prefix}-code-snippet[type='multi']) { + @extend .#{$prefix}--snippet--multi; +} + +:host(#{$prefix}-code-snippet[type='multi']) { + .#{$prefix}--snippet-container { + padding: 0; + + @extend .#{$prefix}--snippet--multi, .#{$prefix}--snippet-container; + } + + pre { + padding: 0 $spacing-08 $spacing-06 0; + margin: 0; + overflow-x: auto; + } + + pre::after { + position: absolute; + background-image: linear-gradient(to right, transparent, $layer); + block-size: 100%; + content: ''; + inline-size: $spacing-05; + inset-block-start: 0; + inset-inline-end: 0; + } + + #{$prefix}-button { + .#{$prefix}--snippet__icon { + margin-inline-start: $spacing-03; + } + + &[disabled] { + .#{$prefix}--snippet-btn--text { + color: $text-disabled; + } + } + } + + #{$prefix}-copy-button { + position: absolute; + z-index: 10; + inset-block-start: $spacing-03; + inset-inline-end: $spacing-03; + } +} + +:host(#{$prefix}-code-snippet[type='multi'][expanded-code]) { + .#{$prefix}--snippet-container { + padding-block-end: $spacing-05; + transition: max-height $duration-moderate-01 motion(standard, productive); + } + + #{$prefix}-button { + .#{$prefix}--snippet__icon { + transform: rotate(180deg); + transition: transform $transition-expansion; + } + } +} + +:host(#{$prefix}-code-snippet-skeleton[type='single']) { + @extend .#{$prefix}--snippet--single, .#{$prefix}--skeleton; +} + +:host(#{$prefix}-code-snippet-skeleton[type='multi']) { + @extend .#{$prefix}--snippet--multi, .#{$prefix}--skeleton; +} + +:host(#{$prefix}-code-snippet-skeleton) { + @extend .#{$prefix}--skeleton; + + span { + @include skeleton; + + display: block; + block-size: $spacing-05; + + inline-size: 100%; + margin-block-start: $spacing-03; + + &:first-child { + margin: 0; + } + + &:nth-child(2) { + inline-size: 85%; + } + + &:nth-child(3) { + inline-size: 95%; + } + } +} diff --git a/packages/web-components/src/components/code-snippet/code-snippet.stories.ts b/packages/web-components/src/components/code-snippet/code-snippet.stories.ts new file mode 100644 index 000000000000..a80c69cb04e7 --- /dev/null +++ b/packages/web-components/src/components/code-snippet/code-snippet.stories.ts @@ -0,0 +1,285 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './index'; +import '../layer/index'; +import '../../../.storybook/templates/with-layer'; + +const args = { + copyButtonDescription: 'Copy to clipboard', + copyText: '', + disabled: false, + feedback: '', + feedbackTimeout: 0, + hideCopyButton: false, + maxCollapsedNumberOfRows: 15, + maxExpandeddNumberOfRows: 0, + minCollapsedNumberOfRows: 3, + minExpandeddNumberOfRows: 16, + showLessText: 'Show less', + showMoreText: 'Show more', + wrapText: false, +}; + +const argTypes = { + copyButtonDescription: { + control: 'text', + description: 'Specify the description for the Copy Button.', + }, + copyText: { + control: 'text', + description: + "Optional text to copy. If not specified, the children node's innerText will be used as the copy value.", + }, + disabled: { + control: 'boolean', + description: 'Specify whether or not the CodeSnippet should be disabled.', + }, + feedback: { + control: 'text', + description: 'Specify the string displayed when the snippet is copied.', + }, + feedbackTimeout: { + control: 'number', + description: + 'Specify the time it takes for the feedback message to timeout.', + }, + hideCopyButton: { + control: 'boolean', + description: + 'Specify whether or not a copy button should be used/rendered.', + }, + maxCollapsedNumberOfRows: { + control: 'number', + description: + 'Specify the maximum number of rows to be shown when in collapsed view.', + }, + maxExpandeddNumberOfRows: { + control: 'number', + description: + 'Specify the maximum number of rows to be shown when in expanded view.', + }, + minCollapsedNumberOfRows: { + control: 'number', + description: + 'Specify the minimum number of rows to be shown when in collapsed view.', + }, + minExpandeddNumberOfRows: { + control: 'number', + description: + 'Specify the minimum number of rows to be shown when in expanded view.', + }, + showLessText: { + control: 'text', + description: + 'Specify a string that is displayed when the Code Snippet has been interacted with to show more lines.', + }, + showMoreText: { + control: 'text', + description: + 'Specify a string that is displayed when the Code Snippet text is more than 15 lines.', + }, + wrapText: { + control: 'boolean', + description: 'Specify whether or not to wrap the text.', + }, +}; + +export const Inline = { + render: () => { + return html` + node -v + + `; + }, +}; + +export const InlineWithLayer = { + render: () => { + return html` + + node -v + + + `; + }, +}; + +export const Multiline = { + render: () => { + const children = `"scripts": { + "build": "lerna run build --stream --prefix --npm-client yarn", + "ci-check": "carbon-cli ci-check", + "clean": "lerna run clean && lerna clean --yes && rimraf node_modules", + "doctoc": "doctoc --title '## Table of Contents'", + "format": "prettier --write '**/*.{js,md,scss,ts}' '!**/{build,es,lib,storybook,ts,umd}/**'", + "format:diff": "prettier --list-different '**/*.{js,md,scss,ts}' '!**/{build,es,lib,storybook,ts,umd}/**' '!packages/components/**'", + "lint": "eslint actions config codemods packages", + "lint:styles": "stylelint '**/*.{css,scss}' --report-needless-disables --report-invalid-scope-disables", + "sync": "carbon-cli sync", + "test": "cross-env BABEL_ENV=test jest", + "test:e2e": "cross-env BABEL_ENV=test jest --testPathPattern=e2e --testPathIgnorePatterns='examples,/packages/components/,/packages/react/'" + }, + "resolutions": { + "react": "~16.9.0", + "react-dom": "~16.9.0", + "react-is": "~16.9.0", + "react-test-renderer": "~16.9.0" + }, + "devDependencies": { + "@babel/core": "^7.10.0", + "@babel/plugin-proposal-class-properties": "^7.7.4", + "@babel/plugin-proposal-export-default-from": "^7.7.4", + "@babel/plugin-proposal-export-namespace-from": "^7.7.4", + "@babel/plugin-transform-runtime": "^7.10.0", + "@babel/preset-env": "^7.10.0", + "@babel/preset-react": "^7.10.0", + "@babel/runtime": "^7.10.0", + "@commitlint/cli": "^8.3.5", +`; + // prettier-ignore + return html` + ${children} + +`; + }, +}; + +export const MultilineWithLayer = { + render: () => { + const children = `"scripts": { + "build": "lerna run build --stream --prefix --npm-client yarn", + "ci-check": "carbon-cli ci-check", + "clean": "lerna run clean && lerna clean --yes && rimraf node_modules", + "doctoc": "doctoc --title '## Table of Contents'", + "format": "prettier --write '**/*.{js,md,scss,ts}' '!**/{build,es,lib,storybook,ts,umd}/**'", + "format:diff": "prettier --list-different '**/*.{js,md,scss,ts}' '!**/{build,es,lib,storybook,ts,umd}/**' '!packages/components/**'", + "lint": "eslint actions config codemods packages", + "lint:styles": "stylelint '**/*.{css,scss}' --report-needless-disables --report-invalid-scope-disables", + "sync": "carbon-cli sync", + "test": "cross-env BABEL_ENV=test jest", + "test:e2e": "cross-env BABEL_ENV=test jest --testPathPattern=e2e --testPathIgnorePatterns='examples,/packages/components/,/packages/react/'" + }, + "resolutions": { + "react": "~16.9.0", + "react-dom": "~16.9.0", + "react-is": "~16.9.0", + "react-test-renderer": "~16.9.0" + }, + "devDependencies": { + "@babel/core": "^7.10.0", + "@babel/plugin-proposal-class-properties": "^7.7.4", + "@babel/plugin-proposal-export-default-from": "^7.7.4", + "@babel/plugin-proposal-export-namespace-from": "^7.7.4", + "@babel/plugin-transform-runtime": "^7.10.0", + "@babel/preset-env": "^7.10.0", + "@babel/preset-react": "^7.10.0", + "@babel/runtime": "^7.10.0", + "@commitlint/cli": "^8.3.5", +`; + // prettier-ignore + return html` + + ${children} + + +`; + }, +}; + +export const Singleline = { + render: () => { + return html` + + yarn add carbon-components@latest carbon-components-react@latest + @carbon/icons-react@latest carbon-icons@latest + + `; + }, +}; + +export const SinglelineWithLayer = { + render: () => { + return html` + + yarn add carbon-components@latest carbon-components-react@latest + @carbon/icons-react@latest carbon-icons@latest > + + `; + }, +}; + +export const Skeleton = { + parameters: { + percy: { + skip: true, + }, + }, + render: () => + html` + + + `, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + copyButtonDescription, + copyText, + disabled, + feedback, + feedbackTimeout, + hideCopyButton, + maxCollapsedNumberOfRows, + maxExpandedNumberOfRows, + minCollapsedNumberOfRows, + minExpandedNumberOfRows, + showLessText, + showMoreText, + wrapText, + } = args ?? {}; + return html` + yarn add @carbon/react + + `; + }, +}; + +const meta = { + title: 'Components/Code snippet', +}; + +export default meta; diff --git a/packages/web-components/src/components/code-snippet/code-snippet.ts b/packages/web-components/src/components/code-snippet/code-snippet.ts new file mode 100644 index 000000000000..51c6f3f11790 --- /dev/null +++ b/packages/web-components/src/components/code-snippet/code-snippet.ts @@ -0,0 +1,475 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { styleMap } from 'lit/directives/style-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import ChevronDown16 from '@carbon/icons/lib/chevron--down/16'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import { CODE_SNIPPET_COLOR_SCHEME, CODE_SNIPPET_TYPE } from './defs'; +import styles from './code-snippet.scss?lit'; +import Handle from '../../globals/internal/handle'; +import '../copy-button/index'; +import '../copy/copy'; +import '../button/button'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { CODE_SNIPPET_COLOR_SCHEME, CODE_SNIPPET_TYPE }; + +/** + * Observes resize of the given element with the given resize observer. + * + * @param observer The resize observer. + * @param elem The element to observe the resize. + */ +const observeResize = (observer: ResizeObserver, elem: Element) => { + if (!elem) { + return null; + } + observer.observe(elem); + return { + release() { + observer.unobserve(elem); + return null; + }, + } as Handle; +}; + +/** + * Basic code snippet. + * + * @element cds-code-snippet + */ +@customElement(`${prefix}-code-snippet`) +class CDSCodeSnippet extends FocusMixin(LitElement) { + /** + * `true` to expand multi-line variant of code snippet. + */ + private _expandedCode = false; + + /** + * The handle for observing resize of the parent element of this element. + */ + private _hObserveResize: Handle | null = null; + + /** + * Row height in pixels + */ + private _rowHeightInPixels = 16; + + /** + * `true` if code-snippet has right overflow + */ + private _hasRightOverflow = true; + + /** + * `true` if code-snippet has left overflow + */ + private _hasLeftOverflow = false; + + /** + * `true` if show more or show less btn is visible + */ + private _shouldShowMoreLessBtn = false; + + /** + * Handles `click` event on the copy button. + */ + private _handleCopyClick() { + const { ownerDocument: doc } = this; + const selection = doc!.defaultView!.getSelection(); + selection!.removeAllRanges(); + const code = doc!.createElement('code'); + code.className = `${prefix}--visually-hidden`; + const pre = doc!.createElement('pre'); + const text = Array.from(this.childNodes).filter( + (node) => node.nodeType === Node.TEXT_NODE + ); + pre.textContent = this.copyText || text[0].textContent; + code.appendChild(pre); + // Using `` in shadow DOM seems to lose the LFs in some browsers + doc!.body.appendChild(code); + const range = doc!.createRange(); + range.selectNodeContents(code); + selection!.addRange(range); + doc!.execCommand('copy'); + doc!.body.removeChild(code); + selection!.removeAllRanges(); + } + + // eslint-disable-next-line class-methods-use-this + private _getCodeRefDimensions(ref) { + const { + clientWidth: codeClientWidth, + scrollLeft: codeScrollLeft, + scrollWidth: codeScrollWidth, + } = ref; + + return { + horizontalOverflow: codeScrollWidth > codeClientWidth, + codeClientWidth, + codeScrollWidth, + codeScrollLeft, + }; + } + /** + * Handles `scroll` event. + */ + private _handleScroll() { + if (this) { + const codeContainerRef = this?.shadowRoot?.querySelector( + `.${prefix}--snippet-container` + ); + const codeContentRef = codeContainerRef?.querySelector('pre'); + if ( + this.type === CODE_SNIPPET_TYPE.INLINE || + (this.type === CODE_SNIPPET_TYPE.SINGLE && !codeContainerRef) || + (this.type === CODE_SNIPPET_TYPE.MULTI && !codeContentRef) + ) { + return; + } + + const { + horizontalOverflow, + codeClientWidth, + codeScrollWidth, + codeScrollLeft, + } = + this.type === CODE_SNIPPET_TYPE.SINGLE + ? this._getCodeRefDimensions(codeContainerRef) + : this._getCodeRefDimensions(codeContentRef); + + this._hasLeftOverflow = horizontalOverflow && !!codeScrollLeft; + this._hasRightOverflow = + horizontalOverflow && + codeScrollLeft + codeClientWidth !== codeScrollWidth; + this.requestUpdate(); + } + } + + /** + * Handles `click` event on the show more or show less button. + */ + private _handleClickExpanded() { + this._expandedCode = !this._expandedCode; + this.requestUpdate(); + } + + /** + * The `ResizeObserver` instance for observing element resizes for re-positioning floating menu position. + */ + // TODO: Wait for `.d.ts` update to support `ResizeObserver` + // @ts-ignore + private _resizeObserver = new ResizeObserver(() => { + const codeContainerRef = this.shadowRoot?.querySelector( + `.${prefix}--snippet-container` + ); + const codeContentRef = codeContainerRef?.querySelector('code'); // PRE? + const { + type, + maxCollapsedNumberOfRows, + maxExpandedNumberOfRows, + minExpandedNumberOfRows, + _rowHeightInPixels: rowHeightInPixels, + _handleScroll: handleScroll, + } = this; + if (codeContentRef && type === CODE_SNIPPET_TYPE.MULTI) { + const { height } = codeContentRef.getBoundingClientRect(); + if ( + maxCollapsedNumberOfRows > 0 && + (maxExpandedNumberOfRows <= 0 || + maxExpandedNumberOfRows > maxCollapsedNumberOfRows) && + height > maxCollapsedNumberOfRows * rowHeightInPixels + ) { + this._shouldShowMoreLessBtn = true; + } else { + this._shouldShowMoreLessBtn = false; + } + if ( + this._expandedCode && + minExpandedNumberOfRows > 0 && + height <= minExpandedNumberOfRows * rowHeightInPixels + ) { + this._expandedCode = false; + } + } + if ( + (codeContentRef && type === CODE_SNIPPET_TYPE.MULTI) || + (codeContainerRef && type === CODE_SNIPPET_TYPE.SINGLE) + ) { + handleScroll(); + } + this.requestUpdate(); + }); + + /** + * Optional text to copy. If not specified, the `children` node's `innerText` + * will be used as the copy value. + */ + @property({ attribute: 'copy-text' }) + copyText = ''; + + /** + * `true` if the button should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * Specify the string displayed when the snippet is copied + */ + @property() + feedback = 'Copied!'; + + /** + * Specify the time it takes for the feedback message to timeout + */ + @property({ type: Number, attribute: 'feedback-timeout' }) + feedbackTimeout = 2000; + + /** + * Specify whether or not a copy button should be used/rendered. + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-copy-button' }) + hideCopyButton = false; + + /** + * Specify the maximum number of rows to be shown when in collapsed view + */ + @property() + maxCollapsedNumberOfRows = 15; + + /** + * Specify the maximum number of rows to be shown when in expanded view + */ + @property() + maxExpandedNumberOfRows = 0; + + /** + * Specify the minimum number of rows to be shown when in collapsed view + */ + @property() + minCollapsedNumberOfRows = 3; + + /** + * Specify the minimum number of rows to be shown when in expanded view + */ + @property() + minExpandedNumberOfRows = 16; + + /** + * Specify a string that is displayed when the Code Snippet has been + * interacted with to show less lines + */ + @property({ attribute: 'show-less-text' }) + showLessText = 'Show less'; + + /** + * Specify a string that is displayed when the Code Snippet text is more + * than 15 lines + */ + @property({ attribute: 'show-more-text' }) + showMoreText = 'Show more'; + + /** + * Tooltip content for the copy button. + */ + @property({ attribute: 'tooltip-content' }) + tooltipContent = 'Copy to clipboard'; + + /** + * `true` if the button should be disabled. + */ + @property({ type: Boolean, reflect: true, attribute: 'wrap-text' }) + wrapText = false; + + /** + * The type of code snippet. + */ + @property({ reflect: true }) + type = CODE_SNIPPET_TYPE.SINGLE; + + connectedCallback() { + super.connectedCallback(); + if (this._hObserveResize) { + this._hObserveResize = this._hObserveResize.release(); + } + this._hObserveResize = observeResize(this._resizeObserver, this); + } + + disconnectedCallback() { + if (this._hObserveResize) { + this._hObserveResize = this._hObserveResize.release(); + } + } + + updated() { + if (this._expandedCode) { + this.setAttribute('expanded-code', ''); + } else { + this.removeAttribute('expanded-code'); + } + } + + render() { + const { + disabled, + feedback, + feedbackTimeout, + hideCopyButton, + maxExpandedNumberOfRows, + minExpandedNumberOfRows, + maxCollapsedNumberOfRows, + minCollapsedNumberOfRows, + type, + wrapText, + tooltipContent, + showMoreText, + showLessText, + _expandedCode: expandedCode, + _handleCopyClick: handleCopyClick, + _handleScroll: handleScroll, + _hasRightOverflow: hasRightOverflow, + _hasLeftOverflow: hasLeftOverflow, + _rowHeightInPixels: rowHeightInPixels, + _shouldShowMoreLessBtn: shouldShowMoreLessBtn, + } = this; + + let classes = `${prefix}--snippet`; + type ? (classes += ` ${prefix}--snippet--${type}`) : ''; + type !== 'inline' && disabled + ? (classes += ` ${prefix}--snippet--disabled`) + : ''; + hideCopyButton ? (classes += ` ${prefix}--snippet--no-copy`) : ''; + wrapText ? (classes += ` ${prefix}--snippet--wraptext`) : ''; + type == 'multi' && hasRightOverflow + ? (classes += ` ${prefix}--snippet--has-right-overflow`) + : ''; + + const expandButtonClass = `${prefix}--snippet-btn--expand`; + + const disabledCopyButtonClasses = disabled + ? `${prefix}--snippet--disabled` + : ''; + + const expandCodeBtnText = expandedCode ? showLessText : showMoreText; + + if (type === CODE_SNIPPET_TYPE.INLINE) { + // Ensures no extra whitespace text node + // prettier-ignore + return html` + + + ${tooltipContent} + + `; + } + + const styles = {}; + if (type === 'multi') { + if (expandedCode) { + if (maxExpandedNumberOfRows > 0) { + styles['max-height'] = + maxExpandedNumberOfRows * rowHeightInPixels + 'px'; + } + if (minExpandedNumberOfRows > 0) { + styles['min-height'] = + minExpandedNumberOfRows * rowHeightInPixels + 'px'; + } + } else { + if (maxCollapsedNumberOfRows > 0) { + styles['max-height'] = + maxCollapsedNumberOfRows * rowHeightInPixels + 'px'; + } + if (minCollapsedNumberOfRows > 0) { + styles['min-height'] = + minCollapsedNumberOfRows * rowHeightInPixels + 'px'; + } + } + } + + return html` +
    +
    +
    + + ${hasLeftOverflow + ? html` +
    + ` + : ``} + ${hasRightOverflow && type !== CODE_SNIPPET_TYPE.MULTI + ? html` +
    + ` + : ``} + ${hideCopyButton + ? `` + : html` + + ${tooltipContent} + + `} + ${shouldShowMoreLessBtn + ? html` + this._handleClickExpanded()}> + + ${expandCodeBtnText} + + ${ChevronDown16({ + class: `${prefix}--icon-chevron--down ${prefix}--snippet__icon`, + name: 'cheveron--down', + role: 'img', + slot: 'icon', + })} + + ` + : ``} + `; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; +} + +export default CDSCodeSnippet; diff --git a/packages/web-components/src/components/code-snippet/defs.ts b/packages/web-components/src/components/code-snippet/defs.ts new file mode 100644 index 000000000000..1a5522c92180 --- /dev/null +++ b/packages/web-components/src/components/code-snippet/defs.ts @@ -0,0 +1,30 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +export { FORM_ELEMENT_COLOR_SCHEME as CODE_SNIPPET_COLOR_SCHEME } from '../../globals/shared-enums'; + +/** + * Code snippet types. + */ +export enum CODE_SNIPPET_TYPE { + /** + * Single variant. + */ + SINGLE = 'single', + + /** + * Inline variant. + */ + INLINE = 'inline', + + /** + * Multi-line variant. + */ + MULTI = 'multi', +} diff --git a/packages/web-components/src/components/code-snippet/docs/overview.mdx b/packages/web-components/src/components/code-snippet/docs/overview.mdx new file mode 100644 index 000000000000..c96bcabf75a2 --- /dev/null +++ b/packages/web-components/src/components/code-snippet/docs/overview.mdx @@ -0,0 +1,20 @@ +## Live demo + + diff --git a/packages/web-components/src/components/code-snippet/index.ts b/packages/web-components/src/components/code-snippet/index.ts new file mode 100644 index 000000000000..e0b66808a6fd --- /dev/null +++ b/packages/web-components/src/components/code-snippet/index.ts @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './code-snippet'; +import './code-snippet-skeleton'; diff --git a/packages/web-components/src/components/combo-box/combo-box-item.ts b/packages/web-components/src/components/combo-box/combo-box-item.ts new file mode 100644 index 000000000000..f75b547ccaf9 --- /dev/null +++ b/packages/web-components/src/components/combo-box/combo-box-item.ts @@ -0,0 +1,25 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { prefix } from '../../globals/settings'; +import CDSDropdownItem from '../dropdown/dropdown-item'; +import styles from './combo-box.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Combo box item. + * + * @element cds-combo-box-item + */ +@customElement(`${prefix}-combo-box-item`) +class CDSComboBoxItem extends CDSDropdownItem { + static styles = styles; +} + +export default CDSComboBoxItem; diff --git a/packages/web-components/src/components/combo-box/combo-box.mdx b/packages/web-components/src/components/combo-box/combo-box.mdx new file mode 100644 index 000000000000..2d469480e2bc --- /dev/null +++ b/packages/web-components/src/components/combo-box/combo-box.mdx @@ -0,0 +1,108 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as ComboBoxStories from './combo-box.stories'; + + + +# Combo box + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/combo-box) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/combo-box) + +A combobox allows the user to make a selection from a predefined list of options +and is typically used when there are a large amount of options to choose from. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/combo-box/index.js'; +``` + +{`${cdnJs({ components: ['combo-box'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + Option 6 + Option 7 + Option 8 + +``` + +## Disabled + +A disabled combobox is available but should not be used as the sole means of +conveying information. For example, if the user must complete a previous form +input before moving on to the combobox, make sure to make that clear to the user +via an error state on the previous form element in addition to disabling the +next element. + +```html + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + Option 6 + Option 7 + Option 8 + +``` + +## Labels and Helper Texts + +The label is not a replacement for a helper or title text under any +circumstances including space restraints. A label should be used to provide +additive information regarding the format of the input. In all cases a helper +text is required in addition to a placeholder. + +## Selection + +When user attempts to select a combo box item, `cds-combo-box-beingselected` +event fires on ``, which has the following properties in the +event details: + +| Property | Description | +| -------- | ------------------------------------------ | +| `item` | The `` being selected. | + +`cds-combo-box-beingselected` bubbles and is cancelable. Canceling this event +means canceling change in selection. + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `open` attribute). + + + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `disabled` attribute). + + diff --git a/packages/web-components/src/components/combo-box/combo-box.scss b/packages/web-components/src/components/combo-box/combo-box.scss new file mode 100644 index 000000000000..1fdeb8e83f6e --- /dev/null +++ b/packages/web-components/src/components/combo-box/combo-box.scss @@ -0,0 +1,161 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/layout' as *; +@use '@carbon/styles/scss/components/combo-box' as *; +@use '@carbon/styles/scss/components/form'; +@use '@carbon/styles/scss/components/text-input/text-input'; +@use '../dropdown/dropdown.scss'; + +:host(#{$prefix}-combo-box) { + @extend :host(#{$prefix}-dropdown); + @include emit-layout-tokens(); + + outline: none; + + .#{$prefix}--assistive-text { + inset-block-start: -100%; + // Hides screen reader cursor + inset-inline-start: -100%; + } + + .#{$prefix}--list-box__field { + padding: 0; + } + + .#{$prefix}--list-box__menu { + inset-block-start: 100%; + margin-block-start: 1px; + outline: none; + } +} + +:host(#{$prefix}-combo-box[isClosable]) { + .#{$prefix}--list-box__invalid-icon { + /* stylelint-disable declaration-no-important */ + inset-inline-end: to-rem(66px) !important; + /* stylelint-enable declaration-no-important */ + } +} + +:host(#{$prefix}-combo-box[disabled]), +:host(#{$prefix}-combo-box[read-only]) { + .#{$prefix}--list-box__selection { + pointer-events: none; + } +} + +:host(#{$prefix}-combo-box[invalid]) { + .#{$prefix}--form__helper-text { + color: $text-error; + } +} + +:host(#{$prefix}-combo-box[read-only]) { + .#{$prefix}--list-box__selection svg { + fill: $icon-disabled; + } +} + +:host(#{$prefix}-combo-box-item) { + @extend .#{$prefix}--list-box__menu-item; + + display: block; + + .#{$prefix}--list-box__menu-item__option { + block-size: auto; + } + + &:hover { + background-color: $layer-hover; + } +} + +:host(#{$prefix}-combo-box-item[disabled]) { + .#{$prefix}--list-box__menu-item__option { + color: $text-disabled; + text-decoration: none; + } +} + +:host(#{$prefix}-combo-box-item[highlighted]) { + @extend .#{$prefix}--list-box__menu-item--highlighted; +} + +:host(#{$prefix}-combo-box-item[selected]) { + @extend .#{$prefix}--list-box__menu-item--active; + @extend .#{$prefix}--list-box__menu-item--highlighted; + + .#{$prefix}--list-box__menu-item__option { + color: $text-primary; + } + + .#{$prefix}--list-box__menu-item__selected-icon { + display: block; + } +} + +:host(#{$prefix}-combo-box-item[size='sm']) { + block-size: $spacing-07; + + .#{$prefix}--list-box__menu-item__option { + padding-block: to-rem(7px); + } +} + +:host(#{$prefix}-combo-box-item[size='lg']) { + block-size: $spacing-09; + + .#{$prefix}--list-box__menu-item__option { + padding-block: to-rem(15px); + } +} + +:host(#{$prefix}-combo-box[slug]) { + @extend .#{$prefix}--list-box__wrapper--slug; + + .#{$prefix}--list-box__field { + padding: 0; + } + + ::slotted(#{$prefix}-slug) { + position: absolute; + inset-block-start: 50%; + inset-inline-end: $spacing-08; + } + + ::slotted(#{$prefix}-slug:not([revert-active])) { + transform: translateY(-50%); + } +} + +:host(#{$prefix}-combo-box[slug][isclosable]) { + ::slotted(#{$prefix}-slug) { + inset-inline-end: $spacing-10; + } +} + +:host(#{$prefix}-combo-box[warn]), +:host(#{$prefix}-combo-box[invalid]) { + ::slotted(#{$prefix}-slug) { + inset-inline-end: $spacing-10; + } +} + +:host(#{$prefix}-combo-box[warn][isclosable]), +:host(#{$prefix}-combo-box[invalid][isclosable]) { + ::slotted(#{$prefix}-slug) { + inset-inline-end: to-rem(88px); + } +} diff --git a/packages/web-components/src/components/combo-box/combo-box.stories.ts b/packages/web-components/src/components/combo-box/combo-box.stories.ts new file mode 100644 index 000000000000..00d85d4a3fe8 --- /dev/null +++ b/packages/web-components/src/components/combo-box/combo-box.stories.ts @@ -0,0 +1,221 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { DROPDOWN_DIRECTION, DROPDOWN_SIZE } from './combo-box'; +import './combo-box-item'; + +const items = [ + { + value: 'option-0', + text: 'An example option that is really long to show what should be done to handle long text', + }, + { + value: 'option-1', + text: 'Option 1', + }, + { + value: 'option-2', + text: 'Option 2', + }, + { + value: 'option-3', + text: 'Option 3 - a disabled item', + disabled: true, + }, + { + value: 'option-4', + text: 'Option 4', + }, + { + value: 'option-5', + text: 'Option 5', + }, +]; + +const directionOptions = { + [`Top`]: DROPDOWN_DIRECTION.TOP, + [`Bottom`]: DROPDOWN_DIRECTION.BOTTOM, +}; + +const sizes = { + [`Small size (${DROPDOWN_SIZE.SMALL})`]: DROPDOWN_SIZE.SMALL, + 'Regular size': null, + [`Large size (${DROPDOWN_SIZE.LARGE})`]: DROPDOWN_SIZE.LARGE, +}; + +const defaultArgs = { + direction: DROPDOWN_DIRECTION.BOTTOM, + disabled: false, + hideLabel: false, + helperText: 'This is some helper text', + invalid: false, + invalidText: 'invalid selection', + label: 'This is an example label', + readOnly: false, + size: null, + titleText: 'This is an example title', + value: '', + warn: false, + warnText: 'please notice the warning', +}; + +const controls = { + disabled: { + control: 'boolean', + description: `Specify if the dropdown should be disabled, or not.`, + }, + direction: { + control: 'select', + options: directionOptions, + description: `Dropdown direction`, + }, + hideLabel: { + control: 'boolean', + description: `Specify if the title text should be hidden, or not.`, + }, + helperText: { + control: 'text', + description: `The helper text for the dropdown.`, + }, + invalid: { + control: 'boolean', + description: `Specify if the dropdown should display an invalid icon, or not.`, + }, + invalidText: { + control: 'text', + description: `Message which is displayed if the value is invalid.`, + }, + label: { + control: 'text', + description: `The default content of the trigger button.`, + }, + readOnly: { + control: 'boolean', + description: `Specify if the dropdown should be read only, or not.`, + }, + size: { + control: 'select', + options: sizes, + description: `Dropdown size.`, + }, + titleText: { + control: 'text', + description: `Text that will be read by a screen reader when visiting this control.`, + }, + value: { + control: 'text', + description: `The value of the selected item.`, + }, + warn: { + control: 'boolean', + description: `Specify whether the control is currently in warning state.`, + }, + warnText: { + control: 'text', + description: `Text that is displayed when the control is in warning state.`, + }, +}; + +export const Default = { + render: () => html` + + ${items.map( + (elem) => html` + ${elem.text} + ` + )} + + `, +}; + +export const WithLayer = { + render: () => html` + +
    + + ${items.map( + (elem) => html` + ${elem.text} + ` + )} + +
    +
    + `, +}; + +export const Playground = { + argTypes: controls, + args: defaultArgs, + render: ({ + disabled, + helperText, + invalid, + titleText, + hideLabel, + direction, + readOnly, + warn, + warnText, + size, + label, + type, + invalidText, + value, + }) => html` + + ${items.map( + (elem) => html` + ${elem.text} + ` + )} + + `, +}; + +const meta = { + title: 'Components/Combo box', + decorators: [ + (story, { name }) => { + const width = !name.toLowerCase().includes('layer') ? `width:300px` : ``; + return html`
    ${story()}
    `; + }, + ], +}; + +export default meta; diff --git a/packages/web-components/src/components/combo-box/combo-box.ts b/packages/web-components/src/components/combo-box/combo-box.ts new file mode 100644 index 000000000000..2f0d2455f84b --- /dev/null +++ b/packages/web-components/src/components/combo-box/combo-box.ts @@ -0,0 +1,376 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { TemplateResult, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import Close16 from '@carbon/icons/lib/close/16'; +import { prefix } from '../../globals/settings'; +import { findIndex, forEach } from '../../globals/internal/collection-helpers'; +import CDSDropdown, { DROPDOWN_KEYBOARD_ACTION } from '../dropdown/dropdown'; +import CDSComboBoxItem from './combo-box-item'; +import styles from './combo-box.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import ifNonEmpty from '../../globals/directives/if-non-empty'; + +export { DROPDOWN_DIRECTION, DROPDOWN_SIZE } from '../dropdown/dropdown'; + +/** + * Combo box. + * + * @element cds-combo-box + * @fires cds-combo-box-beingselected + * The custom event fired before a combo box item is selected upon a user gesture. + * Cancellation of this event stops changing the user-initiated selection. + * @fires cds-combo-box-beingtoggled + * The custom event fired before the open state of this combo box is toggled upon a user gesture. + * Cancellation of this event stops the user-initiated toggling. + * @fires cds-combo-box-selected - The custom event fired after a combo box item is selected upon a user gesture. + * @fires cds-combo-box-toggled - The custom event fired after the open state of this combo box is toggled upon a user gesture. + */ +@customElement(`${prefix}-combo-box`) +class CDSComboBox extends CDSDropdown { + /** + * The text content that should be set to the `` for filtering. + */ + protected _filterInputValue = ''; + + protected _shouldTriggerBeFocusable = false; + + /** + * The `` for filtering. + */ + @query('input') + private _filterInputNode!: HTMLInputElement; + + /** + * The menu containing all selectable items. + */ + @query('#menu-body') + private _itemMenu!: HTMLElement; + + /** + * The selection button. + */ + @query('#selection-button') + private _selectionButtonNode!: HTMLElement; + + /** + * @param item A combo box item. + * @returns `true` if the given combo box item matches the query text user types. + */ + protected _testItemWithQueryText(item) { + return (this.itemMatches || this._defaultItemMatches)( + item, + this._filterInputNode.value + ); + } + + /* eslint-disable class-methods-use-this */ + /** + * The default item matching callback. + * + * @param item The combo box item. + * @param queryText The query text user types. + * @returns `true` if the given combo box item matches the given query text. + */ + protected _defaultItemMatches( + item: CDSComboBoxItem, + queryText: string + ): boolean { + return ( + item.textContent!.toLowerCase().indexOf(queryText.toLowerCase()) >= 0 + ); + } + /* eslint-enable class-methods-use-this */ + + /** + * Handles `input` event on the `` for filtering. + */ + protected _handleInput() { + if (this._filterInputValue.length != 0) { + this.setAttribute('isClosable', ''); + } else { + this.removeAttribute('isClosable'); + } + + const items = this.querySelectorAll( + (this.constructor as typeof CDSComboBox).selectorItem + ); + const index = !this._filterInputNode.value + ? -1 + : findIndex(items, this._testItemWithQueryText, this); + forEach(items, (item, i) => { + if (i === index) { + const menuRect = this._itemMenu?.getBoundingClientRect(); + const itemRect = item.getBoundingClientRect(); + + if (menuRect && itemRect) { + const isViewable = + menuRect!.top <= itemRect?.top && + itemRect?.bottom <= menuRect?.top + this._itemMenu!.clientHeight; + if (!isViewable) { + const scrollTop = itemRect?.top - menuRect?.top; + const scrollBot = itemRect?.bottom - menuRect?.bottom; + + if (Math.abs(scrollTop) < Math.abs(scrollBot)) { + this._itemMenu!.scrollTop += scrollTop; + } else { + this._itemMenu!.scrollTop += scrollBot; + } + } + } + } + (item as CDSComboBoxItem).highlighted = i === index; + }); + const { _filterInputNode: filterInput } = this; + this._filterInputValue = !filterInput ? '' : filterInput.value; + this.open = true; + this.requestUpdate(); // If the only change is to `_filterInputValue`, auto-update doesn't happen + } + + protected _handleClickInner(event: MouseEvent) { + const { target } = event as any; + if (this._selectionButtonNode?.contains(target)) { + this._handleUserInitiatedClearInput(); + } else { + super._handleClickInner(event); + } + } + + protected _handleKeypressInner(event: KeyboardEvent) { + const { key } = event; + const action = (this.constructor as typeof CDSDropdown).getAction(key); + const { TRIGGERING } = DROPDOWN_KEYBOARD_ACTION; + if ( + this._selectionButtonNode?.contains(event.target as Node) && + // Space key should be handled by `` unless "clear selection" button has focus + (action === TRIGGERING || key === ' ') + ) { + this._handleUserInitiatedClearInput(); + } else { + super._handleKeypressInner(event); + } + } + + /** + * Handles user-initiated clearing the `` for filtering. + */ + protected _handleUserInitiatedClearInput() { + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSComboBox).selectorItem + ), + (item) => { + (item as CDSComboBoxItem).highlighted = false; + } + ); + this._filterInputValue = ''; + this._filterInputNode.focus(); + this._handleUserInitiatedSelectItem(); + } + + protected _handleUserInitiatedSelectItem(item?: CDSComboBoxItem) { + if (item && !this._selectionShouldChange(item)) { + // Escape hatch for `shouldUpdate()` logic that updates `._filterInputValue()` when selection changes, + // given we want to update the `` and close the dropdown even if selection doesn't update. + // Use case: + // 1. Select the 2nd item in combo box drop down + // 2. Type some text in the `` + // 3. Re-select the 2nd item in combo box drop down, + // the `` has to updated with the 2nd item and the dropdown should be closed, + // even if there is no change in the selected value + this._filterInputValue = item.textContent || ''; + this.open = false; + this.requestUpdate(); + } + super._handleUserInitiatedSelectItem(item); + } + + protected _selectionDidChange(itemToSelect?: CDSComboBoxItem) { + this.value = !itemToSelect ? '' : itemToSelect.value; + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSDropdown).selectorItemSelected + ), + (item) => { + (item as CDSComboBoxItem).selected = false; + item.setAttribute('aria-selected', 'false'); + } + ); + if (itemToSelect) { + itemToSelect.selected = true; + itemToSelect.setAttribute('aria-selected', 'true'); + } + this._handleUserInitiatedToggle(false); + } + + protected _renderLabel(): TemplateResult { + const { + disabled, + inputLabel, + label, + open, + readOnly, + value, + _activeDescendant: activeDescendant, + _filterInputValue: filterInputValue, + _handleInput: handleInput, + } = this; + + const inputClasses = classMap({ + [`${prefix}--text-input`]: true, + [`${prefix}--text-input--empty`]: !value, + }); + + let activeDescendantFallback: string | undefined; + if (open && !activeDescendant) { + const constructor = this.constructor as typeof CDSDropdown; + const items = this.querySelectorAll(constructor.selectorItem); + activeDescendantFallback = items[0]?.id; + } + + return html` + + `; + } + + protected _renderFollowingLabel(): TemplateResult | void { + const { clearSelectionLabel, _filterInputValue: filterInputValue } = this; + + if (filterInputValue.length != 0) { + this.setAttribute('isClosable', ''); + } else { + this.removeAttribute('isClosable'); + } + + return filterInputValue.length === 0 + ? undefined + : html` +
    + ${Close16({ 'aria-label': clearSelectionLabel })} +
    + `; + } + + /** + * The `aria-label` attribute for the icon to clear selection. + */ + @property({ attribute: 'clear-selection-label' }) + clearSelectionLabel = 'Clear selection'; + + /** + * The `aria-label` attribute for the `` for filtering. + */ + @property({ attribute: 'input-label' }) + inputLabel = ''; + + /** + * The custom item matching callback. + */ + @property({ attribute: false }) + itemMatches!: (item: CDSComboBoxItem, queryText: string) => boolean; + + shouldUpdate(changedProperties) { + super.shouldUpdate(changedProperties); + const { _selectedItemContent: selectedItemContent } = this; + if (selectedItemContent && changedProperties.has('value')) { + this._filterInputValue = selectedItemContent?.textContent || ''; + } + return true; + } + + updated(changedProperties) { + super.updated(changedProperties); + const { _listBoxNode: listBoxNode } = this; + if (listBoxNode) { + listBoxNode.classList.add(`${prefix}--combo-box`); + } + } + + // For combo box, open/selection with space key is disabled given the input box should take it over + static TRIGGER_KEYS = new Set(['Enter']); + + /** + * A selector that will return highlighted items. + */ + static get selectorItemHighlighted() { + return `${prefix}-combo-box-item[highlighted]`; + } + + /** + * A selector that will return combo box items. + */ + static get selectorItem() { + return `${prefix}-combo-box-item`; + } + + /** + * A selector that will return selected items. + */ + static get selectorItemSelected() { + return `${prefix}-combo-box-item[selected]`; + } + + /** + * The name of the custom event fired before this combo box item is being toggled upon a user gesture. + * Cancellation of this event stops the user-initiated action of toggling this combo box item. + */ + static get eventBeforeToggle() { + return `${prefix}-combo-box-beingtoggled`; + } + + /** + * The name of the custom event fired after this combo box item is toggled upon a user gesture. + */ + static get eventToggle() { + return `${prefix}-combo-box-toggled`; + } + + /** + * The name of the custom event fired before a combo box item is selected upon a user gesture. + * Cancellation of this event stops changing the user-initiated selection. + */ + static get eventBeforeSelect() { + return `${prefix}-combo-box-beingselected`; + } + + /** + * The name of the custom event fired after a a combo box item is selected upon a user gesture. + */ + static get eventSelect() { + return `${prefix}-combo-box-selected`; + } + + static styles = styles; +} + +export default CDSComboBox; diff --git a/packages/web-components/src/components/combo-box/docs/overview.mdx b/packages/web-components/src/components/combo-box/docs/overview.mdx new file mode 100644 index 000000000000..8c27d91377bc --- /dev/null +++ b/packages/web-components/src/components/combo-box/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/combo-box/index.ts b/packages/web-components/src/components/combo-box/index.ts new file mode 100644 index 000000000000..b9bb2fc0dc2b --- /dev/null +++ b/packages/web-components/src/components/combo-box/index.ts @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './combo-box'; +import './combo-box-item'; diff --git a/packages/web-components/src/components/content-switcher/content-switcher-item.ts b/packages/web-components/src/components/content-switcher/content-switcher-item.ts new file mode 100644 index 000000000000..60d3efc1bed0 --- /dev/null +++ b/packages/web-components/src/components/content-switcher/content-switcher-item.ts @@ -0,0 +1,161 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import styles from './content-switcher.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Content switcher button. + * + * @element cds-content-switcher-item + */ +@customElement(`${prefix}-content-switcher-item`) +export default class CDSContentSwitcherItem extends FocusMixin(LitElement) { + /** + * `true` if this content switcher item should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * `true` to hide the divider at the left. + * + * @private + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-divider' }) + hideDivider = false; + + /** + * `true` if the content switcher button should be selected. + * + * @private + */ + @property({ type: Boolean, reflect: true }) + selected = false; + + /** + * The element ID of target panel. + */ + @property() + target!: string; + + /** + * The `value` attribute that is set to the parent `` + * when this content switcher item is selected. + */ + @property() + value = ''; + + /** + * `true` if the content switcher button should be icon-only. + */ + @property({ type: Boolean, reflect: true }) + icon = false; + + /** + * Specify how the trigger should align with the tooltip for icon-only + * switcher item + */ + @property({ reflect: true, type: String }) + align = 'top'; + + /** + * Determines whether the tooltip should close when inner content is + * activated (click, Enter or Space) + */ + @property({ attribute: 'close-on-activation', reflect: true, type: Boolean }) + closeOnActivation = true; + + /** + * Specify the duration in milliseconds to delay before displaying the + * tooltip for icon-only switcher item + */ + enterDelayMs = 100; + + /** + * Specify the duration in milliseconds to delay before hiding the tooltip + * for icon-only switcher-item + * + * TODO: match upstream value once #10471 is resolved + */ + leaveDelayMs = 100; + + updated(changedProperties) { + if (changedProperties) { + this.shadowRoot + ?.querySelector(`${prefix}-tooltip`) + ?.shadowRoot?.querySelector(`.${prefix}--tooltip`) + ?.classList.add(`${prefix}--icon-tooltip`); + } + } + + // eslint-disable-next-line class-methods-use-this + protected _renderTooltipContent() { + return html` + + + + `; + } + + shouldUpdate(changedProperties) { + if (changedProperties.has('selected') || changedProperties.has('target')) { + const { selected, target } = this; + if (target) { + const doc = this.getRootNode() as HTMLDocument; + // `doc` can be an element if such element is orphaned + const targetNode = doc?.getElementById(target); + targetNode?.toggleAttribute('hidden', !selected); + } + } + return true; + } + + render() { + const { disabled, selected, target } = this; + const className = classMap({ + [`${prefix}--content-switcher-btn`]: true, + [`${prefix}--content-switcher--selected`]: selected, + }); + const switcherItem = html``; + + if (this.icon) { + const { align, closeOnActivation, enterDelayMs, leaveDelayMs } = this; + return html` + ${switcherItem} ${this._renderTooltipContent()} + `; + } + return switcherItem; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; +} diff --git a/packages/web-components/src/components/content-switcher/content-switcher.mdx b/packages/web-components/src/components/content-switcher/content-switcher.mdx new file mode 100644 index 000000000000..5889088bb7ba --- /dev/null +++ b/packages/web-components/src/components/content-switcher/content-switcher.mdx @@ -0,0 +1,54 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as ContentSwitcherStories from './content-switcher.stories'; + + + +# Content switcher + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/content-switcher) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/content-switcher) + +Content switcher manipulates the content shown following an exclusive or +“either/or” pattern. It is used to toggle between two or more content sections +within the same space on screen. Only one section can be shown at a time. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/content-switcher/index.js'; +``` + +{`${cdnJs({ components: ['content-switcher'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + +``` + +## `` attributes, properties and events + + + +## `` attributes and properties + + diff --git a/packages/web-components/src/components/content-switcher/content-switcher.scss b/packages/web-components/src/components/content-switcher/content-switcher.scss new file mode 100644 index 000000000000..7ad1456a2e0f --- /dev/null +++ b/packages/web-components/src/components/content-switcher/content-switcher.scss @@ -0,0 +1,115 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/components/content-switcher/content-switcher' as *; +@use '@carbon/styles/scss/layout' as *; + +// https://github.com/carbon-design-system/carbon/issues/11408 +@include content-switcher; + +:host(#{$prefix}-content-switcher) { + @extend .#{$prefix}--content-switcher; + @include emit-layout-tokens(); +} + +:host(#{$prefix}-content-switcher[icon]) { + @extend .#{$prefix}--content-switcher--icon-only; +} + +:host(#{$prefix}-content-switcher[size='sm']) { + @extend .#{$prefix}--layout--size-sm; +} + +:host(#{$prefix}-content-switcher[size='lg']) { + @extend .#{$prefix}--layout--size-lg; +} + +:host(#{$prefix}-content-switcher-item) { + inline-size: 100%; + outline: none; + + .#{$prefix}--content-switcher-btn { + align-items: center; + padding: $spacing-03 var(--cds-layout-density-padding-inline-local); + block-size: 100%; + inline-size: 100%; + + &:first-child, + &:last-child { + border-radius: 0; + border-inline-end: none; + border-inline-start: none; + } + + &::before { + position: absolute; + z-index: 2; + display: block; + background-color: $border-subtle; + block-size: $spacing-05; + content: ''; + inline-size: rem(1px); + inset-inline-start: 0; + } + + &.#{$prefix}--content-switcher--selected, + &:focus, + &:hover { + &::before { + background-color: transparent; + } + } + + &:disabled { + border-block-end-color: $border-inverse; + border-block-start-color: $border-inverse; + } + } +} + +:host(#{$prefix}-content-switcher-item[icon]) { + inline-size: initial; + + .#{$prefix}--content-switcher-btn { + block-size: $spacing-08; + padding-inline: rem(11px); + } + + .#{$prefix}--content-switcher__label { + display: flex; + align-items: center; + } +} + +:host(#{$prefix}-content-switcher-item[hide-divider]) + .#{$prefix}--content-switcher-btn::before { + background-color: transparent; +} + +:host(#{$prefix}-content-switcher-item:first-of-type) + .#{$prefix}--content-switcher-btn { + border-end-start-radius: $spacing-02; + border-inline-start: rem(1px) solid $border-inverse; + border-start-start-radius: $spacing-02; + + &::before { + content: none; + } +} + +:host(#{$prefix}-content-switcher-item:last-of-type) + .#{$prefix}--content-switcher-btn { + border-end-end-radius: $spacing-02; + border-inline-end: rem(1px) solid $border-inverse; + border-start-end-radius: $spacing-02; +} diff --git a/packages/web-components/src/components/content-switcher/content-switcher.stories.ts b/packages/web-components/src/components/content-switcher/content-switcher.stories.ts new file mode 100644 index 000000000000..4e78f651af64 --- /dev/null +++ b/packages/web-components/src/components/content-switcher/content-switcher.stories.ts @@ -0,0 +1,173 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { CONTENT_SWITCHER_SIZE } from './content-switcher'; +import './index'; +import { prefix } from '../../globals/settings'; +import TableOfContents16 from '@carbon/icons/lib/table-of-contents/16'; +import Workspace16 from '@carbon/icons/lib/workspace/16'; +import ViewMode2_16 from '@carbon/icons/lib/view--mode-2/16'; +import '../layer/index'; +import '../../../.storybook/templates/with-layer'; + +const noop = () => {}; + +const sizes = { + 'Medium (md - default)': null, + [`Small (${CONTENT_SWITCHER_SIZE.SMALL})`]: CONTENT_SWITCHER_SIZE.SMALL, + [`Large (${CONTENT_SWITCHER_SIZE.LARGE})`]: CONTENT_SWITCHER_SIZE.LARGE, +}; + +const args = { + value: '', + size: null, + disableSelection: false, +}; + +const argTypes = { + value: { + control: 'text', + description: 'The value of the selected item (value)', + }, + size: { + control: 'select', + options: sizes, + description: 'Button size (size)', + }, + disableSelection: { + control: 'boolean', + description: `Disable user-initiated selection change (Call event.preventDefault() in ${prefix}-content-switcher-beingselected event)`, + }, + onBeforeSelect: { + action: `${prefix}-content-switcher-beingselected`, + }, + onSelect: { + action: `${prefix}-content-switcher-selected`, + }, +}; + +export const Default = { + render: () => html` + + + First section + + + Second section + + + Third section + + + `, +}; + +export const IconOnly = { + render: () => html` + + + ${TableOfContents16()} + Table of Contents + + + ${Workspace16()} + Workspace Test + + + ${ViewMode2_16()} + View Mode + + + `, +}; + +export const IconOnlyWithLayer = { + render: () => html` + + + + ${TableOfContents16()} + Table of Contents + + + ${Workspace16()} + Workspace Test + + + ${ViewMode2_16()} + View Mode + + + + `, +}; + +export const WithLayer = { + render: () => html` + + + + First section + + + Second section + + + Third section + + + + `, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + value, + disableSelection, + onBeforeSelect = noop, + onSelect = noop, + size, + } = args ?? {}; + const handleBeforeSelected = (event: CustomEvent) => { + onBeforeSelect(event); + if (disableSelection) { + event.preventDefault(); + } + }; + + return html` + + + First section + + + Second section + + + Third section + + + `; + }, +}; + +const meta = { + title: 'Components/Content switcher', +}; + +export default meta; diff --git a/packages/web-components/src/components/content-switcher/content-switcher.ts b/packages/web-components/src/components/content-switcher/content-switcher.ts new file mode 100644 index 000000000000..6f8d49fef3ff --- /dev/null +++ b/packages/web-components/src/components/content-switcher/content-switcher.ts @@ -0,0 +1,321 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { forEach, indexOf } from '../../globals/internal/collection-helpers'; +import { NAVIGATION_DIRECTION, CONTENT_SWITCHER_SIZE } from './defs'; +import CDSContentSwitcherItem from './content-switcher-item'; +import styles from './content-switcher.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { NAVIGATION_DIRECTION, CONTENT_SWITCHER_SIZE }; + +/** + * @param index The index + * @param length The length of the array. + * @returns The new index, adjusting overflow/underflow. + */ +const capIndex = (index: number, length: number) => { + if (index < 0) { + return length - 1; + } + if (index >= length) { + return 0; + } + return index; +}; + +/** + * Content switcher. + * + * @element cds-content-switcher + * @fires cds-content-switcher-beingselected + * The custom event fired before a content switcher item is selected upon a user gesture. + * Cancellation of this event stops changing the user-initiated selection. + * @fires cds-content-switcher-selected - The custom event fired after a a content switcher item is selected upon a user gesture. + */ +@customElement(`${prefix}-content-switcher`) +export default class CDSContentSwitcher extends LitElement { + /** + * Handles `mouseover`/`mouseout` events on ``. + * + * @param event The event. + * @param event.target The event target. + * @param event.type The event type. + */ + private _handleHover({ target, type }: MouseEvent) { + const { selectorItem } = this.constructor as typeof CDSContentSwitcher; + const items = this.querySelectorAll(selectorItem); + const index = + type !== 'mouseover' + ? -1 + : indexOf(items, (target as Element).closest(selectorItem)!); + const nextIndex = index < 0 ? index : index + 1; + forEach(this.querySelectorAll(selectorItem), (elem, i) => { + // Specifies child `` to hide its divider instead of using CSS, + // until `:host-context()` gets supported in all major browsers + (elem as CDSContentSwitcherItem).hideDivider = i === nextIndex; + }); + + const { selectorItemSelected } = this + .constructor as typeof CDSContentSwitcher; + const selectedItem = this.querySelector(selectorItemSelected); + const nextItem = this._getNextItem( + selectedItem as CDSContentSwitcherItem, + 1 + ); + (nextItem as CDSContentSwitcherItem).hideDivider = true; + } + + /** + * @param target The current event target. + * @returns The item to be selected. + */ + protected _getCurrentItem(target: HTMLElement) { + const items = this.querySelectorAll( + (this.constructor as typeof CDSContentSwitcher).selectorItemEnabled + ); + const { selectorItem } = this.constructor as typeof CDSContentSwitcher; + const containerItem = target.closest( + selectorItem + ) as CDSContentSwitcherItem; + const index = indexOf(items, containerItem); + return items[index] ?? null; + } + + /** + * @param currentItem The currently selected item. + * @param direction The navigation direction. + * @returns The item to be selected. + */ + protected _getNextItem( + currentItem: CDSContentSwitcherItem, + direction: number + ) { + const items = this.querySelectorAll( + (this.constructor as typeof CDSContentSwitcher).selectorItemEnabled + ); + const currentIndex = indexOf(items, currentItem); + const nextIndex = capIndex(currentIndex + direction, items.length); + return nextIndex === currentIndex ? null : items[nextIndex]; + } + + /** + * Handles `click` event on content switcher item. + * + * @param event The event. + * @param event.target The event target. + */ + protected _handleClick({ target }: MouseEvent) { + const currentItem = this._getCurrentItem(target as HTMLElement); + this._handleUserInitiatedSelectItem(currentItem as CDSContentSwitcherItem); + } + + /** + * Handles `keydown` event on the top-level element in the shadow DOM. + * + * @param event The event. + * @param event.key The event key. + */ + protected _handleKeydown({ key }: KeyboardEvent) { + if (key in NAVIGATION_DIRECTION) { + this._navigate(NAVIGATION_DIRECTION[key]); + } + } + + /** + * Handles user-initiated selection of a content switcher item. + * + * @param [item] The content switcher item user wants to select. + */ + protected _handleUserInitiatedSelectItem(item: CDSContentSwitcherItem) { + if (!item.disabled && item.value !== this.value) { + const init = { + bubbles: true, + composed: true, + detail: { + item, + }, + }; + const constructor = this.constructor as typeof CDSContentSwitcher; + const beforeSelectEvent = new CustomEvent(constructor.eventBeforeSelect, { + ...init, + cancelable: true, + }); + if (this.dispatchEvent(beforeSelectEvent)) { + this._selectionDidChange(item); + const afterSelectEvent = new CustomEvent(constructor.eventSelect, init); + this.dispatchEvent(afterSelectEvent); + } + } + } + + /** + * Navigates through content switcher items. + * + * @param direction `-1` to navigate backward, `1` to navigate forward. + */ + protected _navigate(direction: number) { + const { selectorItemSelected } = this + .constructor as typeof CDSContentSwitcher; + const nextItem = this._getNextItem( + this.querySelector(selectorItemSelected) as CDSContentSwitcherItem, + direction + ); + if (nextItem) { + this._handleUserInitiatedSelectItem(nextItem as CDSContentSwitcherItem); + this.requestUpdate(); + } + } + + /** + * A callback that runs after change in content switcher selection upon user interaction is confirmed. + * + * @param itemToSelect A content switcher item. + */ + protected _selectionDidChange(itemToSelect: CDSContentSwitcherItem) { + this.value = itemToSelect.value; + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSContentSwitcher).selectorItemSelected + ), + (item) => { + (item as CDSContentSwitcherItem).selected = false; + } + ); + itemToSelect.selected = true; + // Waits for rendering with the new state that updates `tabindex` + Promise.resolve().then(() => { + itemToSelect.focus(); + + const { selectorItem } = this.constructor as typeof CDSContentSwitcher; + const items = this.querySelectorAll(selectorItem); + const index = indexOf( + items, + (itemToSelect as Element).closest(selectorItem)! + ); + const nextIndex = index < 0 ? index : index + 1; + forEach(this.querySelectorAll(selectorItem), (elem, i) => { + // Specifies child `` to hide its divider instead of using CSS, + // until `:host-context()` gets supported in all major browsers + (elem as CDSContentSwitcherItem).hideDivider = i === nextIndex; + }); + }); + } + + /** + * The value of the selected item. + */ + @property({ reflect: true }) + value = ''; + + /** + * Content switcher size. + */ + @property({ reflect: true }) + size = CONTENT_SWITCHER_SIZE.REGULAR; + + /** + * Icon only. + */ + @property({ type: Boolean, reflect: true, attribute: 'icon' }) + iconOnly = false; + + shouldUpdate(changedProperties) { + if (changedProperties.has('value')) { + const { selectorItem } = this.constructor as typeof CDSContentSwitcher; + forEach(this.querySelectorAll(selectorItem), (elem) => { + (elem as CDSContentSwitcherItem).selected = + (elem as CDSContentSwitcherItem).value === this.value; + }); + } + const { selectorIconItem } = this.constructor as typeof CDSContentSwitcher; + if (this.querySelector(selectorIconItem)) { + this.iconOnly = true; + } + return true; + } + + _handleSlotchange() { + const { selectorItemSelected } = this + .constructor as typeof CDSContentSwitcher; + const selectedItem = this.querySelector(selectorItemSelected); + const nextItem = this._getNextItem( + selectedItem as CDSContentSwitcherItem, + 1 + ); + + // Specifies child `` to hide its divider instead of using CSS, + // until `:host-context()` gets supported in all major browsers + (nextItem as CDSContentSwitcherItem).hideDivider = true; + } + + /** + * A selector that will return content switcher items. + */ + static get selectorItem() { + return `${prefix}-content-switcher-item`; + } + + /** + * A selector that will return content switcher icon items. + */ + static get selectorIconItem() { + return `${prefix}-content-switcher-item[icon]`; + } + + /** + * A selector that will return enabled content switcher items. + */ + static get selectorItemEnabled() { + return `${prefix}-content-switcher-item:not([disabled])`; + } + + /** + * A selector that will return selected items. + */ + static get selectorItemSelected() { + return `${prefix}-content-switcher-item[selected]`; + } + + /** + * The name of the custom event fired before a content switcher item is selected upon a user gesture. + * Cancellation of this event stops changing the user-initiated selection. + */ + static get eventBeforeSelect() { + return `${prefix}-content-switcher-beingselected`; + } + + /** + * The name of the custom event fired after a a content switcher item is selected upon a user gesture. + */ + static get eventSelect() { + return `${prefix}-content-switcher-selected`; + } + + render() { + const { + _handleHover: handleHover, + _handleKeydown: handleKeydown, + _handleSlotchange: handleSlotchange, + } = this; + return html` + + `; + } + + static styles = styles; +} diff --git a/packages/web-components/src/components/content-switcher/defs.ts b/packages/web-components/src/components/content-switcher/defs.ts new file mode 100644 index 000000000000..cd8ef9002604 --- /dev/null +++ b/packages/web-components/src/components/content-switcher/defs.ts @@ -0,0 +1,44 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Navigation direction, associated with key symbols. + */ +export const NAVIGATION_DIRECTION = { + Left: -1, + ArrowLeft: -1, + Right: 1, + ArrowRight: 1, +}; + +/** + * Button size. + */ +export enum CONTENT_SWITCHER_SIZE { + /** + * Regular size. + */ + REGULAR = '', + + /** + * Small size. + */ + SMALL = 'sm', + + /** + * Large size. + */ + LARGE = 'lg', + + // TODO: deprecate + /** + * X-Large size. + */ + EXTRA_LARGE = 'xl', +} diff --git a/packages/web-components/src/components/content-switcher/docs/overview.mdx b/packages/web-components/src/components/content-switcher/docs/overview.mdx new file mode 100644 index 000000000000..1bb36acde208 --- /dev/null +++ b/packages/web-components/src/components/content-switcher/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/content-switcher/index.ts b/packages/web-components/src/components/content-switcher/index.ts new file mode 100644 index 000000000000..0cc82cd4fa5f --- /dev/null +++ b/packages/web-components/src/components/content-switcher/index.ts @@ -0,0 +1,13 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '../tooltip/tooltip'; +import '../tooltip/tooltip-content'; +import './content-switcher'; +import './content-switcher-item'; diff --git a/packages/web-components/src/components/copy-button/copy-button.mdx b/packages/web-components/src/components/copy-button/copy-button.mdx new file mode 100644 index 000000000000..047380fd2cce --- /dev/null +++ b/packages/web-components/src/components/copy-button/copy-button.mdx @@ -0,0 +1,42 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as CopyButtonStories from './copy-button.stories'; + + + +# Copy button + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/copy-button) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/copy-button) + +Copy button provides the interface of copy button and its feedback tooltip. No +actual copy is performed, but application can listen to `click` event of +`` and interact with the clipboard. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/copy-button/index.js'; +``` + +{`${cdnJs({ components: ['copy-button'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + Copy to Clipboard + +``` + +## `` attributes and properties + + diff --git a/packages/web-components/src/components/copy-button/copy-button.scss b/packages/web-components/src/components/copy-button/copy-button.scss new file mode 100644 index 000000000000..1efb31eeb1a3 --- /dev/null +++ b/packages/web-components/src/components/copy-button/copy-button.scss @@ -0,0 +1,57 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/utilities/keyframes' as *; +@use '@carbon/styles/scss/motion' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/components/button'; +@use '@carbon/styles/scss/components/tooltip'; +@use '@carbon/styles/scss/components/code-snippet/code-snippet' as *; +@use '@carbon/styles/scss/components/copy-button/index'; +@use '@carbon/styles/scss/layout' as *; + +@include code-snippet; + +:host(#{$prefix}-copy-button) { + @include emit-layout-tokens(); + + display: inline-flex; + outline: none; +} + +.#{$prefix}--snippet__icon { + block-size: $spacing-05; + fill: $icon-primary; + inline-size: $spacing-05; + transition: all $duration-fast-01 motion(standard, productive); +} + +.#{$prefix}--copy-btn--animating.#{$prefix}--copy-btn--fade-out { + // https://github.com/stylelint/stylelint/issues/2363 + animation: $duration-fast-02 motion(standard, productive) hide-feedback; +} + +.#{$prefix}--copy-btn--animating.#{$prefix}--copy-btn--fade-in { + animation: $duration-fast-02 motion(standard, productive) show-feedback; +} + +// code snippet disabled overrides +.#{$prefix}--snippet--disabled, +.#{$prefix}--snippet--disabled + .#{$prefix}--btn.#{$prefix}--snippet-btn--expand { + background-color: $layer !important; /* stylelint-disable-line declaration-no-important */ + color: $text-disabled !important; /* stylelint-disable-line declaration-no-important */ + + ::slotted([slot='icon']) { + fill: $text-disabled !important; /* stylelint-disable-line declaration-no-important */ + } +} diff --git a/packages/web-components/src/components/copy-button/copy-button.stories.ts b/packages/web-components/src/components/copy-button/copy-button.stories.ts new file mode 100644 index 000000000000..340aa1d68bf6 --- /dev/null +++ b/packages/web-components/src/components/copy-button/copy-button.stories.ts @@ -0,0 +1,59 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import type { Meta } from '@storybook/web-components'; +import './copy-button'; + +const defaultArgs = { + feedback: 'Copied!', + feedbackTimeout: 2000, + iconDescription: 'Copy to clipboard', +}; + +const controls = { + feedback: { + control: 'text', + description: `Provide a description for the icon representing the copy action that can be read by screen readers`, + }, + feedbackTimeout: { + control: { type: 'number', min: 1, step: 1 }, + description: `Specify the time it takes for the feedback message to timeout`, + }, + iconDescription: { + control: 'text', + description: `Provide a description for the icon representing the copy action that can be read by screen readers`, + }, +}; + +const meta: Meta = { + title: 'Components/Copy button', + render: ({ feedbackText, feedbackTimeout, onClick, iconDescription }) => html` + + ${iconDescription} + + `, + args: defaultArgs, +}; + +export const Default = { + parameters: { + controls: { exclude: /(.*?)/ }, + }, +}; + +export const Playground = { + argTypes: controls, +}; + +export default meta; diff --git a/packages/web-components/src/components/copy-button/copy-button.ts b/packages/web-components/src/components/copy-button/copy-button.ts new file mode 100644 index 000000000000..2fb8ab45930d --- /dev/null +++ b/packages/web-components/src/components/copy-button/copy-button.ts @@ -0,0 +1,74 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import Copy16 from '@carbon/icons/lib/copy/16'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import styles from './copy-button.scss?lit'; +import '../copy/copy'; + +/** + * Copy button. + * + * @element cds-copy-button + */ +@customElement(`${prefix}-copy-button`) +class CDSCopyButton extends FocusMixin(LitElement) { + /** + * Specify an optional className to be added to your Button + */ + @property({ reflect: true, attribute: 'button-class-name' }) + buttonClassName; + + /** + * `true` if the button should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * Specify the string that is displayed when the button is clicked and the content is copi + */ + @property() + feedback = 'Copied!'; + + /** + * The number in milliseconds to determine how long the tooltip should remain. + */ + @property({ type: Number, attribute: 'feedback-timeout' }) + feedbackTimeout = 2000; + + render() { + const { buttonClassName, disabled, feedback, feedbackTimeout } = this; + + let classes = `${prefix}--copy-btn`; + + if (buttonClassName) { + classes += ` ${buttonClassName}`; + } + + return html` + + ${Copy16({ slot: 'icon', class: `${prefix}--snippet__icon` })} + + + `; + } + + static styles = styles; +} + +export default CDSCopyButton; diff --git a/packages/web-components/src/components/copy-button/docs/overview.mdx b/packages/web-components/src/components/copy-button/docs/overview.mdx new file mode 100644 index 000000000000..2c7cf60b449b --- /dev/null +++ b/packages/web-components/src/components/copy-button/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/copy-button/index.ts b/packages/web-components/src/components/copy-button/index.ts new file mode 100644 index 000000000000..ca44b28d1422 --- /dev/null +++ b/packages/web-components/src/components/copy-button/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './copy-button'; diff --git a/packages/web-components/src/components/copy/copy.ts b/packages/web-components/src/components/copy/copy.ts new file mode 100644 index 000000000000..42e28088b432 --- /dev/null +++ b/packages/web-components/src/components/copy/copy.ts @@ -0,0 +1,125 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from '../copy-button/copy-button.scss?lit'; +import CDSIconButton from '../icon-button/icon-button'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Copy. + * + * @element cds-copy + */ +@customElement(`${prefix}-copy`) +class CDSCopy extends CDSIconButton { + /** + * `true` to show the feedback tooltip. + */ + private _showFeedback = false; + + /** + * `true` to show the feedback tooltip. + */ + private _animation = ''; + + private _createHandleFeedbackTooltip = () => { + let timeoutId: number | void; + return (timeout: number) => { + const buttonClasses = this.shadowRoot?.querySelector('button')?.classList; + + if (timeoutId) { + clearTimeout(timeoutId); + timeoutId = undefined; + } + this._showFeedback = true; + buttonClasses?.add(`${prefix}--copy-btn--animating`); + this._animation = 'fade-in'; + buttonClasses?.add(`${prefix}--copy-btn--${this._animation}`); + this.requestUpdate(); + timeoutId = setTimeout(() => { + this._showFeedback = false; + this._animation = 'fade-out'; + buttonClasses?.remove(`${prefix}--copy-btn--fade-in`); + buttonClasses?.add(`${prefix}--copy-btn--${this._animation}`); + this.requestUpdate(); + }, timeout) as unknown as number; + }; + }; + + /** + * Handles showing/hiding the feedback tooltip. + */ + private _handleFeedbackTooltip = this._createHandleFeedbackTooltip(); + + /** + * Handles `click` event on the copy button. + */ + private _handleClickButton() { + this._handleFeedbackTooltip(this.feedbackTimeout); + } + + /** + * Specify the string that is displayed when the button is clicked and the content is copi + */ + @property() + feedback = 'Copied!'; + + /** + * The number in milliseconds to determine how long the tooltip should remain. + */ + @property({ type: Number, attribute: 'feedback-timeout' }) + feedbackTimeout = 2000; + + // eslint-disable-next-line class-methods-use-this + protected _renderTooltipContent() { + return html` + + ${this._showFeedback + ? this.feedback + : html``} + + `; + } + + connectedCallback() { + this.closeOnActivation = false; + this.align = 'bottom'; + + this.addEventListener('click', this._handleClickButton); + + super.connectedCallback(); + } + + updated(changedProperties) { + this.shadowRoot + ?.querySelector('button') + ?.addEventListener('animationend', () => { + if (this._animation === 'fade-out') { + const buttonClasses = + this.shadowRoot?.querySelector('button')?.classList; + buttonClasses?.remove(`${prefix}--copy-btn--animating`); + buttonClasses?.remove(`${prefix}--copy-btn--${this._animation}`); + this._animation = ''; + } + }); + + super.updated(changedProperties); + + this.shadowRoot + ?.querySelector('button') // @ts-ignore: TS thinks `host` doesn't exist on `parentNode` + ?.setAttribute('aria-label', this.parentNode?.host.textContent); + } + + static styles = styles; +} + +export default CDSCopy; diff --git a/packages/web-components/src/components/data-table/_table-action.scss b/packages/web-components/src/components/data-table/_table-action.scss new file mode 100644 index 000000000000..44ae90bcd6c9 --- /dev/null +++ b/packages/web-components/src/components/data-table/_table-action.scss @@ -0,0 +1,135 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/motion' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/components/button'; +@use '@carbon/styles/scss/components/search'; +@use '@carbon/styles/scss/components/data-table/action'; + +// +// Table toolbar +// + +:host(#{$prefix}-table-toolbar) { + @extend .#{$prefix}--table-toolbar; + + z-index: 1; +} + +:host(#{$prefix}-table-toolbar-content) { + @extend .#{$prefix}--toolbar-content; + + clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); + + ::slotted(#{$prefix}-overflow-menu) { + display: flex; + block-size: $spacing-09; + cursor: pointer; + inline-size: $spacing-09; + transition: background-color $duration-fast-02 motion(entrance, productive); + } +} + +:host(#{$prefix}-table-toolbar-content[has-batch-actions]) { + clip-path: polygon(0 0, 100% 0, 100% 0, 0 0); + transform: translate3d(0, $spacing-09, 0); + transition: transform $duration-fast-02 motion(standard, productive), + clip-path $duration-fast-02 motion(standard, productive); +} + +:host(#{$prefix}-table-toolbar-search) { + @extend .#{$prefix}--toolbar-action; + @extend .#{$prefix}--toolbar-search-container-expandable; + + &:hover { + background-color: $field-hover; + } + + flex: none; + transition: flex 175ms $standard-easing; + + .#{$prefix}--search { + block-size: 100%; + inline-size: 100%; + + .#{$prefix}--search-magnifier { + cursor: pointer; + inset-inline-start: 0; + pointer-events: all; + transition: background $duration-fast-02 motion(entrance, productive); + + &-icon { + block-size: auto; + inline-size: auto; + } + } + + .#{$prefix}--search-input { + border-block-end: 0; + } + + .#{$prefix}--search-close { + &::before { + background-color: $background-hover; + inline-size: 0; + } + + :hover { + background-color: none; + } + } + + :hover { + background-color: none; + } + } + + svg { + inset-inline-start: 0; + } +} + +:host(#{$prefix}-table-toolbar-search[size='xs']), +:host(#{$prefix}-table-toolbar-search[size='sm']) { + svg { + padding: 0; + inset-inline-start: $spacing-03; + } +} + +:host(#{$prefix}-table-toolbar-search[expanded]) { + @extend .#{$prefix}--toolbar-search-container-active; + + flex: auto; +} + +:host(#{$prefix}-table-toolbar-search[size='xs'][expanded]), +:host(#{$prefix}-table-toolbar-search[size='sm'][expanded]) { + svg { + inset-inline-start: $spacing-05; + } +} + +:host(#{$prefix}-table-toolbar-search[persistent]:hover) { + .#{$prefix}--search-input { + background-color: $field-hover; + } +} + +:host(#{$prefix}-table-batch-actions) { + @extend .#{$prefix}--batch-actions; + + box-sizing: border-box; +} + +:host(#{$prefix}-table-batch-actions[active]) { + @extend .#{$prefix}--batch-actions--active; +} diff --git a/packages/web-components/src/components/data-table/_table-core.scss b/packages/web-components/src/components/data-table/_table-core.scss new file mode 100644 index 000000000000..e30ef7a3ebf3 --- /dev/null +++ b/packages/web-components/src/components/data-table/_table-core.scss @@ -0,0 +1,521 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +// +// Table header and table body +// + +:host(#{$prefix}-table) { + @extend .#{$prefix}--data-table; + + display: table; + + ::slotted(#{$prefix}-table-head) { + @include type-style('heading-01'); + + display: table-header-group; + + background-color: $layer-accent-01; + } + + ::slotted(#{$prefix}-table-body) { + @include type-style('body-short-01'); + + display: table-row-group; + + background-color: $layer-01; + inline-size: 100%; + } +} + +:host(#{$prefix}-table[use-static-width]) { + inline-size: auto; +} + +:host(#{$prefix}-table[sticky-header]) { + ::slotted(#{$prefix}-table-head), + ::slotted(#{$prefix}-table-body) { + display: flex; + flex-direction: column; + will-change: transform; + } + + .#{$prefix}--data-table-content { + display: block; + overflow-y: scroll; + } +} + +:host(#{$prefix}-table[with-header]) { + .#{$prefix}--data-table-header-container { + display: table-caption; + } +} +.#{$prefix}--data-table-header-container { + display: table-caption; +} +:host(#{$prefix}-table-head[sticky-header]) { + position: sticky; + z-index: 1; + inline-size: 100%; + inset-block-start: 0; + will-change: transform; + + ::slotted(#{$prefix}-table-header-row) { + display: flex; + inline-size: 100%; + } +} + +:host(#{$prefix}-table-header-cell[sort-direction]) { + block-size: $spacing-09; + + .#{$prefix}--table-sort__flex { + display: flex; + align-items: center; + justify-content: space-between; + block-size: 100%; + inline-size: 100%; + min-block-size: $spacing-09; + } +} + +:host(#{$prefix}-table-header-cell[slug]), +:host(#{$prefix}-table-header-cell[slug]) .#{$prefix}--table-sort { + @include ai-table-gradient(); + + box-shadow: inset 0 1px $ai-border-strong; +} + +:host(#{$prefix}-table-header-cell[slug]) .#{$prefix}--table-sort { + background: none; +} + +:host(#{$prefix}-table-header-cell[sticky-header]) { + overflow: hidden; + + border-block-end: 1px solid $layer-active; + inline-size: 100%; + text-overflow: ellipsis; + white-space: nowrap; +} + +:host(#{$prefix}-table-header-cell[sticky-header]:not([is-sortable])) { + padding-block-start: rem(14px); +} + +:host(#{$prefix}-table-header-cell[slug]:not([is-sortable])) { + .#{$prefix}--table-header-label--slug { + display: flex; + align-items: center; + } + + ::slotted(#{$prefix}-slug) { + margin-inline-start: auto; + } +} + +// +// Common style for table cell and table header cell +// + +:host(#{$prefix}-table-header-row) ::slotted(#{$prefix}-table-header-cell), +:host(#{$prefix}-table-header-row) .#{$prefix}--table-column-checkbox, +:host(#{$prefix}-table-header-expand-row) + ::slotted(#{$prefix}-table-header-cell), +:host(#{$prefix}-table-header-expand-row) .#{$prefix}--table-expand, +:host(#{$prefix}-table-header-expand-row) .#{$prefix}--table-column-checkbox, +:host(#{$prefix}-table-row) ::slotted(#{$prefix}-table-cell), +:host(#{$prefix}-table-row) ::slotted(#{$prefix}-table-cell-skeleton), +:host(#{$prefix}-table-row) .#{$prefix}--table-column-checkbox, +:host(#{$prefix}-table-expand-row) ::slotted(#{$prefix}-table-cell), +:host(#{$prefix}-table-expand-row) ::slotted(#{$prefix}-table-cell-skeleton), +:host(#{$prefix}-table-expand-row) .#{$prefix}--table-expand, +:host(#{$prefix}-table-expand-row) .#{$prefix}--table-column-checkbox { + display: table-cell; +} + +// +// Table header row +// + +:host(#{$prefix}-table-head) ::slotted(#{$prefix}-table-header-row), +:host(#{$prefix}-table-head) ::slotted(#{$prefix}-table-header-expand-row) { + display: table-row; + block-size: $spacing-09; +} + +// +// Table header cell +// +:host(#{$prefix}-table-header-row) { + outline: none; + + ::slotted(#{$prefix}-table-header-cell), + ::slotted(#{$prefix}-table-header-cell-skeleton) { + display: table-cell; + background-color: $layer-accent-01; + color: $text-primary; + outline: none; + text-align: start; + } + + ::slotted(#{$prefix}-table-header-cell), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + padding-inline: $spacing-05; + text-align: start; + vertical-align: middle; + } + + ::slotted(#{$prefix}-table-header-cell:first-of-type), + ::slotted(#{$prefix}-table-header-cell-skeleton:first-of-type) { + padding-inline-start: $spacing-05; + } +} + +:host(#{$prefix}-table-header-row:not([batch-expansion])) { + .#{$prefix}--table-expand__button { + display: none; + } +} + +:host(#{$prefix}-table-header-row[selection-name]) { + .#{$prefix}--table-expand { + display: table-cell; + } +} + +:host(#{$prefix}-table-header-row[sticky-header]) { + #{$prefix}-checkbox { + margin: 0; + border-block-end: 1px solid $layer-active; + padding-block-start: $spacing-04; + } +} + +:host(#{$prefix}-table-header-row[expandable]), +:host(#{$prefix}-table-row[expandable]), +:host(#{$prefix}-table-header-row[selection-name]), +:host(#{$prefix}-table-row[selection-name]) { + .#{$prefix}--table-expand { + padding: $spacing-03; + block-size: $spacing-07; + inline-size: $spacing-07; + padding-inline-end: 0; + } +} + +:host(#{$prefix}-table-header-row[expanded]), +:host(#{$prefix}-table-row[expanded]) { + transition: transform $duration-moderate-01 motion(standard, productive); + .#{$prefix}--table-expand__svg { + transform: rotate(270deg); + } +} + +:host(#{$prefix}-table-header-row), +:host(#{$prefix}-table-row) { + .#{$prefix}--table-column-checkbox div, + .#{$prefix}--table-expand div { + display: flex; + align-items: center; + block-size: 100%; + } +} + +// +// Table row +// + +:host(#{$prefix}-table-body) { + ::slotted(#{$prefix}-table-row), + ::slotted(#{$prefix}-table-expand-row) { + display: table-row; + border: none; + block-size: $spacing-09; + inline-size: 100%; + outline: none; + } +} + +:host(#{$prefix}-table-body[sticky-header]) { + ::slotted(#{$prefix}-table-row), + ::slotted(#{$prefix}-table-expand-row) { + display: flex; + } +} + +// +// Table cell +// + +:host(#{$prefix}-table-cell) { + padding: 0 $spacing-05; + border-block-end: 1px solid $border-subtle; + + ::slotted(#{$prefix}-overflow-menu:hover) { + background-color: none; + } +} + +:host(#{$prefix}-table-cell[overflow-menu-on-hover]) { + ::slotted(*) { + opacity: 0; + } +} + +:host(#{$prefix}-table-cell[slug-in-header]) { + @include ai-table-gradient; +} + +:host(#{$prefix}-table-cell-content) { + @include type-style('label-01'); + + display: block; +} + +:host(#{$prefix}-table-row[sticky-header]), +:host(#{$prefix}-table-expand-row[sticky-header]) { + ::slotted(#{$prefix}-table-cell), + ::slotted(#{$prefix}-table-cell-skeleton) { + inline-size: 100%; + padding-block-start: rem(14px); + } +} + +:host(#{$prefix}-table-row[size='xl']), +:host(#{$prefix}-table-expand-row[size='xl']) { + ::slotted(#{$prefix}-table-cell), + ::slotted(#{$prefix}-table-cell-skeleton) { + vertical-align: top; + } +} + +:host(#{$prefix}-table-row), +:host(#{$prefix}-table-expand-row) { + ::slotted(#{$prefix}-table-cell), + ::slotted(#{$prefix}-table-cell-skeleton), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + color: $text-secondary; + vertical-align: middle; + } +} + +:host(#{$prefix}-table-row) { + ::slotted(#{$prefix}-table-cell:first-of-type), + ::slotted(#{$prefix}-table-cell-skeleton:first-of-type) { + padding-inline-start: $spacing-05; + } + + ::slotted(#{$prefix}-table-cell:last-of-type), + ::slotted(#{$prefix}-table-cell-skeleton:last-of-type) { + padding-inline-end: $spacing-05; + } +} + +:host(#{$prefix}-table-row[expandable]), +:host(#{$prefix}-table-row[selection-name]) { + .#{$prefix}--table-expand { + display: table-cell; + border-block-end: 1px solid $border-subtle; + padding-inline-end: 0; + transition: transform $duration-moderate-01 motion(standard, productive); + } +} + +:host(#{$prefix}-table-row[expandable][expanded]), +:host(#{$prefix}-table-row[selection-name][expanded]) { + .#{$prefix}--table-expand__svg { + transform: rotate(270deg); + } +} + +:host(#{$prefix}-table-row[expandable][expanded]), +:host(#{$prefix}-table-row[selection-name][expandable][expanded]), +:host(#{$prefix}-table-row[expandable][expanded][highlighted]), +:host(#{$prefix}-table-row[selection-name][expandable][expanded][highlighted]) + :host(#{$prefix}-table-row[expandable][expanded]:hover), +:host(#{$prefix}-table-row[selection-name][expandable][expanded]:hover) { + .#{$prefix}--table-expand { + border-block-end-color: transparent; + } +} + +:host(#{$prefix}-table-row[expandable][expanded][selected]), +:host(#{$prefix}-table-row[selection-name][expandable][expanded][selected]) { + ::slotted(#{$prefix}-table-cell), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + background-color: $layer-selected; + border-block-end-color: $border-subtle; + border-block-start-color: $layer-active; + } +} + +:host(#{$prefix}-table-row[expandable][expanded][selected][highlighted]), +:host( + #{$prefix}-table-row[selection-name][expandable][expanded][selected][highlighted] + ), +:host(#{$prefix}-table-row[expandable][expanded][selected]:hover), +:host( + #{$prefix}-table-row[selection-name][expandable][expanded][selected]:hover + ) { + ::slotted(#{$prefix}-table-cell), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + background-color: $layer-selected-hover; + } +} + +:host(#{$prefix}-table-row[expandable][selected]), +:host(#{$prefix}-table-row[selection-name][expandable][selected]) { + ::slotted(#{$prefix}-table-cell), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + border-block-end-color: $border-subtle; + } +} + +:host(#{$prefix}-table-row[expandable][highlighted]), +:host(#{$prefix}-table-row[selection-name][expandable][highlighted]), +:host(#{$prefix}-table-row[expandable]:hover), +:host(#{$prefix}-table-row[selection-name][expandable]:hover) { + &:not([slug]) { + ::slotted(#{$prefix}-table-cell), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + border-block-end-color: $border-subtle; + } + } +} + +:host(#{$prefix}-table-row[odd]) { + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox, + ::slotted(#{$prefix}-table-cell), + ::slotted(#{$prefix}-table-cell-skeleton) { + border-block-end: 1px solid $layer-01; + } +} + +:host(#{$prefix}-table-row[even]) { + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox, + ::slotted(#{$prefix}-table-cell), + ::slotted(#{$prefix}-table-cell-skeleton) { + background-color: $layer-accent-01; + border-block-end: 1px solid $layer-accent-01; + } +} + +:host(#{$prefix}-table-row[highlighted]), +:host(#{$prefix}-table-row:hover), +:host(#{$prefix}-table-expand-row:hover) { + ::slotted(#{$prefix}-table-cell), + ::slotted(#{$prefix}-table-cell-skeleton), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + background-color: $background-hover; + border-block-end-color: $layer-hover-01; + border-block-start-color: $layer-hover-01; + color: $text-primary; + } +} + +:host(#{$prefix}-table-row[highlighted]), +:host(#{$prefix}-table-row[even]:hover), +:host(#{$prefix}-table-row[odd]:hover) { + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox, + ::slotted(#{$prefix}-table-cell), + ::slotted(#{$prefix}-table-cell-skeleton) { + background-color: $background-hover; + border-block-end: 1px solid $layer-hover-01; + } +} + +//aligns selection and expansion with slug +:host(#{$prefix}-table-row[rows-with-slug]) { + #{$prefix}-checkbox, + #{$prefix}-radio-button { + padding-inline-start: 2rem; + } + + .#{$prefix}--table-expand { + padding-inline-start: $spacing-05; + } + + .#{$prefix}--table-expand__button { + margin-inline-start: $spacing-06; + } +} + +:host(#{$prefix}-table-row[rows-with-slug][slug]) { + #{$prefix}-checkbox, + #{$prefix}-radio-button { + padding-inline-start: $spacing-05; + } + + .#{$prefix}--table-expand__button { + margin-inline-start: $spacing-03; + } +} + +// alighs header with selection and expansion items +:host(#{$prefix}-table-header-row[rows-with-slug]) { + .#{$prefix}--table-expand { + padding-inline-start: $spacing-08; + } + .#{$prefix}--table-column-checkbox { + padding-inline-start: $spacing-09; + } +} + +:host(#{$prefix}-table-header-row[rows-with-slug][selection-name][expandable]), +:host(#{$prefix}-table-row[rows-with-slug][selection-name][expandable]) { + .#{$prefix}--table-column-checkbox { + padding-inline-start: 0; + } + #{$prefix}-checkbox { + padding-inline-start: $spacing-03; + } +} + +:host(#{$prefix}-table-row[slug]) { + @include ai-table-gradient(); + + background-attachment: fixed; + box-shadow: inset 1px 0 $ai-border-strong; + + &:hover { + @include ai-table-gradient('hover'); + + background-attachment: fixed; + } +} + +:host(#{$prefix}-table-header-title) { + @extend .#{$prefix}--data-table-header__title; + + display: block; +} + +:host(#{$prefix}-table-header-description) { + @extend .#{$prefix}--data-table-header__description; + + display: block; + + @include breakpoint(md) { + max-inline-size: 50ch; + } + + @include breakpoint(lg) { + max-inline-size: 80ch; + } +} diff --git a/packages/web-components/src/components/data-table/_table-expandable.scss b/packages/web-components/src/components/data-table/_table-expandable.scss new file mode 100644 index 000000000000..cd6677e981b7 --- /dev/null +++ b/packages/web-components/src/components/data-table/_table-expandable.scss @@ -0,0 +1,116 @@ +// +// Copyright IBM Corp. 2020, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +:host(#{$prefix}-table-expanded-row) { + display: table-row; + block-size: 0; + transition: height $duration-moderate-01 motion(standard); + + ::slotted(*) { + color: $text-secondary; + } + @media screen and (prefers-reduced-motion: reduce) { + td { + padding: 0; + border-block-end-color: $border-subtle; + padding-inline-start: $spacing-10; + transition: none; + vertical-align: middle; + + .#{$prefix}--child-row-inner-container { + overflow: hidden; + block-size: 0; + } + } + } + + td { + padding: 0; + border-block-end-color: $border-subtle; + padding-inline-start: $spacing-10; + transition: all $duration-fast-02 motion(standard, productive); + vertical-align: middle; + + .#{$prefix}--child-row-inner-container { + overflow: hidden; + block-size: 0; + } + } +} + +:host(#{$prefix}-table-expanded-row[expanded]) { + block-size: $spacing-09; + + td { + block-size: auto; + border-block-end: 1px solid $border-subtle; + + .#{$prefix}--child-row-inner-container { + block-size: auto; + } + } +} + +:host(#{$prefix}-table-expanded-row:hover), +:host(#{$prefix}-table-expanded-row[selected]), +:host(#{$prefix}-table-expanded-row[highlighted]) { + background-color: $background-hover; + + ::slotted(*) { + color: $text-primary; + } +} + +:host(#{$prefix}-table-expanded-row[selected][highlighted]) { + background-color: $layer-selected; +} + +:host(#{$prefix}-table-row[slug][expandable][selection-name][selected]), +:host(#{$prefix}-table-row[slug][expandable]) { + &:hover, + &[highlighted] { + @include ai-table-gradient('hover'); + + background-attachment: fixed; + + ::slotted(#{$prefix}-table-cell), + ::slotted(#{$prefix}-table-cell-skeleton), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + background: none; + } + + &[expanded] .#{$prefix}--table-expand { + border-block-end-color: transparent; + } + } + + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox, + ::slotted(#{$prefix}-table-cell), + ::slotted(#{$prefix}-table-cell-skeleton) { + background: none; + } + + &[expanded] .#{$prefix}--table-expand { + border-block-end-color: transparent; + } +} + +:host(#{$prefix}-table-expanded-row[slug]) { + @include ai-table-gradient(); + + &[highlighted] { + @include ai-table-gradient('hover'); + } +} + +:host(#{$prefix}-table-expanded-row[rows-with-slug]) { + td { + padding-inline-start: to-rem(88px); + } +} diff --git a/packages/web-components/src/components/data-table/_table-selection.scss b/packages/web-components/src/components/data-table/_table-selection.scss new file mode 100644 index 000000000000..5558ff63faac --- /dev/null +++ b/packages/web-components/src/components/data-table/_table-selection.scss @@ -0,0 +1,102 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +// +// Selection check box +// +:host(#{$prefix}-table-header-row) { + .#{$prefix}--table-column-checkbox { + border-block-end: none; + border-block-start: none; + padding-inline: $spacing-05 $spacing-02; + transition: background-color $duration-fast-01 motion(entrance, productive); + + .#{$prefix}--checkbox-label { + inline-size: 20px; + } + } +} + +:host(#{$prefix}-table-row) { + .#{$prefix}--table-column-checkbox { + border-block-end: 1px solid $border-subtle; + padding-inline: $spacing-05 $spacing-02; + + .#{$prefix}--checkbox-label { + padding-inline-start: $spacing-05; + } + } +} + +:host(#{$prefix}-table-row:hover) { + .#{$prefix}--table-column-checkbox { + background-color: $background-hover; + border-block-end-color: $layer-hover-01; + border-block-start-color: $layer-hover-01; + } +} + +:host(#{$prefix}-table-row[selected]) { + /* stylelint-disable-next-line no-duplicate-selectors */ + .#{$prefix}--table-column-checkbox, + ::slotted(#{$prefix}-table-cell), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + background-color: $layer-accent-01; + // bottom border acts as separator from other rows + border-block-end: 1px solid $layer-active; + color: $text-primary; + } + + &:hover { + /* stylelint-disable-next-line no-duplicate-selectors */ + .#{$prefix}--table-column-checkbox, + ::slotted(#{$prefix}-table-cell), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + background-color: $data-table-column-hover; + border-block-end-color: $data-table-column-hover; + } + } +} + +:host(#{$prefix}-table-expanded-row[filtered]), +:host(#{$prefix}-table-row[filtered]) { + /* stylelint-disable-next-line declaration-no-important */ + display: none !important; +} + +:host(#{$prefix}-table-expanded-row[selected][slug]:not([highlighted])), +:host(#{$prefix}-table-row[selected][slug]), +:host(#{$prefix}-table-row[expandable][selected][slug]) { + @include ai-table-gradient('selected'); + + background-attachment: fixed; + + &[highlighted], + &:hover { + @include ai-table-gradient('hover'); + + background-attachment: fixed; + + /* stylelint-disable-next-line no-duplicate-selectors */ + .#{$prefix}--table-column-checkbox, + ::slotted(#{$prefix}-table-cell), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + background: none; + } + } + + /* stylelint-disable-next-line no-duplicate-selectors */ + .#{$prefix}--table-column-checkbox, + ::slotted(#{$prefix}-table-cell), + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + background: none; + } +} diff --git a/packages/web-components/src/components/data-table/_table-sizes.scss b/packages/web-components/src/components/data-table/_table-sizes.scss new file mode 100644 index 000000000000..a4fa842b9bdf --- /dev/null +++ b/packages/web-components/src/components/data-table/_table-sizes.scss @@ -0,0 +1,218 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +// +// "xs" table size variant +// + +:host(#{$prefix}-table-head) ::slotted(#{$prefix}-table-header-row[size='xs']), +:host(#{$prefix}-table-body) ::slotted(#{$prefix}-table-row[size='xs']) { + block-size: $spacing-06; +} + +:host(#{$prefix}-table-header-row[size='xs']), +:host(#{$prefix}-table-row[size='xs']) { + ::slotted(#{$prefix}-table-header-cell) { + block-size: $spacing-06; + } + + ::slotted(#{$prefix}-table-cell) { + padding-block: $spacing-01; + padding-inline-start: $spacing-05; + } + + .#{$prefix}--table-expand { + block-size: $spacing-06; + padding-block: 0; + } +} + +// +// "sm" table size variant +// + +:host(#{$prefix}-table-head) ::slotted(#{$prefix}-table-header-row[size='sm']), +:host(#{$prefix}-table-body) ::slotted(#{$prefix}-table-row[size='sm']) { + block-size: $spacing-07; +} + +:host(#{$prefix}-table-header-row[size='sm']), +:host(#{$prefix}-table-row[size='sm']) { + ::slotted(#{$prefix}-table-header-cell) { + block-size: $spacing-07; + } + + ::slotted(#{$prefix}-table-cell) { + padding-block: rem(7px) rem(6px); + padding-inline-start: $spacing-05; + } + + .#{$prefix}--table-expand { + padding-block: 0; + } + + ::slotted(#{$prefix}-overflow-menu) { + block-size: $spacing-07; + } +} + +// +// "md" table size variant +// + +:host(#{$prefix}-table-head) ::slotted(#{$prefix}-table-header-row[size='md']), +:host(#{$prefix}-table-body) ::slotted(#{$prefix}-table-row[size='md']) { + block-size: $spacing-08; +} + +:host(#{$prefix}-table-row[size='md']), +:host(#{$prefix}-table-header-row[size='md']) { + ::slotted(#{$prefix}-table-header-cell) { + block-size: $spacing-08; + } + ::slotted(#{$prefix}-table-cell) { + padding-block: rem(7px) rem(6px); + padding-inline-start: $spacing-05; + } + + .#{$prefix}--table-expand { + padding-block: $spacing-02; + } + + ::slotted(#{$prefix}-overflow-menu) { + block-size: $spacing-08; + } +} + +// +// "lg" table size variant - default +// + +:host(#{$prefix}-table-head) ::slotted(#{$prefix}-table-header-row[size='lg']), +:host(#{$prefix}-table-body) ::slotted(#{$prefix}-table-row[size='lg']) { + block-size: $spacing-09; +} + +// +// "xl" table size variant +// + +:host(#{$prefix}-table-head) ::slotted(#{$prefix}-table-header-row[size='xl']), +:host(#{$prefix}-table-body) ::slotted(#{$prefix}-table-row[size='xl']) { + block-size: $spacing-10; +} + +:host(#{$prefix}-table-header-row[size='xl']) { + ::slotted(#{$prefix}-table-header-cell) { + padding-block-start: $spacing-05; + vertical-align: top; + } +} + +:host(#{$prefix}-table-header-row[size='xl']), +:host(#{$prefix}-table-row[size='xl']) { + ::slotted(#{$prefix}-table-cell) { + padding-block-start: $spacing-05; + } + + .#{$prefix}--table-expand { + padding-block-end: 1.375rem; + } + + .#{$prefix}--table-expand, + .#{$prefix}--table-column-checkbox { + padding-block-start: rem(10px); + vertical-align: top; + } + + &[radio] { + .#{$prefix}--table-column-checkbox { + padding-block-start: $spacing-05; + } + } +} + +:host(#{$prefix}-table-expanded-row[size='xl'][expanded]) { + td { + padding-block: $spacing-05 $spacing-03; + padding-inline-end: $spacing-05; + } +} + +// Small persistent toolbar +:host(#{$prefix}-table-toolbar[size='xs']), +:host(#{$prefix}-table-toolbar-content[size='xs']) { + &, + ::slotted(#{$prefix}-table-toolbar-search), + ::slotted(#{$prefix}-overflow-menu), + ::slotted(#{$prefix}-button) { + block-size: $spacing-07; + min-block-size: $spacing-07; + } + ::slotted(#{$prefix}-table-toolbar-search), + ::slotted(#{$prefix}-overflow-menu) { + inline-size: $spacing-07; + } +} + +:host(#{$prefix}-table-toolbar[size='sm']), +:host(#{$prefix}-table-toolbar-content[size='sm']) { + &, + ::slotted(#{$prefix}-table-toolbar-search), + ::slotted(#{$prefix}-overflow-menu), + ::slotted(#{$prefix}-button) { + block-size: $spacing-07; + min-block-size: $spacing-07; + } + + ::slotted(#{$prefix}-table-toolbar-search), + ::slotted(#{$prefix}-overflow-menu) { + inline-size: $spacing-07; + } +} + +// +// "selection" and "expandable" sizes +// + +:host(#{$prefix}-table-header-row[selection-name][expandable][size='xs']), +:host(#{$prefix}-table-row[selection-name][expandable][size='xs']) { + .#{$prefix}--table-column-checkbox { + padding: 0 rem(6px); + } +} + +:host(#{$prefix}-table-header-row[selection-name][expandable][size='sm']), +:host(#{$prefix}-table-row[selection-name][expandable][size='sm']), +:host(#{$prefix}-table-header-row[selection-name][expandable][size='md']), +:host(#{$prefix}-table-row[selection-name][expandable][size='md']) { + .#{$prefix}--table-column-checkbox { + padding: rem(3px) rem(6px); + } +} + +:host(#{$prefix}-table-header-row[selection-name][expandable][size='xl']) { + .#{$prefix}--table-column-checkbox { + padding-inline: rem(6px); + } +} + +// +// table cell size for overflow menu +// +:host(#{$prefix}-table-cell[size='xs']), +:host(#{$prefix}-table-cell[size='sm']) { + ::slotted(#{$prefix}-overflow-menu) { + block-size: calc(100% + 1px); + } +} + +:host(#{$prefix}-table-cell[size='md']) { + ::slotted(#{$prefix}-overflow-menu) { + block-size: $spacing-08; + } +} diff --git a/packages/web-components/src/components/data-table/_table-sort.scss b/packages/web-components/src/components/data-table/_table-sort.scss new file mode 100644 index 000000000000..374156490b32 --- /dev/null +++ b/packages/web-components/src/components/data-table/_table-sort.scss @@ -0,0 +1,70 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/components/data-table/sort'; + +// Padding of header cell for sorting +// +// Let sort button rather than the cell define the padding +// Ensure sort button takes 100% of the cell, by setting the same height as the parent row + +:host(#{$prefix}-table-header-row) + ::slotted(#{$prefix}-table-header-cell[sort-direction]) { + block-size: $spacing-09; + padding-inline: 0; +} + +:host(#{$prefix}-table-header-cell[sort-direction]:first-of-type) + .#{$prefix}--table-sort { + padding-inline-start: $spacing-05; +} + +:host(#{$prefix}-table-header-cell[sort-direction][expandable][selection-name]) + .#{$prefix}--table-sort { + padding-inline-start: 0; +} + +// +// Sort icon style +// + +// Show sort icon of primary sorting column or one of hovered column +:host(#{$prefix}-table-header-cell[sort-active]) + .#{$prefix}--table-sort + .#{$prefix}--table-sort__icon, +:host(#{$prefix}-table-header-cell) + .#{$prefix}--table-sort:hover + .#{$prefix}--table-sort__icon { + opacity: 1; +} + +// `carbon-web-components` uses conditional rendering for choosing Arrows16 vs. ArrowDown16, +// and thus `display:none` here is not needed +:host(#{$prefix}-table-header-cell[sort-direction]) + .#{$prefix}--table-sort + .#{$prefix}--table-sort__icon { + display: block; +} + +:host(#{$prefix}-table-header-cell[sort-direction='ascending']) + .#{$prefix}--table-sort__icon { + transform: rotate(180deg); +} + +// places slug near sorting icon in header +:host(#{$prefix}-table-header-cell[sort-direction][slug]) { + .#{$prefix}--table-sort__icon-unsorted, + .#{$prefix}--table-sort__icon { + margin-inline: auto $spacing-03; + } + + ::slotted(#{$prefix}-slug) { + margin-inline-end: $spacing-03; + } +} diff --git a/packages/web-components/src/components/data-table/core-library-style-questions.md b/packages/web-components/src/components/data-table/core-library-style-questions.md new file mode 100644 index 000000000000..67b43b161178 --- /dev/null +++ b/packages/web-components/src/components/data-table/core-library-style-questions.md @@ -0,0 +1,6 @@ +- `` in addition to `` setting `background-color`: + https://github.com/carbon-design-system/carbon/blob/v10.3.0/packages/components/src/components/data-table/_data-table-core.scss#L74-L76 +- Re-definition of text color and border width/style for selected and hovered + ``s: + - https://github.com/carbon-design-system/carbon/blob/v10.3.0/packages/components/src/components/data-table/_data-table-core.scss#L78-L83 + - https://github.com/carbon-design-system/carbon/blob/v10.3.0/packages/components/src/components/data-table/_data-table-core.scss#L304-L314 diff --git a/packages/web-components/src/components/data-table/data-table.scss b/packages/web-components/src/components/data-table/data-table.scss new file mode 100644 index 000000000000..43df227037ab --- /dev/null +++ b/packages/web-components/src/components/data-table/data-table.scss @@ -0,0 +1,32 @@ +// +// Copyright IBM Corp. 2019, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/breakpoint' as *; +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/type' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/motion' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/utilities/ai-gradient' as *; +@use '@carbon/styles/scss/components/checkbox'; + +@use '@carbon/styles/scss/components/data-table' as *; +@use '@carbon/styles/scss/components/link' as *; + +@use '@carbon/styles/scss/components/data-table/expandable'; +@use '@carbon/styles/scss/components/data-table/skeleton'; + +// TODO: deprecate @import +@import 'table-action'; +@import 'table-core'; +@import 'table-expandable'; +@import 'table-sizes'; +@import 'table-selection'; +@import 'table-sort'; diff --git a/packages/web-components/src/components/data-table/defs.ts b/packages/web-components/src/components/data-table/defs.ts new file mode 100644 index 000000000000..eafe16dfec7f --- /dev/null +++ b/packages/web-components/src/components/data-table/defs.ts @@ -0,0 +1,92 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Table size. + */ +export enum TABLE_SIZE { + /** + * xs size. + */ + XS = 'xs', + + /** + * sm size. + */ + SM = 'sm', + + /** + * md size. + */ + MD = 'md', + + /** + * lg size - default. + */ + LG = 'lg', + + /** + * xl size. + */ + XL = 'xl', +} + +/** + * Table sort state. + */ +export enum TABLE_SORT_DIRECTION { + /** + * Not sorted. + */ + NONE = 'none', + + /** + * Sorted ascendingly. + */ + ASCENDING = 'ascending', + + /** + * Sorted descendingly. + */ + DESCENDING = 'descending', +} + +/** + * Table sort cycle. + */ +export enum TABLE_SORT_CYCLE { + BI_STATES_FROM_ASCENDING = 'bi-states-from-ascending', + BI_STATES_FROM_DESCENDING = 'bi-states-from-descending', + TRI_STATES_FROM_ASCENDING = 'tri-states-from-ascending', + TRI_STATES_FROM_DESCENDING = 'tri-states-from-descending', +} + +/** + * Mapping of table sort cycles to table sort states. + */ +export const TABLE_SORT_CYCLES = { + [TABLE_SORT_CYCLE.BI_STATES_FROM_ASCENDING]: [ + TABLE_SORT_DIRECTION.ASCENDING, + TABLE_SORT_DIRECTION.DESCENDING, + ], + [TABLE_SORT_CYCLE.BI_STATES_FROM_DESCENDING]: [ + TABLE_SORT_DIRECTION.DESCENDING, + TABLE_SORT_DIRECTION.ASCENDING, + ], + [TABLE_SORT_CYCLE.TRI_STATES_FROM_ASCENDING]: [ + TABLE_SORT_DIRECTION.NONE, + TABLE_SORT_DIRECTION.ASCENDING, + TABLE_SORT_DIRECTION.DESCENDING, + ], + [TABLE_SORT_CYCLE.TRI_STATES_FROM_DESCENDING]: [ + TABLE_SORT_DIRECTION.NONE, + TABLE_SORT_DIRECTION.DESCENDING, + TABLE_SORT_DIRECTION.ASCENDING, + ], +}; diff --git a/packages/web-components/src/components/data-table/docs/overview.mdx b/packages/web-components/src/components/data-table/docs/overview.mdx new file mode 100644 index 000000000000..2a64b22b3cfa --- /dev/null +++ b/packages/web-components/src/components/data-table/docs/overview.mdx @@ -0,0 +1,24 @@ +## Live demo + + diff --git a/packages/web-components/src/components/data-table/index.ts b/packages/web-components/src/components/data-table/index.ts new file mode 100644 index 000000000000..2ae4b0fa80b4 --- /dev/null +++ b/packages/web-components/src/components/data-table/index.ts @@ -0,0 +1,26 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './table'; +import './table-skeleton'; +import './table-header-title'; +import './table-header-description'; +import './table-batch-actions'; +import './table-body'; +import './table-cell'; +import './table-cell-content'; +import './table-expanded-row'; +import './table-head'; +import './table-header-cell'; +import './table-header-row'; +import './table-row'; +import './table-skeleton'; +import './table-toolbar'; +import './table-toolbar-content'; +import './table-toolbar-search'; diff --git a/packages/web-components/src/components/data-table/stories/data-table-basic.stories.ts b/packages/web-components/src/components/data-table/stories/data-table-basic.stories.ts new file mode 100644 index 000000000000..8ff372e69f84 --- /dev/null +++ b/packages/web-components/src/components/data-table/stories/data-table-basic.stories.ts @@ -0,0 +1,287 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { TABLE_SIZE } from '../table'; +import '../index'; +import storyDocs from './data-table.mdx'; + +const sizes = { + [`xs (${TABLE_SIZE.XS})`]: TABLE_SIZE.XS, + [`sm (${TABLE_SIZE.SM})`]: TABLE_SIZE.SM, + [`md (${TABLE_SIZE.MD})`]: TABLE_SIZE.MD, + [`lg (${TABLE_SIZE.LG} - default)`]: TABLE_SIZE.LG, + [`xl (${TABLE_SIZE.XL})`]: TABLE_SIZE.XL, +}; + +const defaultArgs = { + locale: 'en', + size: TABLE_SIZE.LG, + useStaticWidth: false, + useZebraStyles: false, +}; + +const controls = { + locale: { + control: 'text', + description: 'Provide a string for the current locale.', + }, + size: { + control: 'radio', + description: 'Change the row height of table.', + options: sizes, + }, + useStaticWidth: { + control: 'boolean', + description: 'Use static width.', + }, + useZebraStyles: { + control: 'boolean', + description: 'Use zebra styles.', + }, +}; + +export const Default = { + render: () => html` + + + + Name + Rule + Status + Other + Example + + + + + Load Balancer 1 + Round robin + Starting + Test + 22 + + + Load Balancer 2 + DNS delegation + Active + Test + 22 + + + Load Balancer 3 + Round robin + Disabled + Test + 22 + + + Load Balancer 4 + Round robin + Disabled + Test + 22 + + + Load Balancer 5 + Round robin + Disabled + Test + 22 + + + Load Balancer 6 + Round robin + Disabled + Test + 22 + + + Load Balancer 7 + Round robin + Disabled + Test + 22 + + + + `, +}; + +export const XLWithTwoLines = { + render: () => html` + + + + Name + Rule + Status + Other + Example + + + + + + Load Balancer 1 + Austin, Tx + + Round robin + Starting + Test + 22 + + + + Load Balancer 2 + Austin, Tx + + DNS delegation + Active + Test + 22 + + + + Load Balancer 3 + Austin, Tx + + Round robin + Disabled + Test + 22 + + + + Load Balancer 4 + Austin, Tx + + Round robin + Disabled + Test + 22 + + + + Load Balancer 5 + Austin, Tx + + Round robin + Disabled + Test + 22 + + + + Load Balancer 6 + Austin, Tx + + Round robin + Disabled + Test + 22 + + + + Load Balancer 7 + Austin, Tx + + Round robin + Disabled + Test + 22 + + + + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ locale, size, useStaticWidth, useZebraStyles }) => html` + + + + Name + Rule + Status + Other + Example + + + + + Load Balancer 1 + Round robin + Starting + Test + 22 + + + Load Balancer 2 + DNS delegation + Active + Test + 22 + + + Load Balancer 3 + Round robin + Disabled + Test + 22 + + + Load Balancer 4 + Round robin + Disabled + Test + 22 + + + Load Balancer 5 + Round robin + Disabled + Test + 22 + + + Load Balancer 6 + Round robin + Disabled + Test + 22 + + + Load Balancer 7 + Round robin + Disabled + Test + 22 + + + + `, +}; + +const meta = { + title: 'Components/DataTable/Basic', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/data-table/stories/data-table-batch-actions.stories.ts b/packages/web-components/src/components/data-table/stories/data-table-batch-actions.stories.ts new file mode 100644 index 000000000000..38c9c928c3ad --- /dev/null +++ b/packages/web-components/src/components/data-table/stories/data-table-batch-actions.stories.ts @@ -0,0 +1,319 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../../globals/settings'; +import { TABLE_SIZE } from '../table'; +import Add from '@carbon/icons/lib/add/16'; +import Save from '@carbon/icons/lib/save/16'; +import TrashCan from '@carbon/icons/lib/trash-can/16'; +// @ts-ignore +import Download16 from '@carbon/icons/lib/download/16'; +// @ts-ignore +import Settings16 from '@carbon/icons/lib/settings/16'; +import '../../overflow-menu'; +import '../index'; +import storyDocs from './data-table.mdx'; + +const sizes = { + [`xs (${TABLE_SIZE.XS})`]: TABLE_SIZE.XS, + [`sm (${TABLE_SIZE.SM})`]: TABLE_SIZE.SM, + [`md (${TABLE_SIZE.MD})`]: TABLE_SIZE.MD, + [`lg (${TABLE_SIZE.LG} - default)`]: TABLE_SIZE.LG, + [`xl (${TABLE_SIZE.XL})`]: TABLE_SIZE.XL, +}; + +const defaultArgs = { + isSortable: false, + locale: 'en', + radio: false, + size: TABLE_SIZE.LG, + useStaticWidth: false, + useZebraStyles: false, +}; + +const controls = { + isSortable: { + control: 'boolean', + description: 'Is sortable', + }, + locale: { + control: 'text', + description: 'Locale', + }, + radio: { + control: 'boolean', + description: 'Radio', + }, + size: { + control: 'radio', + description: 'Size', + options: sizes, + }, + useStaticWidth: { + control: 'boolean', + description: 'Use static width', + }, + useZebraStyles: { + control: 'boolean', + description: 'Use zebra styles', + }, +}; + +export const Default = { + render: () => html` + + DataTable + With batch actions. Lorem ipsum dolor sit amet, consectetur adipiscing + elit. Maecenas accumsan mauris sed congue egestas. Integer varius mauris + vel arcu pulvinar bibendum non sit amet ligula. Nullam ut nisi eu tellus + aliquet vestibulum vel sit amet odio. + + + + Delete ${TrashCan({ slot: 'icon' })} + ${Add({ slot: 'icon' })} + ${Save({ slot: 'icon' })} + + Download ${Download16({ slot: 'icon' })} + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + alert('Alert 1')}> + Action 1 + + alert('Alert 2')}> + Action 2 + + alert('Alert 3')}> + Action 3 + + + + Add new + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + + Starting + + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +export const Playground = { + args: defaultArgs, + argsType: controls, + render: ({ + isSortable, + locale, + radio, + size, + useStaticWidth, + useZebraStyles, + }) => html` + + DataTable + With batch actions. + + + + Delete ${TrashCan({ slot: 'icon' })} + Save ${Save({ slot: 'icon' })} + + Download ${Download16({ slot: 'icon' })} + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + alert('Alert 1')}> + Action 1 + + alert('Alert 2')}> + Action 2 + + alert('Alert 3')}> + Action 3 + + + + Add new + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +const meta = { + title: 'Components/DataTable/Batch Actions', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/data-table/stories/data-table-dynamic.stories.ts b/packages/web-components/src/components/data-table/stories/data-table-dynamic.stories.ts new file mode 100644 index 000000000000..96d3e746cea5 --- /dev/null +++ b/packages/web-components/src/components/data-table/stories/data-table-dynamic.stories.ts @@ -0,0 +1,394 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../../globals/settings'; +import { TABLE_SIZE } from '../table'; +import Add from '@carbon/icons/lib/add/16'; +import Save from '@carbon/icons/lib/save/16'; +import TrashCan from '@carbon/icons/lib/trash-can/16'; +// @ts-ignore +import Download16 from '@carbon/icons/lib/download/16'; +// @ts-ignore +import Settings16 from '@carbon/icons/lib/settings/16'; +import '../index'; +import storyDocs from './data-table.mdx'; + +const sizes = { + [`xs (${TABLE_SIZE.XS})`]: TABLE_SIZE.XS, + [`sm (${TABLE_SIZE.SM})`]: TABLE_SIZE.SM, + [`md (${TABLE_SIZE.MD})`]: TABLE_SIZE.MD, + [`lg (${TABLE_SIZE.LG} - default)`]: TABLE_SIZE.LG, + [`xl (${TABLE_SIZE.XL})`]: TABLE_SIZE.XL, +}; + +const defaultArgs = { + isSortable: false, + locale: 'en', + radio: false, + size: TABLE_SIZE.LG, + useStaticWidth: false, + useZebraStyles: false, +}; + +const controls = { + isSortable: { + control: 'boolean', + description: 'Is sortable', + }, + locale: { + control: 'text', + description: 'Locale', + }, + radio: { + control: 'boolean', + description: 'Radio', + }, + size: { + control: 'radio', + description: 'Size', + options: sizes, + }, + useStaticWidth: { + control: 'boolean', + description: 'Use static width', + }, + useZebraStyles: { + control: 'boolean', + description: 'Use zebra styles', + }, +}; + +let headerCount = 6; +let rowCount = 1; + +const insertInRandomPosition = (array, element) => { + const index = Math.floor(Math.random() * (array.length + 1)); + return [...array.slice(0, index), element, ...array.slice(index)]; +}; + +const addRow = () => { + const newRow = document.createElement('cds-table-row'); + + const templateRow = { + name: `New Row ${rowCount}`, + protocol: 'HTTP', + port: rowCount * 100, + rule: rowCount % 2 === 0 ? 'Round robin' : 'DNS delegation', + attached_groups: `Row ${rowCount}'s VM Groups`, + status: 'Starting', + }; + + for (const key in templateRow) { + if (Object.prototype.hasOwnProperty.call(templateRow, key)) { + const cell = document.createElement('cds-table-cell'); + cell.textContent = templateRow[key]; + newRow.appendChild(cell); + } + } + + const rows = document.querySelectorAll('cds-table-row'); + const diff = headerCount - Object.keys(templateRow).length; + + [...Array(diff)].forEach(() => { + const newCell = document.createElement('cds-table-cell'); + newCell.textContent = `Header ${headerCount - 1}`; + newRow.appendChild(newCell); + }); + + newRow.setAttribute('selection-name', `${rows.length}`); + + const updatedRows = insertInRandomPosition([...rows], newRow); + updatedRows.forEach((e) => { + document.querySelector('cds-table-body')!.insertBefore(e, null); + }); + + rowCount++; +}; + +const addHeader = () => { + const headerRow = document.querySelector('cds-table-header-row'); + const newHeader = document.createElement('cds-table-header-cell'); + newHeader.textContent = `Header ${headerCount}`; + headerRow?.appendChild(newHeader); + + const rows = document.querySelectorAll('cds-table-row'); + rows.forEach((e) => { + const newCell = document.createElement('cds-table-cell'); + newCell.textContent = `Header ${headerCount}`; + e.appendChild(newCell); + }); + headerCount++; +}; + +export const Default = { + render: () => html` + + DataTable + Use the toolbar menu to add rows and + headers + + + + ${Add({ slot: 'icon' })} + ${Save({ slot: 'icon' })} + ${Save({ slot: 'icon' })} + + Download ${Download16({ slot: 'icon' })} + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + Add row + Add header + + + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ + isSortable, + locale, + radio, + size, + useStaticWidth, + useZebraStyles, + }) => html` + + DataTable + Use the toolbar menu to add rows and + headers + + + + Delete ${TrashCan({ slot: 'icon' })} + Save ${Save({ slot: 'icon' })} + + Download ${Download16({ slot: 'icon' })} + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + Add row + Add header + + + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + +
    Expandable row content
    +
    Description here
    +
    +
    +
    + `, +}; + +const meta = { + title: 'Components/DataTable/Dynamic', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/data-table/stories/data-table-expansion.stories.ts b/packages/web-components/src/components/data-table/stories/data-table-expansion.stories.ts new file mode 100644 index 000000000000..196afe42a666 --- /dev/null +++ b/packages/web-components/src/components/data-table/stories/data-table-expansion.stories.ts @@ -0,0 +1,378 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { TABLE_SIZE } from '../table'; +import '../index'; +import storyDocs from './data-table.mdx'; + +const sizes = { + [`xs (${TABLE_SIZE.XS})`]: TABLE_SIZE.XS, + [`sm (${TABLE_SIZE.SM})`]: TABLE_SIZE.SM, + [`md (${TABLE_SIZE.MD})`]: TABLE_SIZE.MD, + [`lg (${TABLE_SIZE.LG} - default)`]: TABLE_SIZE.LG, + [`xl (${TABLE_SIZE.XL})`]: TABLE_SIZE.XL, +}; + +const defaultArgs = { + isSortable: false, + locale: 'en', + size: TABLE_SIZE.LG, + useStaticWidth: false, + useZebraStyles: false, +}; + +const controls = { + isSortable: { + control: 'boolean', + description: 'Is sortable', + }, + locale: { + control: 'text', + description: 'Locale', + }, + size: { + control: 'radio', + description: 'Size', + options: sizes, + }, + useStaticWidth: { + control: 'boolean', + description: 'Use static width', + }, + useZebraStyles: { + control: 'boolean', + description: 'Use zebra styles', + }, +}; + +export const Default = { + render: () => html` + + DataTable + With expansion + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + +
    Expandable row content
    +
    Description here
    +
    +
    +
    + `, +}; + +export const BatchExpansion = { + render: () => html` + + DataTable + With expansion + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + +
    Expandable row content
    +
    Description here
    +
    +
    +
    + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ + isSortable, + locale, + size, + useStaticWidth, + useZebraStyles, + }) => html` + + DataTable + With expansion + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + +
    Expandable row content
    +
    Description here
    +
    +
    +
    + `, +}; + +const meta = { + title: 'Components/DataTable/Expansion', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/data-table/stories/data-table-filtering.stories.ts b/packages/web-components/src/components/data-table/stories/data-table-filtering.stories.ts new file mode 100644 index 000000000000..9db390bf1e96 --- /dev/null +++ b/packages/web-components/src/components/data-table/stories/data-table-filtering.stories.ts @@ -0,0 +1,272 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../../globals/settings'; +import { TABLE_SIZE } from '../table'; +// @ts-ignore +import Settings16 from '@carbon/icons/lib/settings/16'; +import '../index'; +import storyDocs from './data-table.mdx'; + +const sizes = { + [`xs (${TABLE_SIZE.XS})`]: TABLE_SIZE.XS, + [`sm (${TABLE_SIZE.SM})`]: TABLE_SIZE.SM, + [`md (${TABLE_SIZE.MD})`]: TABLE_SIZE.MD, + [`lg (${TABLE_SIZE.LG} - default)`]: TABLE_SIZE.LG, + [`xl (${TABLE_SIZE.XL})`]: TABLE_SIZE.XL, +}; + +const defaultArgs = { + isSortable: false, + locale: 'en', + size: TABLE_SIZE.LG, + useStaticWidth: false, + useZebraStyles: false, +}; + +const controls = { + isSortable: { + control: 'boolean', + description: 'Is sortable', + }, + locale: { + control: 'text', + description: 'Locale', + }, + size: { + control: 'radio', + description: 'Size', + options: sizes, + }, + useStaticWidth: { + control: 'boolean', + description: 'Use static width', + }, + useZebraStyles: { + control: 'boolean', + description: 'Use zebra styles', + }, +}; + +export const Default = { + render: () => html` + + DataTable + With filtering + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + Action 1 + Action 2 + Action 3 + + + Primary Button + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ + isSortable, + locale, + radio, + size, + useStaticWidth, + useZebraStyles, + }) => html` + + DataTable + With filtering + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + Action 1 + Action 2 + Action 3 + + + Primary Button + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +const meta = { + title: 'Components/DataTable/Filtering', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/data-table/stories/data-table-selection.stories.ts b/packages/web-components/src/components/data-table/stories/data-table-selection.stories.ts new file mode 100644 index 000000000000..610cc1fa9648 --- /dev/null +++ b/packages/web-components/src/components/data-table/stories/data-table-selection.stories.ts @@ -0,0 +1,388 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { TABLE_SIZE } from '../table'; +import '../index'; +import storyDocs from './data-table.mdx'; + +const sizes = { + [`xs (${TABLE_SIZE.XS})`]: TABLE_SIZE.XS, + [`sm (${TABLE_SIZE.SM})`]: TABLE_SIZE.SM, + [`md (${TABLE_SIZE.MD})`]: TABLE_SIZE.MD, + [`lg (${TABLE_SIZE.LG} - default)`]: TABLE_SIZE.LG, + [`xl (${TABLE_SIZE.XL})`]: TABLE_SIZE.XL, +}; + +const defaultArgs = { + isSortable: false, + locale: 'en', + radio: false, + size: TABLE_SIZE.LG, + useStaticWidth: false, + useZebraStyles: false, +}; + +const controls = { + isSortable: { + control: 'boolean', + description: 'Is sortable', + }, + locale: { + control: 'text', + description: 'Locale', + }, + radio: { + control: 'boolean', + description: 'Radio', + }, + size: { + control: 'radio', + description: 'Size', + options: sizes, + }, + useStaticWidth: { + control: 'boolean', + description: 'Use static width', + }, + useZebraStyles: { + control: 'boolean', + description: 'Use zebra styles', + }, +}; + +export const Default = { + render: () => html` + + DataTable + With selection + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +export const WithRadioSelection = { + render: () => html` + + DataTable + With selection + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +export const WithSelectionAndSorting = { + render: () => html` + + DataTable + With selection + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ + isSortable, + locale, + radio, + size, + useStaticWidth, + useZebraStyles, + }) => html` + + DataTable + With selection + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +const meta = { + title: 'Components/DataTable/Selection', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/data-table/stories/data-table-skeleton.stories.ts b/packages/web-components/src/components/data-table/stories/data-table-skeleton.stories.ts new file mode 100644 index 000000000000..20a9bc1e80be --- /dev/null +++ b/packages/web-components/src/components/data-table/stories/data-table-skeleton.stories.ts @@ -0,0 +1,88 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import storyDocs from './data-table.mdx'; +import '../index'; + +const headers = [ + 'Name', + 'Protocol', + 'Port', + 'Rule', + 'Attached groups', + 'Status', +]; + +const defaultArgs = { + compact: false, + columnCount: 5, + rowCount: 5, + showHeader: true, + showToolbar: true, + zebra: false, +}; + +const controls = { + compact: { + control: 'boolean', + description: 'Compact', + }, + columnCount: { + control: 'number', + description: 'Column count', + }, + rowCount: { + control: 'number', + description: 'Row count', + }, + showHeader: { + control: 'boolean', + description: 'Show header', + }, + showToolbar: { + control: 'boolean', + description: 'Show toolbar', + }, + zebra: { + control: 'boolean', + description: 'Use zebra styles', + }, +}; + +export const Default = { + render: () => + html` `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ columnCount, rowCount, showHeader, showToolbar, zebra }) => html` + + + `, +}; + +const meta = { + title: 'Components/DataTable/Skeleton', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/data-table/stories/data-table-sorting.stories.ts b/packages/web-components/src/components/data-table/stories/data-table-sorting.stories.ts new file mode 100644 index 000000000000..2f7bb9d1cd41 --- /dev/null +++ b/packages/web-components/src/components/data-table/stories/data-table-sorting.stories.ts @@ -0,0 +1,229 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { TABLE_SIZE } from '../table'; +import '../index'; +import storyDocs from './data-table.mdx'; + +const sizes = { + [`xs (${TABLE_SIZE.XS})`]: TABLE_SIZE.XS, + [`sm (${TABLE_SIZE.SM})`]: TABLE_SIZE.SM, + [`md (${TABLE_SIZE.MD})`]: TABLE_SIZE.MD, + [`lg (${TABLE_SIZE.LG} - default)`]: TABLE_SIZE.LG, + [`xl (${TABLE_SIZE.XL})`]: TABLE_SIZE.XL, +}; + +const defaultArgs = { + isSortable: true, + locale: 'en', + size: TABLE_SIZE.LG, + useStaticWidth: false, + useZebraStyles: false, +}; + +const controls = { + isSortable: { + control: 'boolean', + description: 'Is sortable', + }, + locale: { + control: 'text', + description: 'Locale', + }, + size: { + control: 'radio', + description: 'Size', + options: sizes, + }, + useStaticWidth: { + control: 'boolean', + description: 'Use static width', + }, + useZebraStyles: { + control: 'boolean', + description: 'Use zebra styles', + }, +}; + +export const Default = { + render: () => html` + + DataTable + With filtering + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ + isSortable, + locale, + size, + useStaticWidth, + useZebraStyles, + }) => html` + + DataTable + With filtering + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +const meta = { + title: 'Components/DataTable/Sorting', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/data-table/stories/data-table-toolbar.stories.ts b/packages/web-components/src/components/data-table/stories/data-table-toolbar.stories.ts new file mode 100644 index 000000000000..c1e58b74199a --- /dev/null +++ b/packages/web-components/src/components/data-table/stories/data-table-toolbar.stories.ts @@ -0,0 +1,738 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../../globals/settings'; +import { TABLE_SIZE } from '../table'; +import Settings16 from '@carbon/icons/lib/settings/16'; +import OverflowMenuVertical16 from '@carbon/icons/lib/overflow-menu--vertical/16'; +import storyDocs from './data-table.mdx'; +import '../index'; + +const sizes = { + [`xs (${TABLE_SIZE.XS})`]: TABLE_SIZE.XS, + [`sm (${TABLE_SIZE.SM})`]: TABLE_SIZE.SM, + [`md (${TABLE_SIZE.MD})`]: TABLE_SIZE.MD, + [`lg (${TABLE_SIZE.LG} - default)`]: TABLE_SIZE.LG, + [`xl (${TABLE_SIZE.XL})`]: TABLE_SIZE.XL, +}; + +const defaultArgs = { + isSortable: false, + locale: 'en', + overflowMenuOnHover: false, + radio: false, + size: TABLE_SIZE.LG, + useStaticWidth: false, + useZebraStyles: false, +}; + +const controls = { + isSortable: { + control: 'boolean', + description: 'Is sortable', + }, + locale: { + control: 'text', + description: 'Locale', + }, + overflowMenuOnHover: { + control: 'boolean', + description: 'Overflow menu on hover', + }, + radio: { + control: 'boolean', + description: 'Radio', + }, + size: { + control: 'select', + description: 'Size', + options: sizes, + }, + useStaticWidth: { + control: 'boolean', + description: 'Use static width', + }, + useZebraStyles: { + control: 'boolean', + description: 'Use zebra styles', + }, +}; + +export const Default = { + render: () => { + return html` + + DataTable + With toolbar + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + alert('Alert 1')}> + Action 1 + + alert('Alert 2')}> + Action 2 + + alert('Alert 3')}> + Action 3 + + + + Primary button + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `; + }, +}; + +export const PersistentToolbar = { + render: () => html` + + DataTable + With toolbar + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + alert('Alert 1')}> + Action 1 + + alert('Alert 2')}> + Action 2 + + alert('Alert 3')}> + Action 3 + + + + Primary button + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +export const SmallPersistentToolbar = { + render: () => html` + + DataTable + With toolbar + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + Action 1 + Action 2 + Action 3 + + + Primary Button + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + + `, +}; + +export const WithOverflowMenu = { + render: () => html` + + DataTable + With toolbar + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + alert('Alert 1')}> + Action 1 + + alert('Alert 2')}> + Action 2 + + alert('Alert 3')}> + Action 3 + + + + Primary button + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + + render: ({ + isSortable, + locale, + radio, + overflowMenuOnHover, + size, + useStaticWidth, + useZebraStyles, + }) => html` + + DataTable + With batch actions. + + + + + + ${Settings16({ + slot: 'icon', + class: `${prefix}--overflow-menu__icon`, + })} + + Action 1 + Action 2 + Action 3 + + + Primary button + + + + + + Name + Protocol + Port + Rule + Attached groups + Status + + + + + + Load Balancer 3 + HTTP + 3000 + Round robin + Kevin's VM Groups + Disabled + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + Load Balancer 1 + HTTP + 443 + Round robin + Maureen's VM Groups + Starting + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + Load Balancer 2 + HTTP + 80 + DNS delegation + Andrew's VM Groups + Active + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + Load Balancer 6 + HTTP + 3000 + Round robin + Marc's VM Groups + Disabled + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + Load Balancer 5 + HTTP + 80 + DNS delegation + Ronja's VM Groups + Active + + + ${OverflowMenuVertical16({ slot: 'icon' })} + Options + + + Stop app + Restart app + Rename + + + + + + + `, +}; + +const meta = { + title: 'Components/DataTable/Toolbar', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/data-table/stories/data-table.mdx b/packages/web-components/src/components/data-table/stories/data-table.mdx new file mode 100644 index 000000000000..def185765fdd --- /dev/null +++ b/packages/web-components/src/components/data-table/stories/data-table.mdx @@ -0,0 +1,603 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../../globals/internal/storybook-cdn'; + +# Data table + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/data-table) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/data-table) + +Data table in `@carbon/web-components` focuses on primitives that constructs +table UI, consisting of the following: + +| Tag | Description | HTML tag counterpart | +| ------------------------- | --------------- | -------------------- | +| `` | The container | N/A | +| `` | The table | `` | +| `` | The header | `` | +| `` | The header row | `` in `` | +| `` | The header cell | `` | +| `` | The header row | `` in `` | +| `` | The header cell | ` + `; + } + + updated() { + this.previousElementSibling?.hasAttribute('slug') + ? this.setAttribute('slug', '') + : this.removeAttribute('slug'); + } + + /** + * A selector that will return the previous sibling row. + */ + static get selectorRow() { + return `${prefix}-table-row`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSTableExpandedRow; diff --git a/packages/web-components/src/components/data-table/table-head.ts b/packages/web-components/src/components/data-table/table-head.ts new file mode 100644 index 000000000000..d938ccfd0b61 --- /dev/null +++ b/packages/web-components/src/components/data-table/table-head.ts @@ -0,0 +1,44 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Data table header. + * + * @element cds-table-head + */ +@customElement(`${prefix}-table-head`) +class CDSTableHead extends LitElement { + /** + * TODO: Uncomment when Carbon fully implements sticky header + * Specify whether the header should be sticky. + * Still experimental: may not work with every combination of table props + */ + //@property({ type: Boolean, reflect: true, attribute: 'sticky-header' }) + // stickyHeader = false; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'rowgroup'); + } + super.connectedCallback(); + } + + render() { + return html` `; + } + + static styles = styles; +} + +export default CDSTableHead; diff --git a/packages/web-components/src/components/data-table/table-header-cell.ts b/packages/web-components/src/components/data-table/table-header-cell.ts new file mode 100644 index 000000000000..6bd485960fbd --- /dev/null +++ b/packages/web-components/src/components/data-table/table-header-cell.ts @@ -0,0 +1,264 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import ArrowsVertical32 from '@carbon/icons/lib/arrows--vertical/32'; +import ArrowDown32 from '@carbon/icons/lib/arrow--down/32'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import { + TABLE_SORT_CYCLE, + TABLE_SORT_CYCLES, + TABLE_SORT_DIRECTION, +} from './defs'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { TABLE_SORT_CYCLE, TABLE_SORT_CYCLES, TABLE_SORT_DIRECTION }; + +/** + * Data table header cell. + * + * @element cds-table-header-cell + * @fires cds-table-header-cell-sort + * The custom event fired before a new sort direction is set upon a user gesture. + * Cancellation of this event stops the user-initiated change in sort direction. + */ +@customElement(`${prefix}-table-header-cell`) +class CDSTableHeaderCell extends FocusMixin(LitElement) { + /** + * Handles `click` event on the sort button. + * + */ + private _handleClickSortButton(event) { + if ( + !(event.target as HTMLElement).matches( + (this.constructor as typeof CDSTableHeaderCell).slugItem + ) + ) { + const nextSortDirection = this._getNextSort(); + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + oldSortDirection: this.sortDirection, + sortDirection: nextSortDirection, + }, + }; + const constructor = this.constructor as typeof CDSTableHeaderCell; + if ( + this.dispatchEvent(new CustomEvent(constructor.eventBeforeSort, init)) + ) { + this.sortActive = true; + this.sortDirection = nextSortDirection; + } + } + } + + /** + * Handles `slotchange` event. + * + */ + private _handleSlotChange() { + this.requestUpdate(); + } + + /** + * Handles `slotchange` event. + */ + protected _handleSlugSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSTableHeaderCell).slugItem + ) + : false + ); + if (hasContent.length > 0) { + this._hasSlug = Boolean(hasContent); + (hasContent[0] as HTMLElement).setAttribute('size', 'mini'); + } + + this.requestUpdate(); + } + + /** + * @returns The next sort direction. + */ + private _getNextSort() { + const { + sortCycle = TABLE_SORT_CYCLE.TRI_STATES_FROM_ASCENDING, + sortDirection, + } = this; + if (!sortDirection) { + throw new TypeError( + 'Table sort direction is not defined. ' + + 'Likely that `_getNextSort()` is called with non-sorted table column, which should not happen in regular condition.' + ); + } + const directions = (this.constructor as typeof CDSTableHeaderCell) + .TABLE_SORT_CYCLES[sortCycle]; + const index = directions.indexOf(sortDirection as TABLE_SORT_DIRECTION); + if (index < 0) { + if (sortDirection === TABLE_SORT_DIRECTION.NONE) { + // If the current sort direction is `none` in bi-state sort cycle, returns the first one in the cycle + return directions[0]; + } + throw new RangeError( + `The given sort state (${sortDirection}) is not found in the given table sort cycle: ${sortCycle}` + ); + } + return directions[(index + 1) % directions.length]; + } + + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + /** + * `true` if the table has expandable rows + */ + @property({ type: Boolean, reflect: true, attribute: 'expandable' }) + isExpandable = false; + + /** + * `true` if this table has selectable rows + */ + @property({ type: Boolean, reflect: true, attribute: 'is-selectable' }) + isSelectable = false; + /** + * `true` if this table header column should be sortable + */ + @property({ type: Boolean, reflect: true, attribute: 'is-sortable' }) + isSortable = false; + + /** + * `true` if this table header cell is of a primary sorting column. + */ + @property({ type: Boolean, reflect: true, attribute: 'sort-active' }) + sortActive = false; + + /** + * The table sort cycle in use. + */ + @property({ reflect: true, attribute: 'sort-cycle' }) + sortCycle?: TABLE_SORT_CYCLE; + + /** + * The table sort direction. + * If present, this table header cell will have a sorting UI. Choose between `ascending` or `descending`. + */ + @property({ reflect: true, attribute: 'sort-direction' }) + sortDirection?: TABLE_SORT_DIRECTION; + + /** + * TODO: Uncomment when Carbon fully implements sticky header + * Specify whether the header should be sticky. + * Still experimental: may not work with every combination of table props + */ + // @property({ type: Boolean, reflect: true, attribute: 'sticky-header' }) + // stickyHeader = false; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'columnheader'); + } + + super.connectedCallback(); + } + + updated(changedProperties) { + if ( + this.isSortable && + !changedProperties.has('sortDirection') && + !this.sortDirection + ) { + this.sortDirection = TABLE_SORT_DIRECTION.NONE; + } + if (this._hasSlug) { + this.setAttribute('slug', ''); + } else { + this.removeAttribute('slug'); + } + } + + render() { + const { sortDirection } = this; + const labelClasses = classMap({ + [`${prefix}--table-header-label`]: true, + [`${prefix}--table-header-label--slug`]: this._hasSlug, + }); + if (sortDirection) { + const sortIcon = + sortDirection === TABLE_SORT_DIRECTION.NONE + ? ArrowsVertical32({ + part: 'sort-icon', + class: `${prefix}--table-sort__icon-unsorted`, + }) + : ArrowDown32({ + part: 'sort-icon', + class: `${prefix}--table-sort__icon`, + }); + return html` + + `; + } + return html` + `; + } + /** + * A selector that will return the slug item. + */ + static get slugItem() { + return `${prefix}-slug`; + } + + /** + * The name of the custom event fired before a new sort direction is set upon a user gesture. + * Cancellation of this event stops the user-initiated change in sort direction. + */ + static get eventBeforeSort() { + return `${prefix}-table-header-cell-sort`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; + + /** + * Mapping of table sort cycles to table sort states. + */ + static TABLE_SORT_CYCLES = TABLE_SORT_CYCLES; +} + +export default CDSTableHeaderCell; diff --git a/packages/web-components/src/components/data-table/table-header-description.ts b/packages/web-components/src/components/data-table/table-header-description.ts new file mode 100644 index 000000000000..e8a072ebeaf8 --- /dev/null +++ b/packages/web-components/src/components/data-table/table-header-description.ts @@ -0,0 +1,29 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Data table header description + * + * @element cds-table-header-description + */ +@customElement(`${prefix}-table-header-description`) +class CDSTableHeaderDescription extends LitElement { + render() { + return html` `; + } + + static styles = styles; +} + +export default CDSTableHeaderDescription; diff --git a/packages/web-components/src/components/data-table/table-header-row.ts b/packages/web-components/src/components/data-table/table-header-row.ts new file mode 100644 index 000000000000..6ff04cc31fc6 --- /dev/null +++ b/packages/web-components/src/components/data-table/table-header-row.ts @@ -0,0 +1,33 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { prefix } from '../../globals/settings'; +import CDSTableRow from './table-row'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Data table header row. + * + * @element cds-table-header-row + * @fires cds-table-change-selection-all + * The name of the custom event fired before this row is selected/unselected upon a user gesture. + * Cancellation of this event stops the user-initiated change in selection. + */ +@customElement(`${prefix}-table-header-row`) +class CDSTableHeaderRow extends CDSTableRow { + /** + * The name of the custom event fired before this row is selected/unselected upon a user gesture. + * Cancellation of this event stops the user-initiated change in selection. + */ + static get eventBeforeChangeSelection() { + return `${prefix}-table-change-selection-all`; + } +} + +export default CDSTableHeaderRow; diff --git a/packages/web-components/src/components/data-table/table-header-title.ts b/packages/web-components/src/components/data-table/table-header-title.ts new file mode 100644 index 000000000000..1a311111a1b3 --- /dev/null +++ b/packages/web-components/src/components/data-table/table-header-title.ts @@ -0,0 +1,29 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Data table header title + * + * @element cds-table-header-title + */ +@customElement(`${prefix}-table-header-title`) +class CDSTableHeader extends LitElement { + render() { + return html` `; + } + + static styles = styles; +} + +export default CDSTableHeader; diff --git a/packages/web-components/src/components/data-table/table-row.ts b/packages/web-components/src/components/data-table/table-row.ts new file mode 100644 index 000000000000..b633c77324b7 --- /dev/null +++ b/packages/web-components/src/components/data-table/table-row.ts @@ -0,0 +1,483 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import ChevronRight16 from '@carbon/icons/lib/chevron--right/16'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import FocusMixin from '../../globals/mixins/focus'; +import styles from './data-table.scss?lit'; +import '../checkbox'; +import '../radio-button'; + +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import CDSTableExpandedRow from './table-expanded-row'; +import CDSTableCell from './table-cell'; + +/** + * Data table row. + * + * @element cds-table-row + * @csspart selection-container The container of the checkbox. + * @csspart selection The checkbox. + * @fires cds-table-row-change-selection + * The custom event fired before this row is selected/unselected upon a user gesture. + * Cancellation of this event stops the user-initiated change in selection. + * @fires cds-radio-button-changed + * The name of the custom event fired after this radio button changes its checked state. + * @fires cds-checkbox-changed + * The name of the custom event fired after this checkbox changes its checked state. + * @fires cds-table-row-expando-beingtoggled + * The name of the custom event fired before the expanded state of this row is being toggled upon a user gesture. + * Cancellation of this event stops the user-initiated action of toggling the expanded state. + * @fires cds-table-row-expando-toggled + * The name of the custom event fired after the expanded state of this row is toggled upon a user gesture. + */ +@customElement(`${prefix}-table-row`) +class CDSTableRow extends HostListenerMixin(FocusMixin(LitElement)) { + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + /** + * Handles `click` event on the radio button. + * + * @param event The event. + */ + @HostListener('eventRadioChange') + // @ts-ignore + private _handleClickSelectionRadio(event: CustomEvent) { + const { detail } = event; + const selected = detail.checked; + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + selected, + }, + }; + const constructor = this.constructor as typeof CDSTableRow; + if ( + this.dispatchEvent( + new CustomEvent(constructor.eventBeforeChangeSelection, init) + ) + ) { + this.selected = selected; + const { selectorExpandedRow } = this.constructor as typeof CDSTableRow; + + if (this.nextElementSibling?.matches(selectorExpandedRow)) { + (this.nextElementSibling as CDSTableExpandedRow).selected = selected; + } + } + } + + /** + * Handles `click` event on the check box. + * + * @param event The event. + */ + @HostListener('eventCheckboxChange') + // @ts-ignore + private _handleClickSelectionCheckbox(event: CustomEvent) { + const { detail } = event; + const selected = detail.checked; + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + selected, + }, + }; + const constructor = this.constructor as typeof CDSTableRow; + if ( + this.dispatchEvent( + new CustomEvent(constructor.eventBeforeChangeSelection, init) + ) + ) { + this.selected = selected; + const { selectorExpandedRow } = this.constructor as typeof CDSTableRow; + + if (this.nextElementSibling?.matches(selectorExpandedRow)) { + (this.nextElementSibling as CDSTableExpandedRow).selected = selected; + } + } + } + + /** + * Handles `click` event on the expando button. + */ + private _handleClickExpando() { + this._handleUserInitiatedToggleExpando(); + } + + /** + * Handles `mouseover`/`mouseout` event handler on this element. + * + * @param event The event. + */ + @HostListener('mouseover') + @HostListener('mouseout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleMouseOverOut(event: MouseEvent) { + const { selectorExpandedRow, selectorTableCellOverflowMenu } = this + .constructor as typeof CDSTableRow; + const { nextElementSibling } = this; + if (nextElementSibling?.matches(selectorExpandedRow)) { + (nextElementSibling as CDSTableExpandedRow).highlighted = + event.type === 'mouseover'; + } + if (this.overflowMenuOnHover) { + const overflowMenu = this.querySelector(selectorTableCellOverflowMenu); + const parentCell = overflowMenu?.parentElement; + + if (event.type === 'mouseout') { + (parentCell as CDSTableCell).overflowMenuOnHover = true; + } else { + (parentCell as CDSTableCell).overflowMenuOnHover = false; + } + } + } + + /** + * Handles user-initiated toggle request of the expando button in this table row. + * + * @param expanded The new expanded state. + */ + _handleUserInitiatedToggleExpando(expanded = !this.expanded) { + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + expanded, + }, + }; + if ( + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSTableRow).eventBeforeExpandoToggle, + init + ) + ) + ) { + this.expanded = expanded; + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSTableRow).eventExpandoToggle, + init + ) + ); + } + } + + protected _renderExpandButton() { + const { _handleClickExpando: handleClickExpando } = this; + return html` +
    +
    + + +
    +
    + `; + } + + /** + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSTableRow).slugItem + ) + : false + ); + if (hasContent.length > 0) { + this._hasSlug = Boolean(hasContent); + (hasContent[0] as HTMLElement).setAttribute('size', 'mini'); + } + this.requestUpdate(); + } + + /** + * @returns The first set of table cells. + */ + protected _renderFirstCells() { + const { + disabled, + hideCheckbox, + radio, + selected, + selectionLabel, + selectionName, + selectionValue, + } = this; + return !selectionName + ? undefined + : html` +
    +
    + + ${radio + ? html`` + : html` `} +
    +
    + `; + } + + /** + * `true` if this table should support batch expansion + */ + @property({ type: Boolean, reflect: true, attribute: 'batch-expansion' }) + batchExpansion = false; + + /** + * `true` if this table row should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * `true` if this table row is placed at an even position in parent ``. + * `` sets this property, _only_ in zebra stripe mode. + * + * @private + */ + @property({ type: Boolean, reflect: true }) + even = false; + + /** + * `true` if this table row can be expanded to show content underneath + * + * @private + */ + @property({ type: Boolean, reflect: true }) + expandable = false; + + /** + * `true` when the table row expanded is showing + * + * @private + */ + @property({ type: Boolean, reflect: true }) + expanded = false; + + /** + * `true` if this table row should be filtered out. + */ + @property({ type: Boolean, reflect: true }) + filtered = false; + + /** + * Specify whether the checkbox should be present in the DOM, + * but invisible and uninteractable. + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-checkbox' }) + hideCheckbox = false; + + /** + * `true` if the table row should be highlighted. + */ + @property({ type: Boolean, reflect: true }) + highlighted = false; + + /** + * `true` if this table row is placed at an odd position in parent ``. + * `` sets this property, _only_ in zebra stripe mode. + * + * @private + */ + @property({ type: Boolean, reflect: true }) + odd = false; + + /** + * Specify whether the overflow menu (if it exists) should be shown always, or only on hover + */ + @property({ + type: Boolean, + reflect: true, + attribute: 'overflow-menu-on-hover', + }) + overflowMenuOnHover = false; + + /** + * Specify whether the control should be a radio button or inline checkbox + * + * @private + */ + @property({ type: Boolean, reflect: true }) + radio = false; + + /** + * `true` if this table row should be selected. + */ + @property({ type: Boolean, reflect: true }) + selected = false; + + /** + * The `aria-label` attribute for the `
    ` | +| `` | The header body | `
    ` | + +## Table of Contents + +- [Getting started](#getting-started) +- [Sorting](#sorting) + - [Programmatic sorting](#programmatic-sorting) + - [Custom sorting](#custom-sorting) +- [Expansion](#expansion) + - [Programmatic expansion](#programmatic-expansion) +- [Selection](#selection) + - [Programmatic selection](#programmatic-selection) +- [Filtering](#filtering) +- [Batch actions](#batch-actions) +- [Toolbar](#toolbar) +- [Skeleton](#skeleton) +- [Attributes, properties, and events](#attributes-properties-and-events) + +- [Feedback](#feedback) + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/data-table/index.js'; +``` + +{`${cdnJs({ components: ['data-table'] })}`} +{`${cdnCss()}`} + +### HTML + +Here is an example of a basic data table with a header row with two columns, and +three regular rows: + +```html + + + + Name + Status + + + + + Load Balancer 1 + Disabled + + + Load Balancer 2 + Starting + + + Load Balancer 3 + Active + + + +``` + +After rendering a `DataTable` component using the code snippet above, you can +optionally add any number of features including sorting, row expansion, +filtering, row selection, batch actions. + +For more information, see each usage section below for the functionality that +you're interested in. If you want to see a full list of the arguments passed +into your render prop, visit the +[render props](#attributes-properties-and-events) section. + +### Table header + +You can add a header to the table that can contain a title and a description. + +```html + + DataTable + Example of a DataTable description. + + + Name + Status + + + + + Load Balancer 1 + Disabled + + + Load Balancer 2 + Starting + + + Load Balancer 3 + Active + + + +``` + +### XL With Two Lines + +In case there is extra data that needs to be added within a `` +that would require a second line, you can use the `` +component as such: + +```html + + ... + + + Load Balancer 1 + Austin, Tx + + Round robin + Starting + Test + 22 + + ... + +``` + +This requires the table to be of `size="xl"` to accomodate the content properly. + +## Sorting + +In order to sort the rows in your data table, you will need to pass in the +`is-sortable` prop to the `` component. + +Optionally, you can pass in `is-sortable` to each `` that +you want to be sorted, or not sorted. This is useful if you only want to enable +sorting on some table column headers, but not all. + +```html + ... +``` + +### Programmatic sorting + +You can also change the sort status of the table by querying the specific +`` you would like to sort. + +```js +// sorting the first column +document + .querySelectorAll('cds-table-header-cell')[0] + .shadowRoot.querySelector('button') + .click(); +``` + +### Custom sorting + +If the default sorting logic doesn't match your use-case, you can provide a +custom sort method as a `customSortRow` prop to ``. + +`sortRow` is a method that takes in the values of two cells, in addition to some +info, and should return -1, 0, or 1 as a result (mirroring the native sort +behavior in JavaScript). + +The component uses a default `Intl.Collator` object created with the current set +locale to sort the rows. The default sorting row function uses this collator, +and as such it is needed in the custom sorting function. + +As a result, `customSortRow` function would take on the following shape: + +```js + customSortRow(lhs, rhs, collator) { + if (typeof lhs === 'number' && typeof rhs === 'number') { + return lhs - rhs; + } + return collator.compare(lhs, rhs); + } + + document.querySelector('cds-table').customSortRow = customSortRow; +``` + +If you would like to use a different locale for collator comparisons, you can +change the `locale` property and it will be updated accordingly. In case a +different collator is needed, you can create a new object and pass it in as +such: + +```js + document.querySelector('cds-table').collator = // new collator here; +``` + +## Expansion + +The `` component supports row-level expansion when using the +`expandable` prop. Setting the prop will apply the `expandable` prop to every +row. This is useful when every row can be expandable. In order to make a row be +expandable, it is necessary for the row to have a `` +component directly following it. + +```html + + + + Name + Status + + + + + Load Balancer 1 + Disabled + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 2 + Starting + + +
    Expandable row content
    +
    Description here
    +
    + + Load Balancer 3 + Active + + +
    Expandable row content
    +
    Description here
    +
    +
    +
    +``` + +In case you'd like a button to expand all the rows at once, you can use the +`batch-expansion` prop in ``. + +In case you only want to set specific rows to be expandable, be sure to set the +`expandable` prop only on that specific `` component, and have +its adjacent sibling `` directly following it. + +### Programmatic expansion + +You can programmatically trigger a row expansion by querying the desired row as +such: + +```js +document + .querySelectorAll('cds-table-row')[0] + .shadowRoot.querySelector('.cds--table-expand__button') + .click(); +``` + +## Selection + +The `` component supports row selection when using the +`is-selectable` prop. Setting the prop will automatically set a numerical +`selection-name` attribute to every row, though this can also be customized with +your own custom name. + +```html + +``` + +By default, the `` component will render with its own +checkbox, used to select all the rows at once. If you would like to disable this +behavior, set the `hide-checkbox` prop within the component. + +```html + + ... + ... + ... + +``` + +### Programmatic selection + +You can programmatically trigger a row selection by querying the desired row as +such: + +```js +document + .querySelectorAll('cds-table-row')[0] + .shadowRoot.querySelector('cds-checkbox') + .shadowRoot.querySelector('input') + .click(); +``` + +## Filtering + +Filtering in a `` is provided through usage of the +`` and the `` component. Any input +entered through `` will be used in the built-in +filtering function. + +```html + + + + + + + ... header + ... body and rows + +``` + +Our built-in filtering function scans the rows' strings and attempts to match to +the current search value input. If there are no matches in a given row, the +current row will be filtered out. + +In other words, a custom function will be doing its own string comparison per +row, and thus it would have the following structure: + +```js +const newFilterRows = (rowText, searchString) => { + return; // provide custom string comparison return boolean; +}; + +document.querySelector('cds-table').filterRows = newFilterRows; +``` + +## Batch actions + +You can combine batch actions with the `` component to allow the user +to perform a single action on multiple selected rows. + +This toolbar is highly customizable, as any action can be adhered to a +`` and inserted into the toolbar. + +In the example below, we have custom ``s that we can customize to +our liking by using the `onclick` property and passing it any custom functions. + +The component has a built-in download function, that is called whenever one of +the ``s has a `download` attribute. The component will create a JSON +object containing the currently selected rows, and trigger its download within +the browser. + +```js +const alertFunction = () => alert('Alert!'); +``` + +```html + + + + Delete + + + Save + + + Download + + + + + ... headers + ... body and rows + +``` + +## Toolbar + +As mentioned earlier, you can add a `` component to +the toolbar. You can also add an overflow menu and a button within the toolbar +as such: + +```html + + + + + + + + Example 1 + Example 2 + + + Example button + + + ... header + ... body and rows + +``` + +### Overflow Menu + +An overflow menu can be added to the toolbar table row. To add an overflow menu, +simply add a `` containing the ``. + +```html +... + + Load Balancer 4 + HTTP + 443 + Round robin + Mel's VM Groups + Starting + + + + Options + + Stop app + Restart app + Rename + + + + +... +``` + +## Skeleton + +The default Skeleton table will render with 5 rows and columns, the header, and +the toolbar. + +```html + +``` + +Specify the number of rows and columns you need with the `row-count` and +`column-count` attributes. + +```html + +``` + +### Custom headers + +Optionally, you can specify to have header titles on the Skeleton table. + +```html + +``` + +```javascript +const customHeaders = [ + 'Name', + 'Protocol', + 'Port', + 'Rule', + 'Attached groups', + 'Status', +]; +document.querySelector('cds-table-skeleton').headers = customHeaders; +``` + +## Attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `is-sortable` attribute). + +### `` + + + +### `` + + + +### `` + + + +### `` + + + +### `` + + + +### `` + + + +### ` + +### `` + + + +### `` + + + +### `` + + + +### `` + + + +### `cds-table-skeleton` + + diff --git a/packages/web-components/src/components/data-table/table-batch-actions.ts b/packages/web-components/src/components/data-table/table-batch-actions.ts new file mode 100644 index 000000000000..d806ac38297a --- /dev/null +++ b/packages/web-components/src/components/data-table/table-batch-actions.ts @@ -0,0 +1,109 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Table batch actions. + * + * @element cds-table-batch-actions + * @fires cds-table-batch-actions-cancel-clicked - The custom event fired after the Cancel button is clicked. + */ +@customElement(`${prefix}-table-batch-actions`) +class CDSTableBatchActions extends LitElement { + /** + * Handles `click` event on the Cancel button. + */ + private _handleCancel() { + const { eventClickCancel } = this + .constructor as typeof CDSTableBatchActions; + this.dispatchEvent( + new CustomEvent(eventClickCancel, { bubbles: true, composed: true }) + ); + } + + /** + * `true` if this batch actions bar should be active. + */ + @property({ type: Boolean, reflect: true }) + active = false; + + /** + * The formatter for selected items. Should be changed upon the locale the UI is rendered with. + */ + @property({ attribute: false }) + formatSelectedItemsCount = ({ count }) => + `${count} item${count <= 1 ? '' : 's'} selected`; + + /** + * Numeric representation of the total number of items selected in a table. + * This number is used to derive the selection message. + */ + @property({ type: Number, attribute: 'selected-rows-count' }) + selectedRowsCount = 0; + + firstUpdated() { + this.querySelectorAll( + (this.constructor as typeof CDSTableBatchActions).selectorButtons + ).forEach((e) => { + e.setAttribute('batch-action', ''); + }); + } + + updated(changedProperties) { + if (changedProperties.has('active')) { + this.setAttribute('tabindex', `${this.active ? '' : '-1'}`); + } + } + + render() { + const { + formatSelectedItemsCount, + selectedRowsCount, + _handleCancel: handleCancel, + } = this; + return html` +
    +

    + ${formatSelectedItemsCount({ count: selectedRowsCount })} +

    +
    +
    + + +
    + `; + } + + /** + * The CSS selector to find the action buttons. + */ + static get selectorButtons() { + return `${prefix}-button`; + } + + /** + * The name of the custom event fired after the Cancel button is clicked. + */ + static get eventClickCancel() { + return `${prefix}-table-batch-actions-cancel-clicked`; + } + + static styles = styles; +} + +export default CDSTableBatchActions; diff --git a/packages/web-components/src/components/data-table/table-body.ts b/packages/web-components/src/components/data-table/table-body.ts new file mode 100644 index 000000000000..6af76bae1859 --- /dev/null +++ b/packages/web-components/src/components/data-table/table-body.ts @@ -0,0 +1,86 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import CDSTableRow from './table-row'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Data table body. + * + * @element cds-table-body + */ +@customElement(`${prefix}-table-body`) +class CDSTableBody extends LitElement { + /** + * The `` element in the shadow DOM. + */ + @query('slot') + private _slotNode!: HTMLSlotElement; + + /** + * Updates `even`/`odd` properties of the child ``s. + */ + private _updateZebra() { + const { useZebraStyles, _slotNode: slotNode } = this; + slotNode.assignedNodes().forEach((node) => { + if (node.nodeType === Node.ELEMENT_NODE) { + const even = (node as HTMLElement).matches('*:nth-of-type(even)'); + (node as CDSTableRow).even = useZebraStyles && even; + (node as CDSTableRow).odd = useZebraStyles && !even; + } + }); + } + + /** + * Handles `slotchange` event in the `` element in the shadow DOM. + */ + private _handleSlotChange = () => { + this._updateZebra(); + }; + + /** + * TODO: Uncomment when Carbon fully implements sticky header + * Specify whether the header should be sticky. + * Still experimental: may not work with every combination of table props + */ + // @property({ type: Boolean, reflect: true, attribute: 'sticky-header' }) + // stickyHeader = false; + + /** + * The color scheme. + */ + @property({ type: Boolean, reflect: true, attribute: 'use-zebra-styles' }) + useZebraStyles = false; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'rowgroup'); + } + super.connectedCallback(); + } + + updated(changedProperties) { + if (changedProperties.has('useZebraStyles')) { + this._updateZebra(); + } + } + + render() { + const { _handleSlotChange: handleSlotChange } = this; + return html` `; + } + + static styles = styles; +} + +export default CDSTableBody; diff --git a/packages/web-components/src/components/data-table/table-cell-content.ts b/packages/web-components/src/components/data-table/table-cell-content.ts new file mode 100644 index 000000000000..b0ea5527fd60 --- /dev/null +++ b/packages/web-components/src/components/data-table/table-cell-content.ts @@ -0,0 +1,29 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Data table cell content. + * + * @element cds-table-cell-content + */ +@customElement(`${prefix}-table-cell-content`) +class CDSTableCellContent extends LitElement { + render() { + return html` `; + } + + static styles = styles; +} + +export default CDSTableCellContent; diff --git a/packages/web-components/src/components/data-table/table-cell.ts b/packages/web-components/src/components/data-table/table-cell.ts new file mode 100644 index 000000000000..9c4e789bd4fb --- /dev/null +++ b/packages/web-components/src/components/data-table/table-cell.ts @@ -0,0 +1,61 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Data table cell. + * + * @element cds-table-cell + */ +@customElement(`${prefix}-table-cell`) +class CDSTableCell extends LitElement { + /** + * Specify whether the overflow menu (if it exists) should be shown always, or only on hover + */ + @property({ + type: Boolean, + reflect: true, + attribute: 'overflow-menu-on-hover', + }) + overflowMenuOnHover = false; + + /** + * The table size. + */ + @property({ reflect: true }) + size; + + /** + * TODO: Uncomment when Carbon fully implements sticky header + * Specify whether the header should be sticky. + * Still experimental: may not work with every combination of table props + */ + // @property({ type: Boolean, reflect: true, attribute: 'sticky-header' }) + // stickyHeader = false; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'cell'); + } + super.connectedCallback(); + } + + render() { + return html``; + } + + static styles = styles; +} + +export default CDSTableCell; diff --git a/packages/web-components/src/components/data-table/table-expanded-row.ts b/packages/web-components/src/components/data-table/table-expanded-row.ts new file mode 100644 index 000000000000..87eafa0b4438 --- /dev/null +++ b/packages/web-components/src/components/data-table/table-expanded-row.ts @@ -0,0 +1,100 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import CDSTableRow from './table-row'; +/** + * Table row of collapsible details. + * + * @element cds-table-expanded-row + */ +@customElement(`${prefix}-table-expanded-row`) +class CDSTableExpandedRow extends HostListenerMixin(LitElement) { + /** + * Handles `mouseover`/`mouseout` event handler on this element. + * + * @param event The event. + */ + @HostListener('mouseover') + @HostListener('mouseout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleMouseOverOut(event: MouseEvent) { + const { selectorRow } = this.constructor as typeof CDSTableExpandedRow; + const { previousElementSibling } = this; + if (previousElementSibling?.matches(selectorRow)) { + (previousElementSibling as CDSTableRow).highlighted = + event.type === 'mouseover'; + } + } + + /** + * The colspan. + */ + @property({ type: Number, attribute: 'colspan' }) + colSpan = 1; + + /** + * `true` if the table row should be expanded. + */ + @property({ type: Boolean, reflect: true }) + expanded = false; + + /** + * `true` if the table row should be filtered. + */ + @property({ type: Boolean, reflect: true }) + filtered = false; + + /** + * `true` if the table row should be highlighted. + */ + @property({ type: Boolean, reflect: true }) + highlighted = false; + + /** + * `true` if the previous table row has been selected + */ + @property({ type: Boolean, reflect: true }) + selected = false; + + render() { + const { colSpan } = this; + return html` +
    +
    + +
    +
    + + + ${Array.from(new Array(columnCount)).map( + (_, index) => + html` + + ` + )} + + + + ${Array.from(new Array(rowCount)).map( + () => + html` + + ${Array.from(new Array(columnCount)).map( + () => + html` + + ` + )} + + ` + )} + +
    +
    + ${headers[index]} +
    +
    + +
    + `; + } + + static styles = styles; +} + +export default CDSTableSkeleton; diff --git a/packages/web-components/src/components/data-table/table-toolbar-content.ts b/packages/web-components/src/components/data-table/table-toolbar-content.ts new file mode 100644 index 000000000000..d9db5f1b18b8 --- /dev/null +++ b/packages/web-components/src/components/data-table/table-toolbar-content.ts @@ -0,0 +1,60 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Table toolbar content. + * + * @element cds-table-toolbar-content + */ +@customElement(`${prefix}-table-toolbar-content`) +class CDSTableToolbarContent extends LitElement { + /** + * `true` if this batch actions bar is active. + */ + @property({ type: Boolean, reflect: true, attribute: 'has-batch-actions' }) + hasBatchActions = false; + + /** + * Table toolbar contents size + */ + @property({ reflect: true }) + size; + + updated(changedProperties) { + if (changedProperties.has('hasBatchActions')) { + this.setAttribute('tabindex', `${this.hasBatchActions ? '-1' : ''}`); + } + + if (changedProperties.has('size')) { + [...this.children].forEach((e) => { + const size = + this.size === 'xs' + ? 'sm' + : this.size === 'md' || this.size === 'xl' + ? 'lg' + : this.size; + e.setAttribute('size', size); + }); + } + } + + render() { + return html` `; + } + + static styles = styles; +} + +export default CDSTableToolbarContent; diff --git a/packages/web-components/src/components/data-table/table-toolbar-search.ts b/packages/web-components/src/components/data-table/table-toolbar-search.ts new file mode 100644 index 000000000000..0d64aa0de5c6 --- /dev/null +++ b/packages/web-components/src/components/data-table/table-toolbar-search.ts @@ -0,0 +1,140 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import HostListener from '../../globals/decorators/host-listener'; +import { INPUT_SIZE } from '../text-input/text-input'; +import CDSSearch from '../search/search'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Table toolbar search. + * + * @element cds-table-toolbar-search + * @fires cds-search-input - The custom event fired after the search content is changed upon a user gesture. + */ +@customElement(`${prefix}-table-toolbar-search`) +class CDSTableToolbarSearch extends HostListenerMixin(CDSSearch) { + @query('input') + private _inputNode!: HTMLInputElement; + + /** + * Handles user-initiated gestures for expanding the search box. + */ + private async _handleUserInitiatedExpand() { + this.expanded = true; + await this.updateComplete; + const { _inputNode: inputNode } = this; + inputNode?.focus(); + } + + /** + * Handles `focus` event handler on this element. + */ + @HostListener('focusin') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleFocusIn() { + this._handleUserInitiatedExpand(); + } + + /** + * Handles `blur` event handler on this element. + * + * @param event The event. + */ + @HostListener('focusout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleFocusOut(event: FocusEvent) { + if ( + !this.contains(event.relatedTarget as Node) && + !this.value && + !this.persistent + ) { + this.expanded = false; + } + } + + /** + * Handles `click` event handler on the search box. + */ + private _handleSearchClick() { + this._handleUserInitiatedExpand(); + } + + /** + * `true` if the search box should be expanded. + */ + @property({ type: Boolean, reflect: true }) + expanded = false; + + /** + * `true` if the search box should be always be open. + */ + @property({ type: Boolean, reflect: true }) + persistent = false; + + /** + * The search box size. + */ + @property({ reflect: true }) + size = INPUT_SIZE.LARGE; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'search'); + } + super.connectedCallback(); + } + + render() { + const result = super.render(); + const { + persistent, + expanded, + size, + _handleSearchClick: handleSearchClick, + } = this; + const classes = classMap({ + [`${prefix}--search`]: true, + [`${prefix}--search--${size}`]: size, + }); + if (persistent) { + this.expanded = true; + } + return html` +
    + ${result} +
    + `; + } + + /** + * The name of the custom event fired after the search content is changed upon a user gesture. + */ + static get eventInput() { + // The code uses on in ``, but definition is done also here for React event generation + return `${prefix}-search-input`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; +} + +export default CDSTableToolbarSearch; diff --git a/packages/web-components/src/components/data-table/table-toolbar.ts b/packages/web-components/src/components/data-table/table-toolbar.ts new file mode 100644 index 000000000000..59a72c9f234c --- /dev/null +++ b/packages/web-components/src/components/data-table/table-toolbar.ts @@ -0,0 +1,61 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './data-table.scss?lit'; +import { CDSTableToolbarContent } from '../..'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Table toolbar. + * + * @element cds-table-toolbar + */ +@customElement(`${prefix}-table-toolbar`) +class CDSTableToolbar extends LitElement { + /** + * Toolbar size + */ + @property({ reflect: true }) + size; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'section'); + } + super.connectedCallback(); + } + + updated(changedProperties) { + if (changedProperties.has('size')) { + ( + this.querySelector( + (this.constructor as typeof CDSTableToolbar).selectorToolbarContent + ) as CDSTableToolbarContent + ).size = this.size; + } + } + + render() { + return html` `; + } + + /** + * The CSS selector to find the toolbar contents + */ + static get selectorToolbarContent() { + return `${prefix}-table-toolbar-content`; + } + + static styles = styles; +} + +export default CDSTableToolbar; diff --git a/packages/web-components/src/components/data-table/table.ts b/packages/web-components/src/components/data-table/table.ts new file mode 100644 index 000000000000..f64c7276d939 --- /dev/null +++ b/packages/web-components/src/components/data-table/table.ts @@ -0,0 +1,1047 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property, state } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { forEach } from '../../globals/internal/collection-helpers'; +import { TABLE_SIZE, TABLE_SORT_DIRECTION } from './defs'; +import styles from './data-table.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import { + CDSRadioButton, + CDSTableBatchActions, + CDSTableCell, + CDSTableHeaderCell, + CDSTableHeaderRow, + CDSTableRow, + CDSTableToolbarSearch, +} from '../..'; +import CDSTableExpandedRow from './table-expanded-row'; + +export { TABLE_SIZE }; + +/** + * Data table. + * + * @element cds-table + * @fires cds-table-header-cell-sort + * The name of the custom event fired before a new sort direction is set upon a user gesture. + * Cancellation of this event stops the user-initiated change in sort direction. + * @fires cds-search input + * The name of the custom event fired during search bar input + * @fires cds-table-change-selection-all + * The name of the custom event fired before header row is selected/unselected upon a user gesture. + * @fires cds-table-row-change-selection + * The name of the custom event fired before a row is selected/unselected upon a user gesture. + * @fires cds-table-batch-actions-cancel-clicked + * The name of the custom event fired after the Cancel button is clicked. + * @fires cds-table-row-expando-toggled + * The name of the custom event fired after the expanded state of a row is toggled upon a user gesture. + * @fires cds-table-row-selected + * The name of the custom event fired after a row has been selected. + * @fires cds-table-row-all-selected + * The name of the custom event fired after all rows have been selected. + * @fires cds-table-sorted + * The name of the custom event fired after the table has been sorted. + * @fires cds-table-filtered + * The name of the custom event fired after the table has been filtered containing remaining rows. + */ +@customElement(`${prefix}-table`) +class CDSTable extends HostListenerMixin(LitElement) { + /** + * The map of how sorting direction affects sorting order. + */ + private collationFactors = { + [TABLE_SORT_DIRECTION.ASCENDING]: 1, + [TABLE_SORT_DIRECTION.DESCENDING]: -1, + }; + + /** + * Reference to download button + */ + @state() + private _downloadButton; + + /** + * Current search value for filtering + */ + @state() + private _searchValue = ''; + + /** + * Table header row within component + */ + @state() + private _tableHeaderRow; + + /** + * Table body + */ + @state() + private _tableBody; + + /** + * Table expanded row within component + */ + @state() + private _tableExpandedRows; + + /** + * Table rows within component + */ + @state() + private _tableRows; + + /** + * Reference to the component containing batch actions + */ + @state() + private _tableBatchActions; + + /** + * Reference to the table toolbar + */ + @state() + private _tableToolbar; + + /** + * Reference to the table toolbar content + */ + @state() + private _tableToolbarContent; + + @state() + private _selectedRows: CDSTableRow[] = []; + + /** + * `true` if this table should support batch expansion + */ + @property({ type: Boolean, reflect: true, attribute: 'batch-expansion' }) + batchExpansion = false; + + /** + * The g11n collator to use. + */ + @property({ attribute: false }) + collator; + + /** + * @param lhs A value. + * @param rhs Another value. + * @param collator A custom collator. + * @returns + * `0` if the given two values are equal + * A negative value to sort `lhs` to an index lower than `rhs` + * A positive value to sort `rhs` to an index lower than `lhs` + */ + // eslint-disable-next-line class-methods-use-this + customSortRow(lhs, rhs, collator) { + if (typeof lhs === 'number' && typeof rhs === 'number') { + return lhs - rhs; + } + return collator.compare(lhs, rhs); + } + + /** + * Specify whether the rows should be able to be expandable + */ + @property({ type: Boolean, reflect: true }) + expandable = false; + + /** + * The method used when filtering the table with the search bar. + * Can be replaced with custom method. + * + * @param rowText A table row. + * @param searchString A search string. + * @returns `false` if the given table row matches the given search string. + */ + @property() + filterRows = (rowText: string, searchString: string) => + rowText.toLowerCase().indexOf(searchString.toLowerCase()) < 0; + + /** + * The total headers + */ + @property() + headerCount = 0; + + /** + * `true` if this table contains selectable rows + */ + @property({ type: Boolean, reflect: true, attribute: 'is-selectable' }) + isSelectable = false; + + /** + * `true` if this table should support sorting. + */ + @property({ type: Boolean, reflect: true, attribute: 'is-sortable' }) + isSortable = false; + + /** + * The table size. + */ + @property({ reflect: true }) + locale = 'en'; + + /** + * Specify whether the overflow menu (if it exists) should be shown always, or only on hover + */ + @property({ + type: Boolean, + reflect: true, + attribute: 'overflow-menu-on-hover', + }) + overflowMenuOnHover = false; + + /** + * Specify whether the control should be a radio button or inline checkbox + */ + @property({ type: Boolean, reflect: true }) + radio = false; + + /** + * The table size. + */ + @property({ reflect: true }) + size = TABLE_SIZE.LG; + + /** + * TODO: Uncomment when Carbon fully implements sticky header + * Specify whether the header should be sticky. + * Still experimental: may not work with every combination of table props + */ + // @property({ type: Boolean, attribute: 'sticky-header', reflect: true }) + // stickyHeader = false; + + /** + * If true, will use a width of 'auto' instead of 100% + */ + @property({ type: Boolean, attribute: 'use-static-width', reflect: true }) + useStaticWidth = false; + + /** + * true to add useZebraStyles striping. + */ + @property({ type: Boolean, attribute: 'use-zebra-styles', reflect: true }) + useZebraStyles = false; + + @property({ type: Boolean, attribute: 'with-header', reflect: true }) + withHeader; + + /** + * true if slugs are added in the rows + */ + @property({ type: Boolean, attribute: 'with-row-slugs' }) + withRowSlugs = false; + + private _handleSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .some( + (node) => node.nodeType !== Node.TEXT_NODE || node!.textContent!.trim() + ); + this.withHeader = hasContent; + } + + private _handleSortAction(columnIndex, sortDirection) { + const rows = [...this._tableRows]; + + // regular row sorting + rows.sort((a, b) => { + const cellA = a.querySelectorAll( + (this.constructor as typeof CDSTable).selectorTableRowCells + )[columnIndex].textContent; + const cellB = b.querySelectorAll( + (this.constructor as typeof CDSTable).selectorTableRowCells + )[columnIndex].textContent; + return ( + this.collationFactors[sortDirection] * + this.customSortRow(cellA, cellB, this.collator) + ); + }); + + // take into account the expanded rows, mapping each expandable row to its original for proper reinsertion + if (this.expandable) { + const originalRows = [...this._tableRows]; + const expandedRows = [...this._tableExpandedRows]; + + const mapping = originalRows.reduce((acc, element, index) => { + const sortId = element.getAttribute('sort-id'); + acc[sortId] = expandedRows[index]; + return acc; + }, {}); + + const sortedWithExpanded = [] as any; + + rows.forEach((e) => { + const sortId = e.getAttribute('sort-id'); + sortedWithExpanded.push(e); + sortedWithExpanded.push(mapping[sortId]); + }); + + sortedWithExpanded.forEach((e) => { + this._tableBody.insertBefore(e, null); + }); + } else { + rows.forEach((e) => { + this._tableBody.insertBefore(e, null); + }); + } + } + + private _handleFilterRows() { + const unfilteredRows = [] as any; + forEach(this._tableRows, (elem) => { + let rowText = elem.textContent?.trim(); + let filtered = this.filterRows(rowText as string, this._searchValue); + (elem as any).filtered = filtered; + + if (filtered && this.expandable) { + rowText = (elem as any).nextElementSibling.textContent?.trim(); + filtered = this.filterRows(rowText as string, this._searchValue); + (elem as any).filtered = filtered; + } + + if (!filtered) { + unfilteredRows.push(elem); + } + + if (this.expandable) { + (elem as any).nextElementSibling.filtered = filtered; + } + }); + + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + unfilteredRows, + }, + }; + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSTable).eventTableFiltered, + init + ) + ); + } + + /** + * Download manager for selected rows. + */ + private _handleDownload({ target }) { + const data = [] as any; + + const elementsToArray = (elements) => + Array.from(elements, (element) => (element as any).textContent); + + const headerCells = this.querySelectorAll( + (this.constructor as typeof CDSTable).selectorHeaderCell + ); + const rows = this._selectedRows; + const headerTitleArray = elementsToArray(headerCells); + + rows.forEach((row) => { + const rowData = {}; + const cells = elementsToArray( + row.querySelectorAll( + (this.constructor as typeof CDSTable).selectorTableRowCells + ) + ); + + cells.forEach((cellText, index) => { + const headerTitle = headerTitleArray[index]; + rowData[headerTitle] = cellText; + }); + + data.push(rowData); + }); + + const blob = new Blob([JSON.stringify(data)], { type: 'application/json' }); + + target.href = URL.createObjectURL(blob); + } + + /** + * Handles batch expansion + */ + @HostListener('eventExpandoToggle') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleBatchExpansion = async (event: CustomEvent) => { + const { detail, target } = event; + const { expanded } = detail; + + if ((target as CDSTableHeaderRow) === this._tableHeaderRow) { + this._tableRows.forEach((e) => ((e as CDSTableRow).expanded = expanded)); + } + }; + + /** + * Handles sorting the table depending on the column selected + */ + @HostListener('eventBeforeSort') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleSort = async (event: CustomEvent) => { + const { detail, target } = event; + const { sortDirection } = detail; + + if (!this.contains(target as any)) { + return; + } + + const columns = [...this._tableHeaderRow.children]; + const columnIndex = columns.indexOf(target); + + columns.forEach((e) => { + if (e !== target && this.isSortable) { + e.setAttribute('sort-direction', 'none'); + } else if (e.hasAttribute('is-sortable')) { + e.setAttribute('sort-direction', 'none'); + } + }); + + this._handleSortAction(columnIndex, sortDirection); + + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + sortedHeader: columns[columnIndex], + }, + }; + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSTable).eventTableSorted, + init + ) + ); + + this._handleFilterRows(); + }; + + /** + * Handles search input within the toolbar actions + */ + @HostListener('eventSearchInput') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleSearchInput = async (event: CustomEvent) => { + const { detail, target } = event; + + if (this.contains(target as CDSTableToolbarSearch)) { + const { value } = detail; + this._searchValue = value; + this._handleFilterRows(); + } + }; + + /** + * Handles row selection + */ + @HostListener('eventBeforeChangeSelection') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleRowSelect = async (event: CustomEvent) => { + const { detail, target } = event; + const { selected } = detail; + const { + _tableBatchActions: tableBatchActions, + _tableToolbarContent: tableToolbarContent, + _tableHeaderRow: tableHeaderRow, + _selectedRows: selectedRows, + } = this; + + if (!this.contains(target as CDSTableRow)) { + return; + } + + if (this.radio) { + this._tableRows.forEach((e) => { + if (e !== target) { + e.removeAttribute('selected'); + e.shadowRoot!.querySelector(`${prefix}-radio-button`).checked = false; + } + }); + this._selectedRows.push(...[target as CDSTableRow]); + } else { + if (selectedRows.includes(target as CDSTableRow)) { + this._selectedRows = selectedRows.filter((e) => e !== target); + } else { + selectedRows.push(target as CDSTableRow); + } + + if (tableBatchActions) { + tableBatchActions.active = this._selectedRows?.length; + tableBatchActions.selectedRowsCount += selected ? 1 : -1; + } + + if (tableToolbarContent) { + tableToolbarContent.hasBatchActions = this._selectedRows.length; + } + } + + const totalRows = [...this._tableRows].filter( + (elem) => !elem.hasAttribute('filtered') + ).length; + + // selected header checkbox upon all rows being selected + const headerCheckbox = tableHeaderRow.shadowRoot + ?.querySelector(`${prefix}-checkbox`) + .shadowRoot.querySelector(`.${prefix}--checkbox`); + const allRowsSelected = this._selectedRows.length === totalRows; + headerCheckbox.checked = !this._selectedRows.length ? false : true; + headerCheckbox.indeterminate = + !allRowsSelected && this._selectedRows.length > 0; + + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + selectedRow: target, + selectedRows: selectedRows, + }, + }; + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSTable).eventTableRowSelect, + init + ) + ); + }; + + /** + * Handles header row selection, selecting/unselecting all rows + */ + @HostListener('eventBeforeChangeSelectionAll') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleAllRowsSelect = async (event: CustomEvent) => { + const { detail, target } = event; + const { selected } = detail; + const { + _tableBatchActions: tableBatchActions, + _tableToolbarContent: tableToolbarContent, + _tableRows: tableRows, + } = this; + + if (!this.contains(target as CDSTableRow)) { + return; + } + + let totalRows = 0; + forEach(tableRows, (elem) => { + if (!(elem as CDSTableRow).filtered) { + (elem as CDSTableRow).selected = selected; + this.radio + ? (( + (elem as CDSTableRow).shadowRoot!.querySelector( + `${prefix}-radio-button` + ) as CDSRadioButton + ).checked = selected) + : null; + this._selectedRows.push(elem as CDSTableRow); + totalRows++; + + const { selectorTableExpandedRows } = this + .constructor as typeof CDSTable; + const { nextElementSibling } = elem; + + // selecting the expanded row as well + if (nextElementSibling?.matches(selectorTableExpandedRows)) { + (elem.nextElementSibling as CDSTableExpandedRow).selected = selected; + } + } + }); + + if (!selected) { + this._selectedRows = []; + } + + if (tableBatchActions) { + tableBatchActions.selectedRowsCount = selected ? totalRows : 0; + tableBatchActions.active = selected; + } + + if (tableToolbarContent) { + tableToolbarContent.hasBatchActions = selected; + } + + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + selectedRows: this._selectedRows, + }, + }; + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSTable).eventTableRowSelectAll, + init + ) + ); + }; + + /** + * Handles cancel button within the toolbar actions + */ + @HostListener('eventClickCancel') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleCancelSelection = async (event: CustomEvent) => { + const { target } = event; + const { _tableHeaderRow: tableHeaderRow } = this; + + if (this.contains(target as CDSTableBatchActions)) { + tableHeaderRow.shadowRoot + ?.querySelector(`${prefix}-checkbox`) + .shadowRoot.querySelector(`.${prefix}--checkbox`) + .click(); + } + }; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'table'); + } + super.connectedCallback(); + } + + firstUpdated() { + this._tableBatchActions = this.querySelector( + (this.constructor as typeof CDSTable).selectorTableBatchActions + ); + this._tableToolbar = this.querySelector( + (this.constructor as typeof CDSTable).selectorTableToolbar + ); + this._tableToolbarContent = this.querySelector( + (this.constructor as typeof CDSTable).selectorTableToolbarContent + ); + this._tableBody = this.querySelector( + (this.constructor as typeof CDSTable).selectorTableBody + ); + this._tableHeaderRow = this.querySelector( + (this.constructor as typeof CDSTable).selectorRowsWithHeader + ); + this._tableExpandedRows = this.querySelectorAll( + (this.constructor as typeof CDSTable).selectorTableExpandedRows + ); + + this._tableRows = this.querySelectorAll( + (this.constructor as typeof CDSTable).selectorTableRow + ); + + this._downloadButton = this.querySelector( + (this.constructor as typeof CDSTable).selectorToolbarDownload + ); + if (this._downloadButton) { + this._downloadButton.onclick = this._handleDownload.bind(this); + } + this.headerCount = this._tableHeaderRow.children.length; + } + + updated(changedProperties) { + if (changedProperties.has('expandable')) { + this._tableRows.forEach((e, index) => { + e.expandable = this.expandable; + e.setAttribute('sort-id', index); + }); + this._tableHeaderRow.expandable = this.expandable; + this._tableHeaderRow.batchExpansion = this.batchExpansion; + this.headerCount += this.expandable ? 1 : -1; + } + + if (changedProperties.has('headerCount')) { + this._tableExpandedRows.forEach((e) => { + e.setAttribute('colspan', this.headerCount); + }); + } + + if (changedProperties.has('isSelectable')) { + if (this.isSelectable) { + this._tableHeaderRow.setAttribute('selection-name', 'header'); + this._tableRows.forEach((e, index) => { + if (!e.hasAttribute('selection-name')) { + e.setAttribute('selection-name', index); + } + }); + } + this.headerCount++; + } + + if (changedProperties.has('locale')) { + this.collator = new Intl.Collator(this.locale); + } + if (changedProperties.has('isSortable')) { + if (this.isSortable) { + this._enableSortAction(); + } + } + + if ( + changedProperties.has('overflowMenuOnHover') || + changedProperties.has('size') + ) { + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSTable).selectorTableCellOverflowMenu + ), + (elem) => { + const cell = elem.parentNode as CDSTableCell; + const row = cell.parentNode as CDSTableRow; + cell.overflowMenuOnHover = this.overflowMenuOnHover; + row.overflowMenuOnHover = this.overflowMenuOnHover; + cell.setAttribute('size', this.size); + elem.setAttribute('size', this.size); + elem.setAttribute('data-table', ''); + } + ); + } + + if (changedProperties.has('radio')) { + // Propagate `size` attribute to descendants until `:host-context()` gets supported in all major browsers + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSTable).selectorTableRow + ), + (elem) => { + (elem as CDSTableRow).radio = this.radio; + } + ); + } + + if (changedProperties.has('size')) { + // Propagate `size` attribute to descendants until `:host-context()` gets supported in all major browsers + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSTable).selectorAllRows + ), + (elem) => { + elem.setAttribute('size', this.size); + } + ); + this._tableToolbar?.setAttribute('size', this.size); + } + + // TODO: Uncomment when Carbon fully implements Sticky header feature + // if (changedProperties.has('stickyHeader')) { + // const tableBody = this.querySelector( + // (this.constructor as typeof CDSTable).selectorTableBody + // ); + // const tableHead = this.querySelector( + // (this.constructor as typeof CDSTable).selectorTableHead + // ); + // (tableBody as any).stickyHeader = this.stickyHeader; + // (tableHead as any).stickyHeader = this.stickyHeader; + // forEach( + // this.querySelectorAll( + // (this.constructor as typeof CDSTable).selectorRowsWithHeader + // ), + // (elem) => { + // (elem as any).stickyHeader = this.stickyHeader; + // } + // ); + // forEach( + // this.querySelectorAll( + // (this.constructor as typeof CDSTable).selectorTableCells + // ), + // (elem) => { + // (elem as any).stickyHeader = this.stickyHeader; + // } + // ); + // } + + if (changedProperties.has('useZebraStyles')) { + const tableBody = this.querySelector( + (this.constructor as typeof CDSTable).selectorTableBody + ); + (tableBody as any).useZebraStyles = this.useZebraStyles; + } + + if (this.withRowSlugs) { + this._tableHeaderRow.setAttribute('rows-with-slug', ''); + this._tableRows.forEach((row) => { + row.setAttribute('rows-with-slug', ''); + }); + } else { + this._tableHeaderRow.removeAttribute('rows-with-slug'); + this._tableRows.forEach((row) => { + row.removeAttribute('rows-with-slug'); + }); + } + + // Gets table header info to add to the column cells for styles + const headersWithSlug: number[] = []; + + Array.prototype.slice + .call(this._tableHeaderRow.children) + .forEach((headerCell, index) => { + if (headerCell.querySelector(`${prefix}-slug`)) { + headerCell.setAttribute('slug', ''); + headersWithSlug.push(index); + } else { + headerCell.removeAttribute('slug'); + } + }); + + this._tableRows.forEach((row) => { + Array.prototype.slice + .call((row as HTMLElement).children) + .forEach((cell, index) => { + headersWithSlug.includes(index) + ? cell.setAttribute('slug-in-header', '') + : cell.removeAttribute('slug-in-header'); + }); + }); + } + + /* eslint-disable no-constant-condition */ + render() { + return html` +
    +
    + + +
    + +
    + + ${false // TODO: replace with this.stickyHeader when feature is fully implemented + ? html`
    +
    + +
    +
    ` + : html``} + `; + } + + /** + * Adds isSortable value for table header cells. + */ + _enableSortAction() { + const headerCells = this.querySelectorAll( + (this.constructor as typeof CDSTable).selectorHeaderCell + ); + headerCells.forEach((e) => { + (e as CDSTableHeaderCell).isSortable = this.isSortable; + (e as CDSTableHeaderCell).isSelectable = this.isSelectable; + (e as CDSTableHeaderCell).isExpandable = this.expandable; + }); + const columns = [...this._tableHeaderRow.children]; + let sortDirection; + let columnIndex = 0; + columns.forEach((column, index) => { + if ( + column.hasAttribute('sort-direction') && + column.getAttribute('sort-direction') !== 'none' + ) { + sortDirection = column.getAttribute('sort-direction'); + columnIndex = index; + } + }); + + columns.forEach((e, index) => { + if (index !== columnIndex && this.isSortable) { + e.setAttribute('sort-direction', 'none'); + } else if (e.hasAttribute('is-sortable')) { + e.setAttribute('sort-direction', 'none'); + } + }); + this._handleSortAction(columnIndex, sortDirection); + } + + /* eslint-enable no-constant-condition */ + + /** + * The name of the custom event fired before a new sort direction is set upon a user gesture. + * Cancellation of this event stops the user-initiated change in sort direction. + */ + static get eventBeforeSort() { + return `${prefix}-table-header-cell-sort`; + } + + /** + * The name of the custom event fired during search bar input + */ + static get eventSearchInput() { + return `${prefix}-search-input`; + } + + /** + * The name of the custom event fired before header row is selected/unselected upon a user gesture. + */ + static get eventBeforeChangeSelectionAll() { + return `${prefix}-table-change-selection-all`; + } + + /** + * The name of the custom event fired before a row is selected/unselected upon a user gesture. + */ + static get eventBeforeChangeSelection() { + return `${prefix}-table-row-change-selection`; + } + + /** + * The name of the custom event fired after the Cancel button is clicked. + */ + static get eventClickCancel() { + return `${prefix}-table-batch-actions-cancel-clicked`; + } + + /** + * The name of the custom event fired after the expanded state a row is toggled upon a user gesture. + */ + static get eventExpandoToggle() { + return `${prefix}-table-row-expando-toggled`; + } + + /** + * The name of the custom event fired after a row has been selected + */ + static get eventTableRowSelect() { + return `${prefix}-table-row-selected`; + } + + /** + * The name of the custom event fired after all rows have been selected + */ + static get eventTableRowSelectAll() { + return `${prefix}-table-row-all-selected`; + } + + /** + * The name of the custom event fired after the table has been sorted + */ + static get eventTableSorted() { + return `${prefix}-table-sorted`; + } + + /** + * The name of the custom event fired after the table has been filtered containing remaining rows. + */ + static get eventTableFiltered() { + return `${prefix}-table-filtered`; + } + + /** + * The CSS selector to find the overflow menu on the table cell + */ + static get selectorTableCellOverflowMenu() { + return `${prefix}-table-cell ${prefix}-overflow-menu`; + } + + /** + * The CSS selector to find the download button + */ + static get selectorToolbarDownload() { + return `${prefix}-button[download]`; + } + + /** + * The CSS selector to find the table batch actions + */ + static get selectorTableBatchActions() { + return `${prefix}-table-batch-actions`; + } + + /** + * The CSS selector to find the table toolbar + */ + static get selectorTableToolbar() { + return `${prefix}-table-toolbar`; + } + + /** + * The CSS selector to find the table toolbar content + */ + static get selectorTableToolbarContent() { + return `${prefix}-table-toolbar-content`; + } + + /** + * The CSS selector to find the table toolbar search + */ + static get selectorTableToolbarSearch() { + return `${prefix}-table-toolbar-search`; + } + + /** + * The CSS selector to find the table head + */ + static get selectorTableHead() { + return `${prefix}-table-head`; + } + + /** + * The CSS selector to find the table body + */ + static get selectorTableBody() { + return `${prefix}-table-body`; + } + + /** + * The CSS selector to find the table expanded rows + */ + static get selectorTableExpandedRows() { + return `${prefix}-table-expanded-row`; + } + + /** + * The CSS selector to find the table rows + */ + static get selectorTableRow() { + return `${prefix}-table-row`; + } + + /** + * The CSS selector to find the rows cells. + */ + static get selectorTableRowCells() { + return `${prefix}-table-cell`; + } + + /** + * The CSS selector to find the rows cells, including header cells. + */ + static get selectorTableCells() { + return `${prefix}-table-cell, ${prefix}-table-header-cell`; + } + + /** + * The CSS selector to find the header cell + */ + static get selectorHeaderCell() { + return `${prefix}-table-header-cell`; + } + + /** + * The CSS selector to find the rows, including header rows. + */ + static get selectorRowsWithHeader() { + return `${prefix}-table-header-row,${prefix}-table-row`; + } + + /** + * The CSS selector to find all rows + */ + static get selectorAllRows() { + return `${prefix}-table-header-row,${prefix}-table-row,${prefix}-table-expanded-row`; + } + + static styles = styles; +} + +export default CDSTable; diff --git a/packages/web-components/src/components/date-picker/append-to-plugin.ts b/packages/web-components/src/components/date-picker/append-to-plugin.ts new file mode 100644 index 000000000000..e5ed4deb3b50 --- /dev/null +++ b/packages/web-components/src/components/date-picker/append-to-plugin.ts @@ -0,0 +1,64 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; +import { Plugin } from 'flatpickr/dist/types/options'; + +/** + * The configuration for the Flatpickr plugin to put the calendar dropdown in shadow DOM. + */ +export interface DatePickerAppendToPluginConfig { + /** + * The floating menu container. + */ + appendTo: HTMLElement; +} + +/** + * @param config Plugin configuration. + * @returns A Flatpickr plugin to put the calendar dropdown in shadow DOM. + */ +export default (config: DatePickerAppendToPluginConfig): Plugin => + (fp: FlatpickrInstance) => { + /** + * Adjusts the floating meun position after Flatpicker sets it. + */ + const handlePreCalendarPosition = async () => { + await Promise.resolve(); + const { + calendarContainer, + config: fpConfig, + _positionElement: positionElement, + } = fp; + const { appendTo } = fpConfig; + const { top: containerTop } = appendTo!.getBoundingClientRect(); + const { bottom: refBottom } = positionElement.getBoundingClientRect(); + const isRtl = + appendTo! + .ownerDocument!.defaultView!.getComputedStyle(appendTo!) + .getPropertyValue('direction') === 'rtl'; + calendarContainer.style.top = `${refBottom - containerTop}px`; + calendarContainer.style.left = !isRtl ? '0' : 'auto'; + calendarContainer.style.right = !isRtl ? 'auto' : '0'; + }; + + /** + * Registers this Flatpickr plugin. + * + */ + const register = () => { + fp.loadedPlugins.push('carbonFlatpickrAppendToPlugin'); + }; + + return { + appendTo: config.appendTo, + onReady: register, + onPreCalendarPosition: handlePreCalendarPosition, + }; + }; diff --git a/packages/web-components/src/components/date-picker/css-class-plugin.ts b/packages/web-components/src/components/date-picker/css-class-plugin.ts new file mode 100644 index 000000000000..1c643e75f4ac --- /dev/null +++ b/packages/web-components/src/components/date-picker/css-class-plugin.ts @@ -0,0 +1,167 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; +import { Plugin } from 'flatpickr/dist/types/options'; +import { forEach } from '../../globals/internal/collection-helpers'; + +/** + * The configuration for the Flatpickr plugin to set CSS classes specific to this design system. + */ +export interface DatePickerCSSClassPluginConfig { + /** + * The CSS class for the calendar dropdown. + */ + classCalendarContainer: string; + + /** + * The CSS class for the month navigator. + */ + classMonth: string; + + /** + * The CSS class for the container of the weekdays. + */ + classWeekdays: string; + + /** + * The CSS class for the container of the days. + */ + classDays: string; + + /** + * The CSS class applied to each weekdays. + */ + classWeekday: string; + + /** + * The CSS class applied to each days. + */ + classDay: string; + + /** + * The CSS class applied to the "today" highlight if there are any dates selected. + */ + classNoBorder: string; + + /** + * The CSS selector for Flatpickr's month navigator. + */ + selectorFlatpickrMonth: string; + + /** + * The CSS selector for Flatpickr's container of the weekdays. + */ + selectorFlatpickrWeekdays: string; + + /** + * The CSS selector for Flatpickr's container of the days. + */ + selectorFlatpickrDays: string; + + /** + * The CSS selector applied to Flatpickr's each weekdays. + */ + selectorFlatpickrWeekday: string; + + /** + * The CSS selector applied to Flatpickr's each days. + */ + selectorFlatpickrDay: string; + + /** + * The CSS class applied to Flatpickr's "today" highlight. + */ + classFlatpickrToday: string; +} + +/** + * @param config Plugin configuration. + * @returns A Flatpickr plugin to set CSS classes specific to this design system. + */ +export default (config: DatePickerCSSClassPluginConfig): Plugin => + (fp: FlatpickrInstance) => { + /** + * Adds class names specific to our design system to calendar dropdown. + */ + const ensureClassesInDatePicker = () => { + const { calendarContainer, selectedDates } = fp; + if (calendarContainer) { + const { + classCalendarContainer, + classMonth, + classWeekdays, + classDays, + classWeekday, + classDay, + classNoBorder, + selectorFlatpickrMonth, + selectorFlatpickrWeekdays, + selectorFlatpickrDays, + selectorFlatpickrWeekday, + selectorFlatpickrDay, + classFlatpickrToday, + } = config; + calendarContainer.classList.add(classCalendarContainer); + const month = calendarContainer.querySelector(selectorFlatpickrMonth); + if (month) { + month.classList.add(classMonth); + } + const weekdays = calendarContainer.querySelector( + selectorFlatpickrWeekdays + ); + if (weekdays) { + weekdays.classList.add(classWeekdays); + } + const days = calendarContainer.querySelector(selectorFlatpickrDays); + if (days) { + days.classList.add(classDays); + } + forEach( + calendarContainer.querySelectorAll(selectorFlatpickrWeekday), + (item) => { + item.innerHTML = item.innerHTML.replace(/\s+/g, ''); + item.classList.add(classWeekday); + } + ); + forEach( + calendarContainer.querySelectorAll(selectorFlatpickrDay), + (item) => { + item.classList.add(classDay); + if ( + item.classList.contains(classFlatpickrToday) && + selectedDates!.length > 0 + ) { + item.classList.add(classNoBorder); + } else if ( + item.classList.contains(classFlatpickrToday) && + selectedDates!.length === 0 + ) { + item.classList.remove(classNoBorder); + } + } + ); + } + }; + + /** + * Registers this Flatpickr plugin. + */ + const register = () => { + fp.loadedPlugins.push('carbonFlatpickrCSSClassPlugin'); + }; + + return { + onMonthChange: ensureClassesInDatePicker, + onYearChange: ensureClassesInDatePicker, + onValueUpdate: ensureClassesInDatePicker, + onOpen: ensureClassesInDatePicker, + onReady: [register], + }; + }; diff --git a/packages/web-components/src/components/date-picker/date-picker-input-skeleton.ts b/packages/web-components/src/components/date-picker/date-picker-input-skeleton.ts new file mode 100644 index 000000000000..109cee35432d --- /dev/null +++ b/packages/web-components/src/components/date-picker/date-picker-input-skeleton.ts @@ -0,0 +1,38 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { DATE_PICKER_INPUT_KIND } from './date-picker-input'; +import styles from './date-picker.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Skeleton version of the input box for date picker. + */ +@customElement(`${prefix}-date-picker-input-skeleton`) +class CDSDatePickerInputSkeleton extends LitElement { + /** + * Date picker input kind. Corresponds to the attribute with the same name. + */ + @property({ reflect: true }) + kind = DATE_PICKER_INPUT_KIND.SIMPLE; + + render() { + return html` + +
    + `; + } + + static styles = styles; +} + +export default CDSDatePickerInputSkeleton; diff --git a/packages/web-components/src/components/date-picker/date-picker-input.ts b/packages/web-components/src/components/date-picker/date-picker-input.ts new file mode 100644 index 000000000000..80f110da2703 --- /dev/null +++ b/packages/web-components/src/components/date-picker/date-picker-input.ts @@ -0,0 +1,375 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property, query, state } from 'lit/decorators.js'; +import Calendar16 from '@carbon/icons/lib/calendar/16'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import { INPUT_SIZE } from '../text-input/text-input'; +import { DATE_PICKER_INPUT_COLOR_SCHEME, DATE_PICKER_INPUT_KIND } from './defs'; +import WarningFilled16 from '@carbon/icons/lib/warning--filled/16'; +import WarningAltFilled16 from '@carbon/icons/lib/warning--alt--filled/16'; +import styles from './date-picker.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { DATE_PICKER_INPUT_COLOR_SCHEME, DATE_PICKER_INPUT_KIND }; + +/** + * The input box for date picker. + * + * @element cds-date-picker-input + */ +@customElement(`${prefix}-date-picker-input`) +class CDSDatePickerInput extends FocusMixin(LitElement) { + /** + * `true` if there is a slug. + */ + private _hasSlug = false; + + /** + * Handles `slotchange` event. + */ + protected _handleSlugSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSDatePickerInput).slugItem + ) + : false + ); + + this._hasSlug = Boolean(hasContent); + (hasContent[0] as HTMLElement).setAttribute('size', 'mini'); + this.requestUpdate(); + } + + /** + * The calendar icon. + */ + @query(`.${prefix}--date-picker__icon`) + private _iconNode!: SVGElement; + + /** + * Handles `click` event on the calendar icon. + * + * @param event The event. + */ + private _handleClickWrapper(event: MouseEvent) { + if (event.target === this._iconNode) { + this.input.focus(); + } + } + + /** + * Handles `input` event on `` in the shadow DOM. + * + * @param event The event. + * @param event.target The event target. + */ + private _handleInput({ target }: Event) { + const { value } = target as HTMLInputElement; + this.value = value; + } + + /** + * @returns The template for the the calendar icon. + */ + private _renderIcon() { + return this.kind === DATE_PICKER_INPUT_KIND.SIMPLE + ? undefined + : Calendar16({ + class: `${prefix}--date-picker__icon`, + role: 'img', + children: [html` Open calendar `], + }); + } + + /** + * `true` if there is helper text content. + */ + @state() + protected _hasHelperText = false; + + /** + * Handles `slotchange` event on the default ``. + */ + protected _handleSlotChange({ target }: Event) { + if (!(target as HTMLSlotElement).name) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .some( + (node) => + node.nodeType !== Node.TEXT_NODE || node!.textContent!.trim() + ); + this._hasHelperText = hasContent; + } + } + + /** + * The ``, used for Flatpickr to grab. + */ + @query('input') + input!: HTMLInputElement; + + /** + * The color scheme. + */ + @property({ attribute: 'color-scheme', reflect: true }) + colorScheme = DATE_PICKER_INPUT_COLOR_SCHEME.REGULAR; + + /** + * `true` if the check box should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * `true` if the label should be hidden. + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-label' }) + hideLabel = false; + + /** + * Specify whether the control is currently in warning state + */ + @property({ type: Boolean, reflect: true }) + warn = false; + + /** + * Provide the text that is displayed when the control is in warning state + */ + @property({ attribute: 'warn-text' }) + warnText = ''; + + /** + * Message which is displayed if the value is invalid. + */ + @property({ attribute: 'invalid-text' }) + invalidText = ''; + + /** + * Controls the invalid state and visibility of the `validityMessage`. + */ + @property({ type: Boolean, reflect: true }) + invalid = false; + + /** + * Date picker input kind. + */ + @property({ reflect: true }) + kind = DATE_PICKER_INPUT_KIND.SIMPLE; + + /** + * The label text. + */ + @property({ attribute: 'label-text' }) + labelText!: string; + + /** + * The `pattern` attribute for the `` in the shadow DOM. + */ + @property() + pattern!: string; + + /** + * The placeholder text. + */ + @property() + placeholder!: string; + + /** + * Specify if the component should be read-only + */ + @property({ type: Boolean, reflect: true }) + readonly = false; + + /** + * `true` if the value is required. + */ + @property({ type: Boolean, reflect: true }) + required = false; + + /** + * Vertical size of this date picker input. + */ + @property({ attribute: 'size', reflect: true }) + size = INPUT_SIZE.MEDIUM; + + /** + * true to use the short version. + */ + @property({ type: Boolean, reflect: true }) + short = false; + + /** + * The `type` attribute for the `` in the shadow DOM. + */ + @property() + type!: string; + + /** + * The value. + */ + @property() + value!: string; + + render() { + const constructor = this.constructor as typeof CDSDatePickerInput; + const { + disabled, + _hasHelperText: hasHelperText, + hideLabel, + invalid, + invalidText, + labelText, + pattern = constructor.defaultPattern, + placeholder, + readonly, + size, + type = constructor.defaultType, + value, + warn, + warnText, + _handleClickWrapper: handleClickWrapper, + _handleInput: handleInput, + _hasSlug: hasSlug, + } = this; + + const invalidIcon = WarningFilled16({ + class: `${prefix}--date-picker__icon ${prefix}--date-picker__icon--invalid`, + }); + + const warnIcon = WarningAltFilled16({ + class: `${prefix}--date-picker__icon ${prefix}--date-picker__icon--warn`, + }); + + const normalizedProps = { + disabled: !readonly && disabled, + invalid: !readonly && invalid, + warn: !readonly && !invalid && warn, + 'slot-name': '', + 'slot-text': '', + icon: null, + }; + + if (normalizedProps.invalid) { + normalizedProps.icon = invalidIcon; + normalizedProps['slot-name'] = 'invalid-text'; + normalizedProps['slot-text'] = invalidText; + } else if (normalizedProps.warn) { + normalizedProps.icon = warnIcon; + normalizedProps['slot-name'] = 'warn-text'; + normalizedProps['slot-text'] = warnText; + } + + const labelClasses = classMap({ + [`${prefix}--label`]: true, + [`${prefix}--visually-hidden`]: hideLabel, + [`${prefix}--label--disabled`]: disabled, + }); + const inputClasses = classMap({ + [`${prefix}--date-picker__input`]: true, + [`${prefix}--date-picker__input--invalid`]: normalizedProps.invalid, + [`${prefix}--date-picker__input--warn`]: normalizedProps.warn, + [`${prefix}--date-picker__input--${size}`]: size, + }); + + const inputWrapperClasses = classMap({ + [`${prefix}--date-picker-input__wrapper`]: true, + [`${prefix}--date-picker-input__wrapper--invalid`]: + normalizedProps.invalid, + [`${prefix}--date-picker-input__wrapper--warn`]: normalizedProps.warn, + [`${prefix}--date-picker-input__wrapper--slug`]: hasSlug, + }); + + const helperTextClasses = classMap({ + [`${prefix}--form__helper-text`]: true, + [`${prefix}--form__helper-text--disabled`]: disabled, + }); + + return html` + +
    + + + ${normalizedProps.icon || this._renderIcon()} + + +
    +
    + + ${normalizedProps['slot-text']} + +
    +
    + +
    + `; + } + + updated() { + this.shadowRoot + ?.querySelector("slot[name='slug']") + ?.classList.toggle( + `${prefix}--slug--revert`, + this.querySelector(`${prefix}-slug`)?.hasAttribute('revert-active') + ); + } + + /** + * The default value for `pattern` property. + */ + static defaultPattern = '\\d{1,2}\\/\\d{1,2}\\/\\d{4}'; + + /** + * The default value for `type` property. + */ + static defaultType = 'text'; + + /** + * A selector that will return the parent date picker. + */ + static get selectorParent() { + return `${prefix}-date-picker`; + } + + /** + * A selector that will return the slug item. + */ + static get slugItem() { + return `${prefix}-slug`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; +} + +export default CDSDatePickerInput; diff --git a/packages/web-components/src/components/date-picker/date-picker.mdx b/packages/web-components/src/components/date-picker/date-picker.mdx new file mode 100644 index 000000000000..c14dc8501e1d --- /dev/null +++ b/packages/web-components/src/components/date-picker/date-picker.mdx @@ -0,0 +1,116 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as DatePickerStories from './date-picker.stories'; + + + +# Date picker + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/date-picker) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/date-picker) + +Date and time pickers allow users to select a single or a range of dates and +times. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/date-picker/index.js'; +``` + +{`${cdnJs({ components: ['date-picker'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + + + +``` + +## Single date picker + +A single Date Picker consists of an input field and a calendar. + +```html + + + + +``` + +## Range date picker + +A range Date Picker consists of two input fields and a calendar. + +```html + + + + + + +``` + +## Skeleton + +For the skeleton variation, utilize ``. + +### Simple + +```html + +``` + +### Single + +```html + +``` + +### Range + +```html +
    + + +
    +``` + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `open` attribute). + + + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `light` attribute). + + diff --git a/packages/web-components/src/components/date-picker/date-picker.scss b/packages/web-components/src/components/date-picker/date-picker.scss new file mode 100644 index 000000000000..a47ea39ec00a --- /dev/null +++ b/packages/web-components/src/components/date-picker/date-picker.scss @@ -0,0 +1,163 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/colors' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/components/form'; +@use '@carbon/styles/scss/components/date-picker/date-picker' as *; + +// https://github.com/carbon-design-system/carbon/issues/11408 +@include date-picker; + +:host(#{$prefix}-date-picker) { + @extend .#{$prefix}--date-picker; + + #floating-menu-container { + position: absolute; + inline-size: 100%; + } + + .#{$prefix}--date-picker__calendar.open { + margin-block-start: 0; + } + + .flatpickr-next-month, + .flatpickr-prev-month { + svg { + transform: rotate(0) #{'/*rtl:rotate(180deg)*/'}; + } + } + + // _date-picker.scss#L351-L360 in `v10.6.0` tree, coping with the CSS class that latest Flatpickr has + .#{$prefix}--date-picker__day.flatpickr-disabled, + .flatpickr-day.flatpickr-disabled { + color: $layer-selected-inverse; + cursor: not-allowed; + opacity: 0.5; + + &:hover { + background: transparent; + } + } + + // _date-picker.scss#L455-L468 in `v10.6.0` tree, coping with the CSS class that latest Flatpickr has + .flatpickr-next-month.flatpickr-disabled, + .flatpickr-prev-month.flatpickr-disabled { + svg { + cursor: not-allowed; + fill: $layer-selected-inverse; + opacity: 0.5; + } + + &:hover { + svg { + fill: $layer-selected-inverse; + } + } + } +} + +:host(#{$prefix}-date-picker-input), +:host(#{$prefix}-date-picker-input-skeleton) { + @extend .#{$prefix}--date-picker-container; + + outline: none; + + .#{$prefix}--form-requirement[hidden] { + display: none; + } +} +:host(#{$prefix}-date-picker-input[warn]) { + .#{$prefix}--form-requirement { + color: $text-primary; + } +} + +:host(#{$prefix}-date-picker-input[kind='simple']), +:host(#{$prefix}-date-picker-input-skeleton[kind='simple']) { + .#{$prefix}--date-picker__input { + inline-size: rem(120px); + } + + .#{$prefix}--date-picker__input--invalid, + .#{$prefix}--date-picker__input--warn { + inline-size: rem(152px); + } +} + +:host(#{$prefix}-date-picker-input[kind='simple'][short]), +:host(#{$prefix}-date-picker-input-skeleton[kind='simple'][short]) { + .#{$prefix}--date-picker__input { + inline-size: rem(90px); + } +} + +:host(#{$prefix}-date-picker-input[kind='single']), +:host(#{$prefix}-date-picker-input-skeleton[kind='single']) { + max-inline-size: rem(288px); + + .#{$prefix}--date-picker__input { + inline-size: rem(288px); + } +} + +:host(#{$prefix}-date-picker-input[kind='from']), +:host(#{$prefix}-date-picker-input-skeleton[kind='from']) { + margin-inline-end: rem(1px); +} + +:host(#{$prefix}-date-picker-input[kind='from']), +:host(#{$prefix}-date-picker-input[kind='to']), +:host(#{$prefix}-date-picker-input-skeleton[kind='from']), +:host(#{$prefix}-date-picker-input-skeleton[kind='to']) { + inline-size: rem(143.5px); + + .#{$prefix}--date-picker__input { + inline-size: rem(143.5px); + } +} + +:host(#{$prefix}-date-picker-input) { + .#{$prefix}--date-picker__icon { + @extend .#{$prefix}--date-picker__icon; + } + + .#{$prefix}--date-picker__icon--warn { + @extend .#{$prefix}--date-picker__icon--warn; + } + + .#{$prefix}--date-picker__icon--invalid { + @extend .#{$prefix}--date-picker__icon--invalid; + } + + ::slotted(#{$prefix}-slug) { + position: absolute; + inset-block-start: 50%; + inset-inline-end: $spacing-08; + } + + ::slotted(#{$prefix}-slug:not([revert-active])) { + transform: translateY(-50%); + } +} + +:host(#{$prefix}-date-picker-input-skeleton) { + display: inline-block; + + .#{$prefix}--label { + @include skeleton; + + block-size: rem(14px); + + inline-size: rem(75px); + } +} diff --git a/packages/web-components/src/components/date-picker/date-picker.stories.ts b/packages/web-components/src/components/date-picker/date-picker.stories.ts new file mode 100644 index 000000000000..bdcbcd46552e --- /dev/null +++ b/packages/web-components/src/components/date-picker/date-picker.stories.ts @@ -0,0 +1,352 @@ +/** + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../globals/settings'; +import { INPUT_SIZE } from '../text-input/text-input'; +import './date-picker'; +import './date-picker-input-skeleton'; +import '../layer/index'; +import '../../../.storybook/templates/with-layer'; + +const sizes = { + [`Small (${INPUT_SIZE.SMALL})`]: INPUT_SIZE.SMALL, + [`Medium (${INPUT_SIZE.MEDIUM})`]: INPUT_SIZE.MEDIUM, + [`Large (${INPUT_SIZE.LARGE})`]: INPUT_SIZE.LARGE, +}; + +const defaultArgs = { + dateFormat: 'm/d/Y', + disabled: false, + allowInput: true, + closeOnSelect: true, + minDate: '', + maxDate: '', + datePickerType: 'single', + readonly: false, + short: false, + helperText: '', + warning: false, + warningText: '', + invalid: false, + invalidText: '', + placeholder: 'mm/dd/yyyy', + size: INPUT_SIZE.MEDIUM, +}; + +const argTypes = { + allowInput: { + control: 'boolean', + description: + 'Flatpickr prop passthrough enables direct date input, and when set to false, we must clear dates manually by resetting the value prop to empty string making it a controlled input.', + }, + closeOnSelect: { + control: 'boolean', + description: + 'Flatpickr prop passthrough. Controls whether the calendar dropdown closes upon selection.', + }, + dateFormat: { + control: 'text', + description: 'The date format.', + }, + datePickerType: { + control: 'radio', + options: { Single: 'single', Simple: 'simple', Range: 'range' }, + description: `The type of the date picker: +
      +
    • simple +
      • Without calendar dropdown.
      +
    • +
    • single +
      • With calendar dropdown and single date.
      +
    • +
    • range +
      • With calendar dropdown and a date range.
      +
    • +
    `, + }, + disabled: { control: 'boolean' }, + helperText: { control: 'text' }, + invalid: { + control: 'boolean', + description: 'Specify whether or not the control is invalid (Fluid only).', + }, + invalidText: { + control: 'text', + description: + 'Provide the text that is displayed when the control is in error state (Fluid Only).', + }, + maxDate: { + control: 'text', + description: 'The maximum date that a user can pick to.', + }, + minDate: { + control: 'text', + description: 'The minimum date that a user can start picking from.', + }, + placeholder: { control: 'text' }, + readonly: { + control: 'boolean', + description: + 'Whether the DatePicker is to be readOnly if boolean applies to all inputs if array applies to each input in order.', + }, + short: { + control: 'boolean', + description: 'true to use the short version.', + }, + size: { control: 'select', options: sizes }, + warning: { + control: 'boolean', + description: + 'Specify whether the control is currently in warning state (Fluid only).', + }, + warningText: { + control: 'text', + description: + 'Provide the text that is displayed when the control is in warning state (Fluid only).', + }, + onChange: { + action: `${prefix}-date-picker-changed`, + }, + onInput: { + action: 'input', + }, +}; + +export const Simple = { + render: () => { + return html` + + + + + `; + }, +}; + +export const SimpleWithLayer = { + render: () => { + return html` + + + + + + `; + }, +}; + +export const SingleWithCalendar = { + render: () => { + return html` + + + + + `; + }, +}; + +export const SingleWithCalendarWithLayer = { + render: () => { + return html` + + + + + + + `; + }, +}; + +export const RangeWithCalendar = { + render: () => { + return html` + + + + + + + `; + }, +}; + +export const RangeWithCalendarWithLayer = { + render: () => { + return html` + + + + + + + + + + + + + + + + + + + + + + + + + `; + }, +}; + +export const Skeleton = { + render: () => + html` + + + `, + decorators: [(story) => html`
    ${story()}
    `], + parameters: { + percy: { + skip: true, + }, + }, +}; + +export const Playground = { + decorators: [(story) => html`
    ${story()}
    `], + argTypes, + args: defaultArgs, + render: (args) => { + const { + disabled, + dateFormat, + onChange, + minDate, + maxDate, + size, + helperText, + placeholder, + invalid, + invalidText, + warning, + warningText, + short, + datePickerType, + readonly, + onInput, + } = args || {}; + + return html` + + ${datePickerType === 'range' + ? html` + + ${helperText + ? html`${helperText}` + : html``} + + + ${helperText + ? html`${helperText}` + : html``} + + ` + : html` + + ${helperText + ? html`${helperText}` + : html``} + + `} + + `; + }, +}; + +const meta = { + title: 'Components/Date picker', +}; + +export default meta; diff --git a/packages/web-components/src/components/date-picker/date-picker.ts b/packages/web-components/src/components/date-picker/date-picker.ts new file mode 100644 index 000000000000..bb126d59ea6c --- /dev/null +++ b/packages/web-components/src/components/date-picker/date-picker.ts @@ -0,0 +1,644 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import flatpickr from 'flatpickr'; +import { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; +import { Locale as FlatpickrLocale } from 'flatpickr/dist/types/locale'; +import { + Options as FlatpickrOptions, + Plugin as FlatpickrPlugin, +} from 'flatpickr/dist/types/options'; +import { prefix } from '../../globals/settings'; +import FormMixin from '../../globals/mixins/form'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import HostListener from '../../globals/decorators/host-listener'; +import { getISODateString, parseISODateString } from './iso-date'; +import CDSDatePickerInput from './date-picker-input'; +import appendToPlugin from './append-to-plugin'; +import cssClassPlugin from './css-class-plugin'; +import fixEventsPlugin from './fix-events-plugin'; +import focusPlugin from './focus-plugin'; +import iconPlugin from './icon-plugin'; +import monthSelectPlugin from './month-select-plugin'; +import rangePlugin from './range-plugin'; +import shadowDOMEventPlugin from './shadow-dom-events-plugin'; +import stateHandshakePlugin from './state-handshake-plugin'; +import styles from './date-picker.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Date picker modes. + */ +enum DATE_PICKER_MODE { + /** + * Simple mode, without calendar dropdown. + */ + SIMPLE = 'simple', + + /** + * Single date mode. + */ + SINGLE = 'single', + + /** + * Range mode. + */ + RANGE = 'range', +} + +// Weekdays shorthand for english locale +flatpickr!.l10ns!.en!.weekdays.shorthand.forEach((_day, index) => { + const currentDay = flatpickr!.l10ns!.en!.weekdays.shorthand; + if (currentDay[index] === 'Thu' || currentDay[index] === 'Th') { + currentDay[index] = 'Th'; + } else { + currentDay[index] = currentDay[index].charAt(0); + } +}); + +/** + * Date picker. + * + * @element cds-date-picker + * @fires cds-date-picker-changed - The custom event fired on this element when Flatpickr updates its value. + * @fires cds-date-picker-flatpickr-error + * The name of the custom event when Flatpickr throws an error. + */ +@customElement(`${prefix}-date-picker`) +class CDSDatePicker extends HostListenerMixin(FormMixin(LitElement)) { + /** + * The slotted ``. + */ + private _dateInteractNode: CDSDatePickerInput | null = null; + + /** + * The element to put calendar dropdown in. + */ + @query('#floating-menu-container') + private _floatingMenuContainerNode!: HTMLDivElement; + + /** + * The internal placeholder for the `value` property. + */ + private _value!: string; + + /** + * @returns The effective date picker mode, determined by the child ``. + */ + private get _mode() { + const { selectorInputFrom, selectorInputTo } = this + .constructor as typeof CDSDatePicker; + if (this.querySelector(selectorInputTo)) { + return DATE_PICKER_MODE.RANGE; + } + if (this.querySelector(selectorInputFrom)) { + return DATE_PICKER_MODE.SINGLE; + } + return DATE_PICKER_MODE.SIMPLE; + } + + /** + * @returns The Flatpickr plugins to use. + */ + private get _datePickerPlugins(): FlatpickrPlugin[] { + const { + classCalendarContainer, + classMonth, + classWeekdays, + classDays, + classWeekday, + classDay, + classNoBorder, + selectorInputFrom, + selectorInputTo, + _selectorFlatpickrMonthYearContainer: selectorFlatpickrMonthYearContainer, + _selectorFlatpickrYearContainer: selectorFlatpickrYearContainer, + _selectorFlatpickrCurrentMonth: selectorFlatpickrCurrentMonth, + _selectorFlatpickrMonth: selectorFlatpickrMonth, + _selectorFlatpickrWeekdays: selectorFlatpickrWeekdays, + _selectorFlatpickrDays: selectorFlatpickrDays, + _selectorFlatpickrWeekday: selectorFlatpickrWeekday, + _selectorFlatpickrDay: selectorFlatpickrDay, + _classFlatpickrCurrentMonth: classFlatpickrCurrentMonth, + _classFlatpickrToday: classFlatpickrToday, + } = this.constructor as typeof CDSDatePicker; + const { + _floatingMenuContainerNode: floatingMenuContainerNode, + _mode: mode, + } = this; + const inputFrom = this.querySelector(selectorInputFrom); + const inputTo = this.querySelector(selectorInputTo); + const plugins = [ + appendToPlugin({ appendTo: floatingMenuContainerNode }), + cssClassPlugin({ + classCalendarContainer, + classMonth, + classWeekdays, + classDays, + classWeekday, + classDay, + classNoBorder, + selectorFlatpickrMonth, + selectorFlatpickrWeekdays, + selectorFlatpickrDays, + selectorFlatpickrWeekday, + selectorFlatpickrDay, + classFlatpickrToday, + }), + fixEventsPlugin({ + inputFrom: inputFrom as CDSDatePickerInput, + inputTo: inputTo as CDSDatePickerInput, + }), + focusPlugin({ + inputFrom: inputFrom as CDSDatePickerInput, + inputTo: inputTo as CDSDatePickerInput, + }), + iconPlugin(), + monthSelectPlugin({ + selectorFlatpickrMonthYearContainer, + selectorFlatpickrYearContainer, + selectorFlatpickrCurrentMonth, + classFlatpickrCurrentMonth, + }), + shadowDOMEventPlugin(), + stateHandshakePlugin(this), + ]; + if (mode === DATE_PICKER_MODE.RANGE) { + // Flatpickr runs event handlers of last registered plugins first. + // Ensures `onValueUpdate` of `rangePlugin` runs first + // given Flatpickr puts `01/01/1970 to 01/02/1970` to from date + // where `rangePlugin` overrides it to separate them to from/to dates. + // We want to ensure our handler of `onValueUpdate` (notably one in ``) + // gets the `` value set by `rangePlugin` instead of Flatpickr core. + plugins.push(rangePlugin({ input: inputTo as HTMLInputElement })); + } + return plugins; + } + + /** + * @returns The options to instantiate Flatpickr with. + */ + private get _datePickerOptions(): FlatpickrOptions { + const { + locale = (this.constructor as typeof CDSDatePicker).defaultLocale, + enabledRange, + _dateInteractNode: dateInteractNode, + _datePickerPlugins: plugins, + _handleFlatpickrError: handleFlatpickrError, + } = this; + // We use `` to communicate values/events with Flatpickr, + // but want to use `` in shadow DOM to base the calendar dropdown's position on + const { input: positionElement } = dateInteractNode!; + const [minDate = undefined, maxDate = undefined] = !enabledRange + ? [] + : enabledRange.split('/'); + return { + allowInput: this.allowInput, + closeOnSelect: this.closeOnSelect, + dateFormat: + this.dateFormat ?? + (this.constructor as typeof CDSDatePicker).defaultDateFormat, + disableMobile: true, + errorHandler: handleFlatpickrError, + locale, + maxDate, + minDate, + positionElement, + plugins, + }; + } + + /** + * Handles `${prefix}-date-picker-changed` event on this element. + */ + @HostListener('eventChange') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleChange = ({ detail }: CustomEvent) => { + this._value = detail.selectedDates + .map((date) => getISODateString(date)) + .join('/'); + }; + + _handleFormdata(event: Event) { + const { formData } = event as any; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const { disabled, name, value } = this; + if (!disabled) { + formData.append(name, value); + } + } + + /** + * Handles `slotchange` event in the ``. + */ + private _handleSlotChange({ target }: Event) { + const { _dateInteractNode: oldDateInteractNode } = this; + const dateInteractNode = (target as HTMLSlotElement) + .assignedNodes() + .find( + (node) => + node.nodeType === Node.ELEMENT_NODE && + (node as HTMLElement).matches( + (this.constructor as typeof CDSDatePicker).selectorInputFrom + ) + ); + if (oldDateInteractNode !== dateInteractNode) { + this._dateInteractNode = dateInteractNode as CDSDatePickerInput; + this._instantiateDatePicker(); + } + } + + /** + * Fires a custom event to notify an error in Flatpickr. + */ + private _handleFlatpickrError = (error: Error) => { + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSDatePicker).eventFlatpickrError, + { + bubbles: true, + cancelable: false, + composed: true, + detail: { + error, + }, + } + ) + ); + }; + + /** + * Instantiates Flatpickr. + * + * @returns The Flatpickr instance. + */ + private _instantiateDatePicker() { + this._releaseDatePicker(); + const { _dateInteractNode: dateInteractNode } = this; + // `this._dateInteractNode` won't be there unless there is a slotted ``, + // which means Flatpickr will never be instantiated in "simple" mode. + if (dateInteractNode && dateInteractNode.input) { + this.calendar = flatpickr( + dateInteractNode as any, + this._datePickerOptions + ); + } + return this.calendar; + } + + /** + * Releases Flatpickr instances. + */ + private _releaseDatePicker() { + if (this.calendar) { + this.calendar.destroy(); + this.calendar = null; + } + return this.calendar; + } + + /** + * The Flatpickr instance. + */ + calendar: FlatpickrInstance | null = null; + + /** + * flatpickr prop passthrough. Allows the user to enter a date directly into the input field + */ + @property({ type: Boolean, reflect: true, attribute: 'allow-input' }) + allowInput = true; + + /** + * flatpickr prop passthrough. Controls whether the calendar dropdown closes upon selection. + */ + @property({ type: Boolean, reflect: true, attribute: 'close-on-select' }) + closeOnSelect = true; + + /** + * The date format to let Flatpickr use. + */ + @property({ attribute: 'date-format' }) + dateFormat!: string; + + /** + * Controls the disabled state of the input + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * The localization data. + */ + @property({ attribute: false }) + locale!: FlatpickrLocale; + + /** + * The date range that a user can pick in calendar dropdown. + */ + @property({ attribute: 'enabled-range' }) + enabledRange!: string; + + /** + * The minimum date that a user can start picking from. + */ + @property({ attribute: 'min-date' }) + minDate!: string; + + /** + * The maximum date that a user can start picking from. + */ + @property({ attribute: 'max-date' }) + maxDate!: string; + + /** + * Name for the input in the `FormData` + */ + @property() + name = ''; + + /** + * `true` if the date picker should be open. + */ + @property({ type: Boolean, reflect: true }) + open = false; + + /** + * Specify if the component should be read-only + */ + @property({ type: Boolean, reflect: true }) + readonly = false; + + /** + * The date(s) in ISO8601 format (date portion only), for range mode, '/' is used for separate start/end dates. + */ + @property() + get value() { + return this._value; + } + + set value(value: string) { + const { _value: oldValue } = this; + this._value = value; + this.requestUpdate('value', oldValue); + } + + connectedCallback() { + super.connectedCallback(); + this._instantiateDatePicker(); + } + + disconnectedCallback() { + this._releaseDatePicker(); + super.disconnectedCallback(); + } + + updated(changedProperties) { + const { calendar, disabled, open, readonly } = this; + const { selectorInputFrom, selectorInputTo } = this + .constructor as typeof CDSDatePicker; + const inputFrom = this.querySelector( + selectorInputFrom + ) as CDSDatePickerInput; + const inputTo = this.querySelector(selectorInputTo) as CDSDatePickerInput; + if (calendar && changedProperties.has('dateFormat')) { + const { dateFormat } = this; + calendar.set({ dateFormat }); + } + if (changedProperties.has('minDate') || changedProperties.has('maxDate')) { + const { minDate, maxDate } = this; + if (!parseISODateString(minDate)) { + // Allows empty start/end + throw new Error( + `Wrong date format found in \`minDate\` property: ${minDate}` + ); + } + if (!parseISODateString(maxDate)) { + // Allows empty start/end + throw new Error( + `Wrong date format found in \`maxDate\` property: ${maxDate}` + ); + } + if (minDate && maxDate && minDate > maxDate) { + throw new Error( + `\`maxDate\` property, shouldn't be smaller than the \`minDate\` property. You have: minDate: ${minDate}, maxDate: ${maxDate}` + ); + } + if (calendar) { + calendar.set({ minDate, maxDate }); + } + } + + if (changedProperties.has('open') && calendar) { + if (open && !readonly) { + calendar.open(); + } else { + calendar.close(); + } + } + if ( + changedProperties.has('disabled') || + changedProperties.has('readonly') + ) { + [inputFrom, inputTo].forEach((input) => { + if (input) { + input.disabled = disabled; + input.readonly = readonly; + } + }); + } + if (changedProperties.has('value')) { + const { value } = this; + const dates = value + .split('/') + .filter(Boolean) + .map((item) => parseISODateString(item)); + if (dates.some((item) => isNaN(Number(item)))) { + throw new Error( + `Wrong date format found in \`value\` property: ${value}` + ); + } + const [startDate, endDate] = dates; + if (startDate && endDate && startDate > endDate) { + throw new Error( + `In \`value\` property, the end date shouldn't be smaller than the start date. You have: ${value}` + ); + } + if (calendar) { + calendar.setDate(dates); + [inputFrom, inputTo].forEach((input, i) => { + if (input) { + input.value = !dates[i] + ? '' + : calendar.formatDate( + new Date(dates[i]), + calendar.config.dateFormat + ); + } + }); + } + } + } + + render() { + const { _handleSlotChange: handleSlotChange } = this; + return html` + + +
    + + `; + } + + /** + * The CSS selector for Flatpickr's month/year portion. + */ + private static _selectorFlatpickrMonthYearContainer = + '.flatpickr-current-month'; + + /** + * The CSS selector for Flatpickr's year portion. + */ + private static _selectorFlatpickrYearContainer = '.numInputWrapper'; + + /** + * The CSS selector for the inner element of Flatpickr's month portion. + */ + private static _selectorFlatpickrCurrentMonth = '.cur-month'; + + /** + * The CSS selector for Flatpickr's month navigator. + */ + private static _selectorFlatpickrMonth = '.flatpickr-month'; + + /** + * The CSS selector for Flatpickr's container of the weekdays. + */ + private static _selectorFlatpickrWeekdays = '.flatpickr-weekdays'; + + /** + * The CSS selector for Flatpickr's container of the days. + */ + private static _selectorFlatpickrDays = '.flatpickr-days'; + + /** + * The CSS selector applied to Flatpickr's each weekdays. + */ + private static _selectorFlatpickrWeekday = '.flatpickr-weekday'; + + /** + * The CSS selector applied to Flatpickr's each days. + */ + private static _selectorFlatpickrDay = '.flatpickr-day'; + + /** + * The CSS class for the inner element of Flatpickr's month portion. + */ + private static _classFlatpickrCurrentMonth = 'cur-month'; + + /** + * The CSS class applied to Flatpickr's "today" highlight. + */ + private static _classFlatpickrToday = 'today'; + + /** + * The CSS class for the calendar dropdown. + */ + static get classCalendarContainer() { + return `${prefix}--date-picker__calendar`; + } + + /** + * The CSS class for the month navigator. + */ + static get classMonth() { + return `${prefix}--date-picker__month`; + } + + /** + * The CSS class for the container of the weekdays. + */ + static get classWeekdays() { + return `${prefix}--date-picker__weekdays`; + } + + /** + * The CSS class for the container of the days. + */ + static get classDays() { + return `${prefix}--date-picker__days`; + } + + /** + * The CSS class applied to each weekdays. + */ + static get classWeekday() { + return `${prefix}--date-picker__weekday`; + } + + /** + * The CSS class applied to each days. + */ + static get classDay() { + return `${prefix}--date-picker__day`; + } + + /** + * The CSS class applied to the "today" highlight if there are any dates selected. + */ + static classNoBorder = 'no-border'; + + /** + * The default date format. + */ + static defaultDateFormat = 'm/d/Y'; + + /** + * The default localization data. + */ + static defaultLocale = flatpickr.l10ns.default; + + /** + * A selector that will return the `` to enter starting date. + */ + static get selectorInputFrom() { + return `${prefix}-date-picker-input,${prefix}-date-picker-input[kind="from"]`; + } + + /** + * A selector that will return the `` to enter end date. + */ + static get selectorInputTo() { + return `${prefix}-date-picker-input[kind="to"]`; + } + + /** + * The name of the custom event when Flatpickr throws an error. + */ + static get eventFlatpickrError() { + return `${prefix}-date-picker-flatpickr-error`; + } + + /** + * The name of the custom event fired on this element when Flatpickr updates its value. + */ + static get eventChange() { + return `${prefix}-date-picker-changed`; + } + + static styles = styles; +} + +export default CDSDatePicker; diff --git a/packages/web-components/src/components/date-picker/defs.ts b/packages/web-components/src/components/date-picker/defs.ts new file mode 100644 index 000000000000..39a31df48697 --- /dev/null +++ b/packages/web-components/src/components/date-picker/defs.ts @@ -0,0 +1,35 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +export { FORM_ELEMENT_COLOR_SCHEME as DATE_PICKER_INPUT_COLOR_SCHEME } from '../../globals/shared-enums'; + +/** + * Date picker input kinds. + */ +export enum DATE_PICKER_INPUT_KIND { + /** + * One for simple variant of date picker, comes without the calendar dropdown. + */ + SIMPLE = 'simple', + + /** + * One for single variant of date picker. + */ + SINGLE = 'single', + + /** + * One for the start date for the range variant. + */ + FROM = 'from', + + /** + * One for the end date for the range variant. + */ + TO = 'to', +} diff --git a/packages/web-components/src/components/date-picker/docs/overview.mdx b/packages/web-components/src/components/date-picker/docs/overview.mdx new file mode 100644 index 000000000000..0593de9e002d --- /dev/null +++ b/packages/web-components/src/components/date-picker/docs/overview.mdx @@ -0,0 +1,20 @@ +## Live demo + + diff --git a/packages/web-components/src/components/date-picker/fix-events-plugin.ts b/packages/web-components/src/components/date-picker/fix-events-plugin.ts new file mode 100644 index 000000000000..69e459cb6751 --- /dev/null +++ b/packages/web-components/src/components/date-picker/fix-events-plugin.ts @@ -0,0 +1,133 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; +import { Plugin } from 'flatpickr/dist/types/options'; +import on from '../../globals/mixins/on'; +import Handle from '../../globals/internal/handle'; +import CDSDatePickerInput from './date-picker-input'; + +/** + * The configuration for the Flatpickr plugin to fix Flatpickr's behavior of certain events. + */ +export interface DatePickerFixEventsPluginConfig { + /** + * The input box to enter starting date. + */ + inputFrom: CDSDatePickerInput; + + /** + * The input box to enter end date. + */ + inputTo?: CDSDatePickerInput; +} + +/** + * `FlatpickrInstance` with additional properties used for `carbonFlatpickrFixEventsPlugin`. + */ +export interface ExtendedFlatpickrInstanceFixEventsPlugin + extends FlatpickrInstance { + /** + * The handle for `keydown` event handler in the `` for the starting date. + */ + _hCDSCEDatePickerFixEventsPluginKeydownFrom?: Handle | null; + + /** + * The handle for `keydown` event handler in the `` for the end date. + */ + _hCDSCEDatePickerFixEventsPluginKeydownTo?: Handle | null; +} + +/** + * @param config Plugin configuration. + * @returns A Flatpickr plugin to fix Flatpickr's behavior of certain events. + */ +export default (config: DatePickerFixEventsPluginConfig): Plugin => + (fp: ExtendedFlatpickrInstanceFixEventsPlugin) => { + /** + * Handles `keydown` event. + */ + const handleKeydown = (event: KeyboardEvent) => { + const { inputFrom, inputTo } = config; + const { key, target } = event; + if (inputFrom === target || inputTo === target) { + switch (key) { + case 'Enter': + // Makes sure the hitting enter key picks up pending values of both `` + // Workaround for: https://github.com/flatpickr/flatpickr/issues/1942 + fp.setDate( + [inputFrom.value!, (inputTo && inputTo.value)!], + true, + fp.config.dateFormat + ); + event.stopPropagation(); + break; + case 'ArrowLeft': + case 'Left': + case 'ArrowRight': + case 'Right': + // Prevents Flatpickr code from canceling the event if left/right arrow keys are hit on ``, + // so user can move the keyboard cursor for editing dates + // Workaround for: https://github.com/flatpickr/flatpickr/issues/1943 + event.stopPropagation(); + break; + default: + break; + } + } + }; + + /** + * Releases event listeners used in this Flatpickr plugin. + */ + const release = () => { + if (fp._hCDSCEDatePickerFixEventsPluginKeydownTo) { + fp._hCDSCEDatePickerFixEventsPluginKeydownTo = + fp._hCDSCEDatePickerFixEventsPluginKeydownTo.release(); + } + if (fp._hCDSCEDatePickerFixEventsPluginKeydownFrom) { + fp._hCDSCEDatePickerFixEventsPluginKeydownFrom = + fp._hCDSCEDatePickerFixEventsPluginKeydownFrom.release(); + } + }; + + /** + * Sets up event listeners used for this Flatpickr plugin. + */ + const init = () => { + release(); + const { inputFrom, inputTo } = config; + fp._hCDSCEDatePickerFixEventsPluginKeydownFrom = on( + inputFrom, + 'keydown', + handleKeydown, + true + ); + if (inputTo) { + fp._hCDSCEDatePickerFixEventsPluginKeydownTo = on( + inputTo, + 'keydown', + handleKeydown, + true + ); + } + }; + + /** + * Registers this Flatpickr plugin. + */ + const register = () => { + fp.loadedPlugins.push('carbonFlatpickrFixEventsPlugin'); + }; + + return { + onReady: [register, init], + onDestroy: [release], + }; + }; diff --git a/packages/web-components/src/components/date-picker/focus-plugin.ts b/packages/web-components/src/components/date-picker/focus-plugin.ts new file mode 100644 index 000000000000..07b88ee369c0 --- /dev/null +++ b/packages/web-components/src/components/date-picker/focus-plugin.ts @@ -0,0 +1,216 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; +import { Plugin } from 'flatpickr/dist/types/options'; +import on from '../../globals/mixins/on'; +import Handle from '../../globals/internal/handle'; +import CDSDatePickerInput from './date-picker-input'; + +/** + * The configuration for the Flatpickr plugin to set CSS classes specific to this design system. + */ +export interface DatePickerFocusPluginConfig { + /** + * The input box to enter starting date. + */ + inputFrom: CDSDatePickerInput; + + /** + * The input box to enter end date. + */ + inputTo?: CDSDatePickerInput; +} + +/** + * `FlatpickrInstance` with additional properties used for `carbonFlatpickrFocusPlugin`. + */ +export interface ExtendedFlatpickrInstanceFocusPlugin + extends FlatpickrInstance { + /** + * The handle for `blur` event handler in calendar dropdown. + */ + _hCDSCEDatePickerFocusPluginBlur?: Handle | null; + + /** + * The handle for `keydown` event handler in the `` for the starting date. + */ + _hCDSCEDatePickerFocusPluginKeydownFrom?: Handle | null; + + /** + * The handle for `keydown` event handler in the `` for the end date. + */ + _hCDSCEDatePickerFocusPluginKeydownTo?: Handle | null; + + /** + * The handle for `focus` event handler in the `` for the starting date. + */ + _hCDSCEDatePickerFocusPluginFocusFrom?: Handle | null; + + /** + * The handle for `focus` event handler in the `` for the end date. + */ + _hCDSCEDatePickerFocusPluginFocusTo?: Handle | null; + + /** + * Lastly focused `` for starting/end date. + */ + _lastFocusInput?: HTMLInputElement; +} + +/** + * @param config Plugin configuration. + * @returns A Flatpickr plugin to manage focus to align with the UX pattern in our design system. + */ +export default (config: DatePickerFocusPluginConfig): Plugin => + (fp: ExtendedFlatpickrInstanceFocusPlugin) => { + /** + * Focuses on calendar dropdown. + */ + const focusCalendar = () => { + const { calendarContainer, selectedDateElem, todayDateElem } = fp; + (selectedDateElem || todayDateElem || calendarContainer).focus(); + }; + + /** + * Handles `blur` event to move the focus back to the ``. + */ + const handleBlur = ({ target, relatedTarget }: FocusEvent) => { + // Obtains `beingUpdated` up-front because it'll be flushed out shortly + const { calendarContainer, isOpen } = fp; + if ( + isOpen && + calendarContainer.contains(target as Node) && + !calendarContainer.contains(relatedTarget as Node) && + relatedTarget !== config.inputFrom && + relatedTarget !== config.inputTo + ) { + Promise.resolve().then(() => { + const rootNode = (target as Node).getRootNode(); + // This `blur` event handler can be called from Flatpickr's code, + // cleaning up the calendar dropdowns DOM. Changing focus in such + // condition causes removing an orphaned DOM node, because Flatpickr + // redraws the calendar dropdown when the `` gets focus. + if ( + rootNode.nodeType === Node.DOCUMENT_NODE || + rootNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE + ) { + if (fp._lastFocusInput === config.inputTo) { + config.inputTo!.focus(); + } else { + config.inputFrom.focus(); + } + // Closing after moving focus. Reversing the order will cause re-opening calendar dropdown upon focusing + fp.close(); + } + }); + } + }; + + /** + * Handles `keydown` event to move focus on calendar dropdown. + */ + const handleInputKeydown = (event: KeyboardEvent) => { + const { key } = event; + if (key === 'ArrowDown' || key === 'Down' || key === 'Enter') { + event.preventDefault(); + fp.open(); + if (key !== 'Enter') { + focusCalendar(); + } else { + // Hitting Enter key blurs the ``, causing any element to lose focus + setTimeout(focusCalendar, 0); + } + } + }; + + /** + * Handles `focus` event on `` for starting/end date to track the lastly focused one. + */ + const handleInputFocus = ({ target }: FocusEvent) => { + fp._lastFocusInput = target as HTMLInputElement; + }; + + /** + * Releases event listeners used in this Flatpickr plugin. + */ + const release = () => { + if (fp._hCDSCEDatePickerFocusPluginBlur) { + fp._hCDSCEDatePickerFocusPluginBlur = + fp._hCDSCEDatePickerFocusPluginBlur.release(); + } + if (fp._hCDSCEDatePickerFocusPluginFocusTo) { + fp._hCDSCEDatePickerFocusPluginFocusTo = + fp._hCDSCEDatePickerFocusPluginFocusTo.release(); + } + if (fp._hCDSCEDatePickerFocusPluginFocusFrom) { + fp._hCDSCEDatePickerFocusPluginFocusFrom = + fp._hCDSCEDatePickerFocusPluginFocusFrom.release(); + } + if (fp._hCDSCEDatePickerFocusPluginKeydownTo) { + fp._hCDSCEDatePickerFocusPluginKeydownTo = + fp._hCDSCEDatePickerFocusPluginKeydownTo.release(); + } + if (fp._hCDSCEDatePickerFocusPluginKeydownFrom) { + fp._hCDSCEDatePickerFocusPluginKeydownFrom = + fp._hCDSCEDatePickerFocusPluginKeydownFrom.release(); + } + }; + + /** + * Sets up event listeners used for this Flatpickr plugin. + */ + const init = () => { + release(); + const { inputFrom, inputTo } = config; + fp._hCDSCEDatePickerFocusPluginBlur = on( + fp.calendarContainer, + 'blur', + handleBlur, + true + ); + fp._hCDSCEDatePickerFocusPluginKeydownFrom = on( + inputFrom, + 'keydown', + handleInputKeydown + ); + if (inputTo) { + fp._hCDSCEDatePickerFocusPluginKeydownTo = on( + inputTo, + 'keydown', + handleInputKeydown + ); + } + fp._hCDSCEDatePickerFocusPluginFocusFrom = on( + inputFrom, + 'focus', + handleInputFocus + ); + if (inputTo) { + fp._hCDSCEDatePickerFocusPluginFocusTo = on( + inputTo, + 'focus', + handleInputFocus + ); + } + }; + + /** + * Registers this Flatpickr plugin. + * + */ + const register = () => { + fp.loadedPlugins.push('carbonFlatpickrFocusPlugin'); + }; + + return { + onReady: [register, init], + onDestroy: release, + }; + }; diff --git a/packages/web-components/src/components/date-picker/icon-plugin.ts b/packages/web-components/src/components/date-picker/icon-plugin.ts new file mode 100644 index 000000000000..76fd78274522 --- /dev/null +++ b/packages/web-components/src/components/date-picker/icon-plugin.ts @@ -0,0 +1,50 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render } from 'lit'; +import { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; +import { Plugin } from 'flatpickr/dist/types/options'; +import ChevronLeft16 from '@carbon/icons/lib/chevron--left/16'; +import ChevronRight16 from '@carbon/icons/lib/chevron--right/16'; + +/** + * @returns A Flatpickr plugin to set the right icons in the design system. + */ +export default (): Plugin => (fp: FlatpickrInstance) => { + /** + * Sets the icon in the design system. + */ + const setIcon = () => { + const { prevMonthNav, nextMonthNav } = fp; + render(ChevronLeft16(), prevMonthNav); + render(ChevronRight16(), nextMonthNav); + }; + + /** + * Sets empty arrow icon contents as we render those icons after initialization. + */ + const parseConfig = () => { + const { config } = fp; + config.prevArrow = ''; + config.nextArrow = ''; + }; + + /** + * Registers this Flatpickr plugin. + * + */ + const register = () => { + fp.loadedPlugins.push('carbonFlatpickrIconPlugin'); + }; + + return { + onParseConfig: parseConfig, + onReady: [register, setIcon], + }; +}; diff --git a/packages/web-components/src/components/date-picker/index.ts b/packages/web-components/src/components/date-picker/index.ts new file mode 100644 index 000000000000..875a9e1dc0f8 --- /dev/null +++ b/packages/web-components/src/components/date-picker/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './date-picker'; +import './date-picker-input'; +import './date-picker-input-skeleton'; diff --git a/packages/web-components/src/components/date-picker/iso-date.ts b/packages/web-components/src/components/date-picker/iso-date.ts new file mode 100644 index 000000000000..28371f5ec2ce --- /dev/null +++ b/packages/web-components/src/components/date-picker/iso-date.ts @@ -0,0 +1,30 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @param date A date. + * @returns Date portion of the ISO8601 string of the given date, based on the local timezone. + */ +export const getISODateString = (date: Date) => + new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())) + .toISOString() + .split('T')[0]; + +/** + * @param s A date portion of an ISO8601 string, based on the local timezone. + * @returns The date object corresponding to the given ISO8601 string. + */ +export const parseISODateString = (s: string) => { + const utcDate = new Date(Date.parse(s)); + return new Date( + utcDate.getUTCFullYear(), + utcDate.getUTCMonth(), + utcDate.getUTCDate() + ); +}; diff --git a/packages/web-components/src/components/date-picker/month-select-plugin.ts b/packages/web-components/src/components/date-picker/month-select-plugin.ts new file mode 100644 index 000000000000..4e51acb33923 --- /dev/null +++ b/packages/web-components/src/components/date-picker/month-select-plugin.ts @@ -0,0 +1,154 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; +import { Locale } from 'flatpickr/dist/types/locale'; +import { Plugin } from 'flatpickr/dist/types/options'; +import { forEach } from '../../globals/internal/collection-helpers'; + +/** + * @param monthNumber The month number. + * @param shorthand `true` to use shorthand month. + * @param locale The Flatpickr locale data. + * @returns The month string. + */ +const monthToStr = (monthNumber: number, shorthand: boolean, locale: Locale) => + locale.months[shorthand ? 'shorthand' : 'longhand'][monthNumber]; + +/** + * The configuration for the Flatpickr plugin to use text instead of `` for month picker. + */ +export default (config: DatePickerMonthSelectPluginConfig): Plugin => + (fp: FlatpickrInstance) => { + /** + * Replaces `` for the starting date. + * Workaround for: https://github.com/flatpickr/flatpickr/issues/1944 + * Disables the logic in Flatpickr `rangePlugin` that calculates the new range with the old selected date + * when user selects a date from calendar dropdown. + * We'd like to reset the selection when user re-opens calendar dropdown and re-selects a date. + * Workaround for: https://github.com/flatpickr/flatpickr/issues/1958 + * Disables the logic in Flatpickr `rangePlugin` that closes the calendar dropdown + * when it's launched from the `` for the end date and user selects a date. + * Workaround for: https://github.com/flatpickr/flatpickr/issues/1958 + * Ensures that the `` in shadow DOM is treated as part of Flatpickr UI, + * by ensuring such `` hits `.contains()` search from `fp.config.ignoredFocusElements`. + * Without that, Flatpickr clears the `` when end date hasn't been selected yet (which we don't want). + */ +export default (config: Config): Plugin => { + const factory = rangePlugin({ position: 'left', ...config }); + return (fp: ExtendedFlatpickrInstanceRangePlugin) => { + const origRangePlugin = factory(fp); + const { onReady: origOnReady } = origRangePlugin; + + const getDateStrFromInputs = (dates: Array) => { + return dates + .filter((value) => value) + .filter( + (d, i, arr) => + fp.config.mode !== 'range' || + fp.config.enableTime || + arr.indexOf(d) === i + ) + .join( + fp.config.mode !== 'range' + ? fp.config.conjunction + : fp.l10n.rangeSeparator + ); + }; + + const handleBlur = (event: FocusEvent) => { + event.stopPropagation(); + const firstInput = fp._input; + const secondInput = config.input as HTMLInputElement; + const isInput = + event.target === firstInput || event.target === secondInput; + const valueChanged = + getDateStrFromInputs([firstInput.value, secondInput.value]) !== + fp.getDateStr(); + const relatedTargetIsCalendar = + event.relatedTarget && + event.relatedTarget instanceof Node && + fp.calendarContainer.contains(event.relatedTarget); + + if (isInput && valueChanged && !relatedTargetIsCalendar) { + fp.setDate( + [firstInput.value, secondInput.value], + true, + firstInput === fp.altInput + ? fp.config.altFormat + : fp.config.dateFormat + ); + } + }; + + const release = () => { + if (fp._hBXCEDatePickerRangePluginOnBlurFrom) { + fp._hBXCEDatePickerRangePluginOnBlurFrom = + fp._hBXCEDatePickerRangePluginOnBlurFrom.release(); + } + if (fp._hBXCEDatePickerRangePluginOnBlurTo) { + fp._hBXCEDatePickerRangePluginOnBlurTo = + fp._hBXCEDatePickerRangePluginOnBlurTo.release(); + } + }; + return Object.assign(origRangePlugin, { + onReady() { + origOnReady.call(this); + const { ignoredFocusElements } = fp.config; + ignoredFocusElements.push( + ...ignoredFocusElements + .map((elem) => elem.shadowRoot as any) + .filter(Boolean) + ); + + // Setup event listeners for the blur even on both inputs. In the case + // of the first input, we're overriding the blur event handler from + // the library to fix it by setting it on the capture phase and then + // stopping propagation. This is necessary b/c the library does not take + // the range plugin into consideration when it calls setDate. + // Workaround for: https://github.com/flatpickr/flatpickr/issues/2918 + release(); + if (fp.config.allowInput) { + fp._hBXCEDatePickerRangePluginOnBlurFrom = on( + fp._input, + 'blur', + handleBlur, + { capture: true } + ); + fp._hBXCEDatePickerRangePluginOnBlurTo = on( + config.input as HTMLInputElement, + 'blur', + handleBlur, + { capture: true } + ); + } + }, + }); + }; +}; diff --git a/packages/web-components/src/components/date-picker/shadow-dom-events-plugin.ts b/packages/web-components/src/components/date-picker/shadow-dom-events-plugin.ts new file mode 100644 index 000000000000..be39e57cc2c8 --- /dev/null +++ b/packages/web-components/src/components/date-picker/shadow-dom-events-plugin.ts @@ -0,0 +1,183 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; +import { Plugin } from 'flatpickr/dist/types/options'; +import on from '../../globals/mixins/on'; +import Handle from '../../globals/internal/handle'; +import { find } from '../../globals/internal/collection-helpers'; + +/** + * `FlatpickrInstance` with additional properties used for `carbonFlatpickrShadowDOMEventsPlugin`. + */ +export interface ExtendedFlatpickrInstanceShadowDOMEventsPlugin + extends FlatpickrInstance { + /** + * The handle for `keydown` event handler in calendar dropdown. + */ + _hCDSCEDatePickerShadowDOMEventsPluginKeydown?: Handle | null; +} + +/** + * The amount of days to adjust, keyed by the key code. + */ +const moveDateForKeys = { + ArrowLeft: -1, + Left: -1, + ArrowUp: -7, + Up: -7, + ArrowRight: 1, + Right: 1, + ArrowDown: 7, + Down: 7, +}; + +/** + * The amount of months to adjust, keyed by the key code. Used with Ctrl modifier key. + */ +const moveMonthForKeys = { + ArrowLeft: -1, + Left: -1, + ArrowUp: -12, + Up: -12, + ArrowRight: 1, + Right: 1, + ArrowDown: 12, + Down: 12, +}; + +/** + * The number of milliseconds per day. + */ +const MILLISECONDS_IN_DAY = 86400000; + +/** + * Adjusts the date with the given amount of days. + * + * @param localDate The original date. + * @param options The options. + * @param [options.date=0] The amount of days to adjust. + */ +const adjustDate = ( + localDate: Date, + { date: moveDate = 0 }: { date?: number } +) => { + const utcDate = new Date( + Date.UTC( + localDate.getFullYear(), + localDate.getMonth(), + localDate.getDate() + ) + + moveDate * MILLISECONDS_IN_DAY + ); + return new Date( + utcDate.getUTCFullYear(), + utcDate.getUTCMonth(), + utcDate.getUTCDate() + ); +}; + +/** + * @returns + * A Flatpickr plugin to handle events. + * Some event handlers in Flatpickr won't work is the calendar dropdown is put in shadow DOM, due to event retargetting. + */ +export default (): Plugin => + (fp: ExtendedFlatpickrInstanceShadowDOMEventsPlugin) => { + const getDateElem = (localDate) => + find( + fp.daysContainer!.firstElementChild!.children, + ({ dateObj }: any) => localDate.getTime() === dateObj.getTime() + ); + + /** + * Handles `keydown` event. + */ + const handleKeydown = (event: KeyboardEvent) => { + const { ctrlKey, key, target } = event; + if (key === 'Enter') { + target!.dispatchEvent( + Object.assign(new CustomEvent('mousedown', { bubbles: true }), { + which: 1, + }) + ); + } else if (!ctrlKey && key in moveDateForKeys) { + const { dateObj } = target as any; + const movedDate = adjustDate(dateObj, { date: moveDateForKeys[key] }); + const movedDateElem = getDateElem(movedDate); + if (movedDateElem) { + movedDateElem.focus(); + } else { + const innerDaysContainer = fp.daysContainer!.firstElementChild!; + if ( + movedDate.getTime() < + (innerDaysContainer.firstElementChild as any).dateObj.getTime() + ) { + fp.changeMonth(-1); + // `fp.daysContainer` is updated by `fp.changeMonth()` + ( + fp.daysContainer!.firstElementChild! + .lastElementChild as HTMLElement + ).focus(); + } else if ( + movedDate.getTime() > + (innerDaysContainer.lastElementChild as any).dateObj.getTime() + ) { + fp.changeMonth(1); + // `fp.daysContainer` is updated by `fp.changeMonth()` + ( + fp.daysContainer!.firstElementChild! + .firstElementChild as HTMLElement + ).focus(); + } + } + event.preventDefault(); + } else if (ctrlKey && key in moveMonthForKeys) { + fp.changeMonth(moveMonthForKeys[key]); + ( + fp.daysContainer!.firstElementChild!.firstElementChild as HTMLElement + ).focus(); + event.preventDefault(); + } + }; + + /** + * Releases event listeners used in this Flatpickr plugin. + */ + const release = () => { + if (fp._hCDSCEDatePickerShadowDOMEventsPluginKeydown) { + fp._hCDSCEDatePickerShadowDOMEventsPluginKeydown = + fp._hCDSCEDatePickerShadowDOMEventsPluginKeydown.release(); + } + }; + + /** + * Sets up event listeners used for this Flatpickr plugin. + */ + const init = () => { + release(); + fp._hCDSCEDatePickerShadowDOMEventsPluginKeydown = on( + fp.calendarContainer, + 'keydown', + handleKeydown + ); + }; + + /** + * Registers this Flatpickr plugin. + */ + const register = () => { + fp.loadedPlugins.push('carbonFlatpickrShadowDOMEventsPlugin'); + }; + + return { + onReady: [register, init], + onDestroy: [release], + }; + }; diff --git a/packages/web-components/src/components/date-picker/state-handshake-plugin.ts b/packages/web-components/src/components/date-picker/state-handshake-plugin.ts new file mode 100644 index 000000000000..d7f7b05a02ee --- /dev/null +++ b/packages/web-components/src/components/date-picker/state-handshake-plugin.ts @@ -0,0 +1,71 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { Instance as FlatpickrInstance } from 'flatpickr/dist/types/instance'; +import { Plugin } from 'flatpickr/dist/types/options'; +import CDSDatePicker from './date-picker'; + +/** + * @param datePicker Plugin configuration. + * @returns A Flatpickr plugin to handshake states with ``. + */ +export default (datePicker: CDSDatePicker): Plugin => + (fp: FlatpickrInstance) => { + /** + * Sets open state. + */ + const setOpen = () => { + datePicker.open = true; + }; + + /** + * Sets closed state. + */ + const setClosed = () => { + datePicker.open = false; + }; + + /** + * Propagates Flatpickr's `onChange` event to ``. + * + * @param selectedDates The latest selected dates. + */ + const handleChange = (selectedDates: Date[]) => { + const { eventChange } = datePicker.constructor as typeof CDSDatePicker; + datePicker.dispatchEvent( + new CustomEvent(eventChange, { + bubbles: true, + cancelable: true, + composed: true, + detail: { + selectedDates, + }, + }) + ); + }; + + /** + * Registers this Flatpickr plugin. + * + * @param _selectedDates The selected dates. + * @param _value The value. + * @param calendar The Flatpickr instance. + */ + const register = (_selectedDates, _value, calendar: FlatpickrInstance) => { + datePicker.calendar = calendar; + fp.loadedPlugins.push('carbonFlatpickrStateHandshakePlugin'); + }; + + return { + onOpen: setOpen, + onClose: setClosed, + onChange: handleChange, + onReady: [register], + }; + }; diff --git a/packages/web-components/src/components/dropdown/defs.ts b/packages/web-components/src/components/dropdown/defs.ts new file mode 100644 index 000000000000..51f68add7a41 --- /dev/null +++ b/packages/web-components/src/components/dropdown/defs.ts @@ -0,0 +1,95 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +export { FORM_ELEMENT_COLOR_SCHEME as DROPDOWN_COLOR_SCHEME } from '../../globals/shared-enums'; + +/** + * Navigation direction, associated with key symbols. + */ +export const NAVIGATION_DIRECTION = { + Up: -1, + ArrowUp: -1, + Down: 1, + ArrowDown: 1, +}; + +/** + * The keyboard action categories for dropdown. + */ +export enum DROPDOWN_KEYBOARD_ACTION { + /** + * Not doing any action. + */ + NONE = 'none', + + /** + * Keyboard action to close menu. + */ + CLOSING = 'closing', + + /** + * Keyboard action to navigate back/forward. + */ + NAVIGATING = 'navigating', + + /** + * Keyboard action to open/close menu on the trigger button or select/deselect a menu item. + */ + TRIGGERING = 'triggering', +} + +/** + * Dropdown size. + */ +export enum DROPDOWN_SIZE { + /** + * Small size. + */ + SMALL = 'sm', + + /** + * Medium size. + */ + MEDIUM = 'md', + + /** + * Large size. + */ + LARGE = 'lg', +} + +/** + * Dropdown types. + */ +export enum DROPDOWN_TYPE { + /** + * Default type. + */ + DEFAULT = '', + + /** + * Inline type. + */ + INLINE = 'inline', +} + +/** + * Dropdown direction. + */ +export enum DROPDOWN_DIRECTION { + /** + * Top. + */ + TOP = 'top', + + /** + * Bottom. + */ + BOTTOM = 'bottom', +} diff --git a/packages/web-components/src/components/dropdown/docs/overview.mdx b/packages/web-components/src/components/dropdown/docs/overview.mdx new file mode 100644 index 000000000000..9486132bc5cf --- /dev/null +++ b/packages/web-components/src/components/dropdown/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/dropdown/dropdown-item.ts b/packages/web-components/src/components/dropdown/dropdown-item.ts new file mode 100644 index 000000000000..cd373afeae76 --- /dev/null +++ b/packages/web-components/src/components/dropdown/dropdown-item.ts @@ -0,0 +1,101 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import Checkmark16 from '@carbon/icons/lib/checkmark/16'; +import { prefix } from '../../globals/settings'; +import { DROPDOWN_SIZE } from './dropdown'; +import styles from './dropdown.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Dropdown item. + * + * @element cds-dropdown-item + * @csspart selected-icon The selected icon. + */ +@customElement(`${prefix}-dropdown-item`) +class CDSDropdownItem extends LitElement { + /** + * `true` if this dropdown item should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * `true` if this dropdown item should be highlighted. + * If `true`, parent `` selects/deselects this dropdown item upon keyboard interaction. + * + * @private + */ + @property({ type: Boolean, reflect: true }) + highlighted = false; + + /** + * `true` if this dropdown item should be selected. + * + * @private + */ + @property({ type: Boolean, reflect: true }) + selected = false; + + /** + * Dropdown size. + */ + @property({ reflect: true }) + size = DROPDOWN_SIZE.MEDIUM; + + /** + * The `value` attribute that is set to the parent `` when this dropdown item is selected. + */ + @property() + value = ''; + + connectedCallback() { + super.connectedCallback(); + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'option'); + } + if (!this.hasAttribute('id')) { + this.setAttribute( + 'id', + `${prefix}-dropdown-item-${(this.constructor as typeof CDSDropdownItem) + .id++}` + ); + } + this.setAttribute('aria-selected', String(this.selected)); + } + + render() { + const { selected } = this; + return html` +
    + + ${!selected + ? undefined + : Checkmark16({ + part: 'selected-icon', + class: `${prefix}--list-box__menu-item__selected-icon`, + })} +
    + `; + } + + /** + * Store an identifier for use in composing this item's id. + * + * Auto-increments anytime a new dropdown-item appears. + */ + static id = 0; + + static styles = styles; +} + +export default CDSDropdownItem; diff --git a/packages/web-components/src/components/dropdown/dropdown-skeleton.ts b/packages/web-components/src/components/dropdown/dropdown-skeleton.ts new file mode 100644 index 000000000000..a40fe4ac229a --- /dev/null +++ b/packages/web-components/src/components/dropdown/dropdown-skeleton.ts @@ -0,0 +1,34 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './dropdown.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Skeleton version of dropdown. + */ +@customElement(`${prefix}-dropdown-skeleton`) +class CDSDropdownSkeleton extends LitElement { + render() { + return html` +
    +
    + +
    +
    + `; + } + + static styles = styles; +} + +export default CDSDropdownSkeleton; diff --git a/packages/web-components/src/components/dropdown/dropdown.mdx b/packages/web-components/src/components/dropdown/dropdown.mdx new file mode 100644 index 000000000000..55f2569e3b42 --- /dev/null +++ b/packages/web-components/src/components/dropdown/dropdown.mdx @@ -0,0 +1,89 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as DropdownStories from './dropdown.stories'; + + + +# Dropdown + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/dropdown) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/dropdown) + +Dropdown presents a list of options that can be used to filter or sort existing +content. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/dropdown/index.js'; +``` + +{`${cdnJs({ components: ['dropdown'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + Foo + Bar + Baz + +``` + +## Selection + +When user attempts to select a dropdown item, `cds-dropdown-beingselected` event +fires on ``, which has the following properties in the event +details: + +| Property | Description | +| -------- | ----------------------------------------- | +| `item` | The `` being selected. | + +`cds-dropdown-beingselected` bubbles and is cancelable. Canceling this event +means canceling change in selection. + +## Inline dropdown + +You can place a `cds-dropdown` inline with other content by using the inline +variant + +```html + + Foo + Bar + Baz + +``` + +## Skeleton + +For the skeleton variation, utilize ``. + +```html + +``` + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `open` attribute). + + + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `disabled` attribute). + + diff --git a/packages/web-components/src/components/dropdown/dropdown.scss b/packages/web-components/src/components/dropdown/dropdown.scss new file mode 100644 index 000000000000..14f0356c04ad --- /dev/null +++ b/packages/web-components/src/components/dropdown/dropdown.scss @@ -0,0 +1,184 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/components/list-box/list-box' as *; +@use '@carbon/styles/scss/components/dropdown' as *; +@use '@carbon/styles/scss/components/form'; +@use '@carbon/styles/scss/components/checkbox'; +@use '@carbon/styles/scss/components/tag'; + +// https://github.com/carbon-design-system/carbon/issues/11408 +@include list-box; + +:host(#{$prefix}-dropdown) { + outline: none; + + .#{$prefix}--assistive-text { + inset-block-start: -100%; + // Hides screen reader cursor + inset-inline-start: -100%; + } + + .#{$prefix}--label[hidden] { + display: none; + } + + .#{$prefix}--list-box__menu { + inset-block-start: 100%; + margin-block-start: 1px; + outline: 1px solid $focus; + } +} + +:host(#{$prefix}-dropdown[open]) { + .#{$prefix}--list-box__field { + outline: none; + } +} + +:host(#{$prefix}-dropdown[invalid]) { + .#{$prefix}--list-box__field { + outline: none; + } + + .#{$prefix}--form__helper-text { + color: $text-error; + } +} + +:host(#{$prefix}-dropdown[read-only]) { + @extend .#{$prefix}--dropdown--readonly; + + .#{$prefix}--list-box { + background-color: transparent; + border-block-end-color: $border-subtle; + } +} + +:host(#{$prefix}-combo-box[direction='top']), +:host(#{$prefix}-dropdown[direction='top']) { + @extend .#{$prefix}--list-box--up; + + .#{$prefix}--list-box__menu { + inset-block-start: auto; + } +} + +:host(#{$prefix}-dropdown[type='inline']) { + @extend .#{$prefix}--list-box__wrapper--inline; + + grid-gap: 0 $spacing-06; +} + +:host(#{$prefix}-dropdown[type='inline'][warn]) .#{$prefix}--list-box__field { + padding-inline: $spacing-05 calc(#{$spacing-08} + #{$spacing-05}); +} + +:host(#{$prefix}-dropdown[warn]), +:host(#{$prefix}-dropdown[invalid]) { + .#{$prefix}--form__helper-text { + grid-column: 2; + } +} + +:host(#{$prefix}-dropdown-item) { + @extend .#{$prefix}--list-box__menu-item; + + display: block; + + .#{$prefix}--list-box__menu-item__option { + block-size: auto; + } +} + +:host(#{$prefix}-dropdown-item:first-child) { + .#{$prefix}--list-box__menu-item__option { + border-block-start-width: 0; + } +} + +:host(#{$prefix}-dropdown-item:hover) { + background-color: $layer-hover; +} + +:host(#{$prefix}-dropdown-item[highlighted]) { + @extend .#{$prefix}--list-box__menu-item--highlighted; +} + +:host(#{$prefix}-dropdown-item[disabled]) + .#{$prefix}--list-box__menu-item__option { + color: $text-disabled; + text-decoration: none; +} + +:host(#{$prefix}-dropdown-item[selected]) { + @extend .#{$prefix}--list-box__menu-item--active; + @extend .#{$prefix}--list-box__menu-item--highlighted; + + .#{$prefix}--list-box__menu-item__option { + color: $text-primary; + } + + .#{$prefix}--list-box__menu-item__selected-icon { + display: block; + } +} + +:host(#{$prefix}-dropdown-item[size='sm']) { + block-size: $spacing-07; + + .#{$prefix}--list-box__menu-item__option { + padding-block: rem(7px); + } +} + +:host(#{$prefix}-dropdown-item[size='lg']) { + block-size: $spacing-09; + + .#{$prefix}--list-box__menu-item__option { + padding-block: rem(15px); + } +} + +:host(#{$prefix}-dropdown-skeleton) { + .#{$prefix}--skeleton { + @include skeleton; + } +} + +:host(#{$prefix}-dropdown[slug]) { + @extend .#{$prefix}--list-box__wrapper--slug; + + ::slotted(#{$prefix}-slug) { + position: absolute; + inset-block-start: 50%; + inset-inline-end: $spacing-08; + } + + ::slotted(#{$prefix}-slug:not([revert-active])) { + transform: translateY(-50%); + } +} + +:host(#{$prefix}-dropdown[slug][warn]), +:host(#{$prefix}-dropdown[slug][invalid]) { + .#{$prefix}--list-box { + .#{$prefix}--list-box__field { + padding-inline-end: $spacing-12; + } + } + + ::slotted(#{$prefix}-slug) { + inset-inline-end: $spacing-10; + } +} diff --git a/packages/web-components/src/components/dropdown/dropdown.stories.ts b/packages/web-components/src/components/dropdown/dropdown.stories.ts new file mode 100644 index 000000000000..4cb18e6c9550 --- /dev/null +++ b/packages/web-components/src/components/dropdown/dropdown.stories.ts @@ -0,0 +1,297 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { DROPDOWN_DIRECTION, DROPDOWN_SIZE, DROPDOWN_TYPE } from './dropdown'; +import './dropdown-item'; +import './dropdown-skeleton'; + +const directionOptions = { + [`Top`]: DROPDOWN_DIRECTION.TOP, + [`Bottom`]: DROPDOWN_DIRECTION.BOTTOM, +}; + +const sizes = { + [`Small size (${DROPDOWN_SIZE.SMALL})`]: DROPDOWN_SIZE.SMALL, + [`Medium size (${DROPDOWN_SIZE.MEDIUM})`]: DROPDOWN_SIZE.MEDIUM, + [`Large size (${DROPDOWN_SIZE.LARGE})`]: DROPDOWN_SIZE.LARGE, +}; + +const types = { + Default: null, + [`Inline (${DROPDOWN_TYPE.INLINE})`]: DROPDOWN_TYPE.INLINE, +}; + +const items = [ + { + value: 'option-0', + text: 'Lorem, ipsum dolor sit amet consectetur adipisicing elit.', + }, + { + value: 'option-1', + text: 'Option 1', + }, + { + value: 'option-2', + text: 'Option 2', + }, + { + value: 'option-3', + text: 'Option 3 - a disabled item', + disabled: true, + }, + { + value: 'option-4', + text: 'Option 4', + }, + { + value: 'option-5', + text: 'Option 5', + }, +]; + +const defaultArgs = { + direction: DROPDOWN_DIRECTION.BOTTOM, + disabled: false, + hideLabel: false, + helperText: 'This is some helper text', + invalid: false, + invalidText: 'invalid selection', + label: 'This is an example label', + open: false, + readOnly: false, + size: null, + titleText: 'This is an example title', + type: null, + value: '', + warn: false, + warnText: 'please notice the warning', +}; + +const controls = { + ariaLabel: { + control: 'text', + description: 'aria-label', + }, + disabled: { + control: 'boolean', + description: `Specify if the dropdown should be disabled, or not.`, + }, + direction: { + control: 'select', + options: directionOptions, + description: `Dropdown direction.`, + }, + hideLabel: { + control: 'boolean', + description: `Specify if the title text should be hidden, or not.`, + }, + helperText: { + control: 'text', + description: `The helper text for the dropdown.`, + }, + invalid: { + control: 'boolean', + description: `Specify if the dropdown should display an invalid icon, or not.`, + }, + invalidText: { + control: 'text', + description: `Message which is displayed if the value is invalid.`, + }, + label: { + control: 'text', + description: `The default content of the trigger button.`, + }, + open: { + control: 'boolean', + description: `Specify if the dropdown should be open, or not.`, + }, + readOnly: { + control: 'boolean', + description: `Specify if the dropdown should be read only, or not.`, + }, + size: { + control: 'select', + options: sizes, + description: `Dropdown size.`, + }, + titleText: { + control: 'text', + description: `Text that will be read by a screen reader when visiting this control.`, + }, + type: { + control: 'select', + options: types, + description: `Dropdown size.`, + }, + value: { + control: 'text', + description: `The value of the selected item.`, + }, + warn: { + control: 'boolean', + description: `Specify whether the control is currently in warning state.`, + }, + warnText: { + control: 'text', + description: `Text that is displayed when the control is in warning state.`, + }, +}; + +export const Default = { + render: () => html` + + ${items.map( + (elem) => html` + ${elem.text} + ` + )} + + `, +}; + +export const Inline = { + render: () => html` + + ${items.map( + (elem) => html` + ${elem.text} + ` + )} + + `, +}; + +export const InlineWithLayer = { + render: () => html` + +
    + + ${items.map( + (elem) => html` + ${elem.text} + ` + )} + +
    +
    + `, +}; + +export const WithLayer = { + render: () => html` + +
    + + ${items.map( + (elem) => html` + ${elem.text} + ` + )} + +
    +
    + `, +}; + +export const Playground = { + argTypes: controls, + args: defaultArgs, + render: ({ + ariaLabel, + open, + direction, + disabled, + helperText, + hideLabel, + invalid, + invalidText, + titleText, + readOnly, + size, + type, + value, + label, + warn, + warnText, + }) => + html` + + ${items.map( + (elem) => html` + ${elem.text} + ` + )} + + `, +}; + +export const Skeleton = { + parameters: { + percy: { + skip: true, + }, + }, + render: () => html` `, +}; + +const meta = { + title: 'Components/Dropdown', + decorators: [ + (story, { name }) => { + const width = !name.toLowerCase().includes('layer') ? `width:400px` : ``; + return html`
    ${story()}
    `; + }, + ], +}; + +export default meta; diff --git a/packages/web-components/src/components/dropdown/dropdown.ts b/packages/web-components/src/components/dropdown/dropdown.ts new file mode 100644 index 000000000000..fbaaa4d5f115 --- /dev/null +++ b/packages/web-components/src/components/dropdown/dropdown.ts @@ -0,0 +1,902 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { LitElement, html, TemplateResult } from 'lit'; +import { property, query, state } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import ChevronDown16 from '@carbon/icons/lib/chevron--down/16'; +import WarningFilled16 from '@carbon/icons/lib/warning--filled/16'; +import WarningAltFilled16 from '@carbon/icons/lib/warning--alt--filled/16'; +import FocusMixin from '../../globals/mixins/focus'; +import FormMixin from '../../globals/mixins/form'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import ValidityMixin from '../../globals/mixins/validity'; +import HostListener from '../../globals/decorators/host-listener'; +import { + find, + forEach, + indexOf, +} from '../../globals/internal/collection-helpers'; +import { + DROPDOWN_DIRECTION, + DROPDOWN_KEYBOARD_ACTION, + DROPDOWN_SIZE, + DROPDOWN_TYPE, + NAVIGATION_DIRECTION, +} from './defs'; +import CDSDropdownItem from './dropdown-item'; +import styles from './dropdown.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { + DROPDOWN_KEYBOARD_ACTION, + DROPDOWN_DIRECTION, + DROPDOWN_SIZE, + DROPDOWN_TYPE, + NAVIGATION_DIRECTION, +}; + +/** + * Dropdown. + * + * @element cds-dropdown + * @csspart label-text The label text. + * @csspart helper-text The helper text. + * @csspart trigger-button The trigger button. + * @csspart menu-body The menu body. + * @csspart validity-message The validity message. + * @fires cds-dropdown-beingselected + * The custom event fired before a dropdown item is selected upon a user gesture. + * Cancellation of this event stops changing the user-initiated selection. + * @fires cds-dropdown-beingtoggled + * The custom event fired before the open state of this dropdown is toggled upon a user gesture. + * Cancellation of this event stops the user-initiated toggling. + * @fires cds-dropdown-selected - The custom event fired after a dropdown item is selected upon a user gesture. + * @fires cds-dropdown-toggled - The custom event fired after the open state of this dropdown is toggled upon a user gesture. + */ +@customElement(`${prefix}-dropdown`) +class CDSDropdown extends ValidityMixin( + HostListenerMixin(FormMixin(FocusMixin(LitElement))) +) { + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + @state() + protected _activeDescendant?: string; + + /** + * The content of the selected item. + */ + protected _selectedItemContent: DocumentFragment | null = null; + + /** + * `true` if the trigger button should be focusable. + * Derived class can set `false` to this if the trigger button contains another primary focusable element (e.g. ``). + */ + protected _shouldTriggerBeFocusable = true; + + /** + * The list box `
    ` node. + */ + @query(`.${prefix}--list-box`) + protected _listBoxNode!: HTMLDivElement; + + /** + * The `` element for the helper text in the shadow DOM. + */ + @query('slot[name="helper-text"]') + protected _slotHelperTextNode!: HTMLSlotElement; + + /** + * The `` element for the title text in the shadow DOM. + */ + @query('slot[name="title-text"]') + protected _slotTitleTextNode!: HTMLSlotElement; + + /** + * @param itemToSelect A dropdown item. Absense of this argument means clearing selection. + * @returns `true` if the selection of this dropdown should change if the given item is selected upon user interaction. + */ + protected _selectionShouldChange(itemToSelect?: CDSDropdownItem) { + return !itemToSelect || itemToSelect.value !== this.value; + } + + /** + * A callback that runs after change in dropdown selection upon user interaction is confirmed. + * + * @param itemToSelect + * A dropdown item. + * Absense of this argument means clearing selection, which may be handled by a derived class. + */ + protected _selectionDidChange(itemToSelect?: CDSDropdownItem) { + if (itemToSelect) { + this.value = itemToSelect.value; + this._activeDescendant = itemToSelect.id; + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSDropdown).selectorItemSelected + ), + (item) => { + (item as CDSDropdownItem).selected = false; + item.setAttribute('aria-selected', 'false'); + } + ); + itemToSelect.selected = true; + itemToSelect.setAttribute('aria-selected', 'true'); + this._handleUserInitiatedToggle(false); + } + } + + /** + * Handles `click` event on the top-level element in the shadow DOM. + * + * @param event The event. + */ + protected _handleClickInner(event: MouseEvent) { + if (this.readOnly) { + return; + } + + if (this.shadowRoot!.contains(event.target as Node)) { + this._handleUserInitiatedToggle(); + } else { + const item = (event.target as Element).closest( + (this.constructor as typeof CDSDropdown).selectorItem + ) as CDSDropdownItem; + if (this.contains(item)) { + this._handleUserInitiatedSelectItem(item); + } + } + } + + /** + * Handler for the `keydown` event on the top-level element in the shadow DOM. + */ + protected _handleKeydownInner(event: KeyboardEvent) { + const { key } = event; + const action = (this.constructor as typeof CDSDropdown).getAction(key); + if (!this.open) { + switch (action) { + case DROPDOWN_KEYBOARD_ACTION.NAVIGATING: + this._handleUserInitiatedToggle(true); + // If this menu gets open with an arrow key, reset the highlight + this._clearHighlight(); + break; + default: + break; + } + } else { + switch (action) { + case DROPDOWN_KEYBOARD_ACTION.CLOSING: + this._handleUserInitiatedToggle(false); + break; + case DROPDOWN_KEYBOARD_ACTION.NAVIGATING: + this._navigate(NAVIGATION_DIRECTION[key]); + break; + default: + break; + } + } + } + + /** + * Handler for the `keypress` event on the top-level element in the shadow DOM. + */ + protected _handleKeypressInner(event: KeyboardEvent) { + const { key } = event; + const action = (this.constructor as typeof CDSDropdown).getAction(key); + if (!this.open) { + switch (action) { + case DROPDOWN_KEYBOARD_ACTION.TRIGGERING: + this._handleUserInitiatedToggle(true); + break; + default: + break; + } + } else { + switch (action) { + case DROPDOWN_KEYBOARD_ACTION.TRIGGERING: + { + const constructor = this.constructor as typeof CDSDropdown; + const highlightedItem = this.querySelector( + constructor.selectorItemHighlighted + ) as CDSDropdownItem; + if (highlightedItem) { + this._handleUserInitiatedSelectItem(highlightedItem); + } else { + this._handleUserInitiatedToggle(false); + } + } + break; + default: + break; + } + } + } + + /** + * Handles `blur` event handler on the document this element is in. + * + * @param event The event. + */ + @HostListener('focusout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + protected _handleFocusOut(event: FocusEvent) { + if (!this.contains(event.relatedTarget as Node)) { + this._handleUserInitiatedToggle(false); + } + } + + /** + * Handles `slotchange` event for the `` for helper text. + */ + protected _handleSlotchangeHelperText() { + this.requestUpdate(); + } + + /** + * Handles `slotchange` event for the `` for label text. + */ + protected _handleSlotchangeLabelText() { + this.requestUpdate(); + } + + /** + * Handles `slotchange` event. + */ + protected _handleSlugSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSDropdown).slugItem + ) + : false + ); + + this._hasSlug = Boolean(hasContent); + (hasContent[0] as HTMLElement).setAttribute('size', 'mini'); + this.requestUpdate(); + } + + /** + * Handles user-initiated selection of a dropdown item. + * + * @param [item] The dropdown item user wants to select. Absense of this argument means clearing selection. + */ + protected _handleUserInitiatedSelectItem(item?: CDSDropdownItem) { + if (item?.hasAttribute('disabled')) { + return; + } + + if (this._selectionShouldChange(item)) { + const init = { + bubbles: true, + composed: true, + detail: { + item, + }, + }; + const constructor = this.constructor as typeof CDSDropdown; + const beforeSelectEvent = new CustomEvent(constructor.eventBeforeSelect, { + ...init, + cancelable: true, + }); + if (this.dispatchEvent(beforeSelectEvent)) { + this._selectionDidChange(item); + const afterSelectEvent = new CustomEvent(constructor.eventSelect, init); + this.dispatchEvent(afterSelectEvent); + } + } + } + + /** + * Handles user-initiated toggling the open state. + * + * @param [force] If specified, forces the open state to the given one. + */ + protected _handleUserInitiatedToggle(force = !this.open) { + const { eventBeforeToggle, eventToggle } = this + .constructor as typeof CDSDropdown; + + const { disabled } = this; + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + open: force, + }, + }; + if (!disabled) { + if (this.dispatchEvent(new CustomEvent(eventBeforeToggle, init))) { + this.open = force; + if (!this.open) { + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSDropdown).selectorItemHighlighted + ), + (item) => { + (item as CDSDropdownItem).highlighted = false; + } + ); + } + this.requestUpdate(); + this.dispatchEvent(new CustomEvent(eventToggle, init)); + } + } + } + + /** + * Clears the selection of dropdown items. + */ + protected _clearHighlight() { + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSDropdown).selectorItem + ), + (item) => { + (item as CDSDropdownItem).highlighted = false; + } + ); + } + + /** + * Navigate through dropdown items. + * + * @param direction `-1` to navigate backward, `1` to navigate forward. + */ + protected _navigate(direction: number) { + const constructor = this.constructor as typeof CDSDropdown; + const items = this.querySelectorAll(constructor.selectorItem); + const highlightedItem = this.querySelector( + constructor.selectorItemHighlighted + ); + const highlightedIndex = indexOf(items, highlightedItem!); + let nextIndex = highlightedIndex + direction; + + if (items[nextIndex]?.hasAttribute('disabled')) { + nextIndex += direction; + } + if (nextIndex < 0) { + nextIndex = items.length - 1; + } + if (nextIndex >= items.length) { + nextIndex = 0; + } + forEach(items, (item, i) => { + (item as CDSDropdownItem).highlighted = i === nextIndex; + }); + + const nextItem = items[nextIndex]; + // Using `{ block: 'nearest' }` to prevent scrolling unless scrolling is absolutely necessary. + // `scrollIntoViewOptions` seems to work in latest Safari despite of MDN/caniuse table. + // IE falls back to the old behavior. + nextItem.scrollIntoView({ block: 'nearest' }); + + const nextItemId = nextItem.id; + if (nextItemId) { + this._activeDescendant = nextItemId; + } + } + + /* eslint-disable class-methods-use-this */ + /** + * @returns The content preceding the trigger button. + */ + protected _renderPrecedingLabel(): TemplateResult | void { + return undefined; + } + /* eslint-enable class-methods-use-this */ + + /** + * @returns The main content of the trigger button. + */ + protected _renderLabel(): TemplateResult { + const { label, _selectedItemContent: selectedItemContent } = this; + return html` + ${selectedItemContent || label} + `; + } + + /** + * @returns The title label. + */ + protected _renderTitleLabel(): TemplateResult { + const { + disabled, + hideLabel, + titleText, + _slotTitleTextNode: slotTitleTextNode, + _handleSlotchangeLabelText: handleSlotchangeLabelText, + } = this; + + const labelClasses = classMap({ + [`${prefix}--label`]: true, + [`${prefix}--label--disabled`]: disabled, + [`${prefix}--visually-hidden`]: hideLabel, + }); + + const hasTitleText = + titleText || + (slotTitleTextNode && slotTitleTextNode.assignedNodes().length > 0); + + return html` + + `; + } + + /* eslint-disable class-methods-use-this */ + /** + * @returns The content following the trigger button. + */ + protected _renderFollowingLabel(): TemplateResult | void { + return undefined; + } + /* eslint-enable class-methods-use-this */ + + /** + * Handles event to include selected value on the parent form. + * + * @param event The event. + */ + _handleFormdata(event: Event) { + const { formData } = event as any; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const { disabled, name, value } = this; + if (!disabled) { + formData.append(name, value); + } + } + + /** + * 'aria-label' of the ListBox component. + * Specify a label to be read by screen readers on the container node + */ + @property({ type: String, reflect: true, attribute: 'aria-label' }) + ariaLabel = ''; + + /** + * Specify the direction of the dropdown. Can be either top or bottom. + */ + @property({ type: String, reflect: true }) + direction = DROPDOWN_DIRECTION.BOTTOM; + + /** + * `true` if this dropdown should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * The helper text. + */ + @property({ attribute: 'helper-text' }) + helperText = ''; + + /** + * Specify whether the title text should be hidden or not + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-label' }) + hideLabel = false; + + /** + * `true` to show the UI of the invalid state. + */ + @property({ type: Boolean, reflect: true }) + invalid = false; + + /** + * Message which is displayed if the value is invalid. + */ + @property({ attribute: 'invalid-text' }) + invalidText = ''; + + /** + * Provide the title text that will be read by a screen reader when visiting this control + */ + @property({ attribute: 'title-text' }) + titleText = ''; + + /** + * Name for the dropdown in the `FormData` + */ + @property() + name = ''; + + /** + * `true` if this dropdown should be open. + */ + @property({ type: Boolean, reflect: true }) + open = false; + + /** + * Whether or not the Dropdown is readonly + */ + @property({ type: Boolean, reflect: true, attribute: 'read-only' }) + readOnly = false; + + /** + * `true` if the value is required. + */ + @property({ type: Boolean, reflect: true }) + required = false; + + /** + * The special validity message for `required`. + */ + @property({ attribute: 'required-validity-message' }) + requiredValidityMessage = 'Please fill out this field.'; + + /** + * Dropdown size. + */ + @property({ reflect: true }) + size = DROPDOWN_SIZE.MEDIUM; + + /** + * The `aria-label` attribute for the UI indicating the closed state. + */ + @property({ attribute: 'toggle-label-closed' }) + toggleLabelClosed = ''; + + /** + * The `aria-label` attribute for the UI indicating the open state. + */ + @property({ attribute: 'toggle-label-open' }) + toggleLabelOpen = ''; + + /** + * Generic label that will be used as the textual representation of what this field is for + */ + @property({ attribute: 'label' }) + label = ''; + + /** + * `true` if this dropdown should use the inline UI variant. + */ + @property({ reflect: true }) + type = DROPDOWN_TYPE.DEFAULT; + + /** + * The validity message. + */ + @property({ attribute: 'validity-message' }) + validityMessage = ''; + + /** + * The value of the selected item. + */ + @property({ reflect: true }) + value = ''; + + /** + * Specify whether the control is currently in warning state + */ + @property({ type: Boolean, reflect: true }) + warn = false; + + /** + * Provide the text that is displayed when the control is in warning state + */ + @property({ attribute: 'warn-text' }) + warnText = ''; + + shouldUpdate(changedProperties) { + const { selectorItem } = this.constructor as typeof CDSDropdown; + if (changedProperties.has('size')) { + forEach(this.querySelectorAll(selectorItem), (elem) => { + (elem as CDSDropdownItem).size = this.size; + }); + } + if (changedProperties.has('disabled') && this.disabled) { + const { disabled } = this; + // Propagate `disabled` attribute to descendants until `:host-context()` gets supported in all major browsers + forEach(this.querySelectorAll(selectorItem), (elem) => { + if (disabled) { + (elem as CDSDropdownItem).disabled = disabled; + } else { + (elem as CDSDropdownItem).removeAttribute('disabled'); + } + }); + } + if (changedProperties.has('value')) { + // `` updates selection beforehand + // because our rendering logic for `` looks for selected items via `qSA()` + forEach(this.querySelectorAll(selectorItem), (elem) => { + (elem as CDSDropdownItem).selected = + (elem as CDSDropdownItem).value === this.value; + }); + const item = find( + this.querySelectorAll(selectorItem), + (elem) => (elem as CDSDropdownItem).value === this.value + ); + if (item) { + const range = this.ownerDocument!.createRange(); + range.selectNodeContents(item); + this._selectedItemContent = range.cloneContents(); + } else { + this._selectedItemContent = null; + } + } + return true; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + updated(_changedProperties) { + this._hasSlug + ? this.setAttribute('slug', '') + : this.removeAttribute('slug'); + + this.shadowRoot + ?.querySelector("slot[name='slug']") + ?.classList.toggle( + `${prefix}--slug--revert`, + this.querySelector(`${prefix}-slug`)?.hasAttribute('revert-active') + ); + } + + /** + * The CSS class list for dropdown listbox + */ + protected get _classes() { + const { disabled, size, type, invalid, open, warn } = this; + const inline = type === DROPDOWN_TYPE.INLINE; + + const selectedItemsCount = this.querySelectorAll( + (this.constructor as typeof CDSDropdown).selectorItemSelected + ).length; + + return classMap({ + [`${prefix}--dropdown`]: true, + [`${prefix}--list-box`]: true, + [`${prefix}--list-box--disabled`]: disabled, + [`${prefix}--list-box--inline`]: inline, + [`${prefix}--list-box--expanded`]: open, + [`${prefix}--list-box--${size}`]: size, + [`${prefix}--dropdown--invalid`]: invalid, + [`${prefix}--dropdown--warn`]: warn, + [`${prefix}--dropdown--inline`]: inline, + [`${prefix}--dropdown--selected`]: selectedItemsCount > 0, + }); + } + + render() { + const { + ariaLabel, + _classes: classes, + disabled, + helperText, + invalid, + invalidText, + open, + toggleLabelClosed, + toggleLabelOpen, + type, + warn, + warnText, + _activeDescendant: activeDescendant, + _shouldTriggerBeFocusable: shouldTriggerBeFocusable, + _handleClickInner: handleClickInner, + _handleKeydownInner: handleKeydownInner, + _handleKeypressInner: handleKeypressInner, + _handleSlotchangeHelperText: handleSlotchangeHelperText, + _handleSlugSlotChange: handleSlugSlotChange, + _slotHelperTextNode: slotHelperTextNode, + } = this; + const inline = type === DROPDOWN_TYPE.INLINE; + + let activeDescendantFallback: string | undefined; + if (open && !activeDescendant) { + const constructor = this.constructor as typeof CDSDropdown; + const items = this.querySelectorAll(constructor.selectorItem); + activeDescendantFallback = items[0]?.id; + } + + const helperClasses = classMap({ + [`${prefix}--form__helper-text`]: true, + [`${prefix}--form__helper-text--disabled`]: disabled, + }); + const iconContainerClasses = classMap({ + [`${prefix}--list-box__menu-icon`]: true, + [`${prefix}--list-box__menu-icon--open`]: open, + }); + const toggleLabel = + (open ? toggleLabelOpen : toggleLabelClosed) || undefined; + const hasHelperText = + helperText || + invalidText || + warnText || + (slotHelperTextNode && slotHelperTextNode.assignedNodes().length > 0); + const validityIcon = !invalid + ? undefined + : WarningFilled16({ + class: `${prefix}--list-box__invalid-icon`, + 'aria-label': toggleLabel, + }); + const warningIcon = + !warn || (invalid && warn) + ? undefined + : WarningAltFilled16({ + class: `${prefix}--list-box__invalid-icon ${prefix}--list-box__invalid-icon--warning`, + 'aria-label': toggleLabel, + }); + const helperMessage = invalid ? invalidText : warn ? warnText : helperText; + const menuBody = html` + + `; + return html` + ${this._renderTitleLabel()} +
    +
    + ${this._renderPrecedingLabel()}${this._renderLabel()}${validityIcon}${warningIcon}${this._renderFollowingLabel()} +
    + ${ChevronDown16({ 'aria-label': toggleLabel })} +
    +
    + + ${menuBody} +
    +
    + ${helperMessage} +
    + `; + } + + /** + * Symbols of keys that triggers opening/closing menu and selecting/deselecting menu item. + */ + static TRIGGER_KEYS = new Set([' ', 'Enter']); + + /** + * A selector that will return highlighted items. + */ + static get selectorItemHighlighted() { + return `${prefix}-dropdown-item[highlighted]`; + } + + /** + * A selector that will return dropdown items. + */ + static get selectorItem() { + return `${prefix}-dropdown-item`; + } + + /** + * A selector that will return selected items. + */ + static get selectorItemSelected() { + return `${prefix}-dropdown-item[selected]`; + } + + /** + * The name of the custom event fired before a dropdown item is selected upon a user gesture. + * Cancellation of this event stops changing the user-initiated selection. + */ + static get eventBeforeSelect() { + return `${prefix}-dropdown-beingselected`; + } + + /** + * The name of the custom event fired after a a dropdown item is selected upon a user gesture. + */ + static get eventSelect() { + return `${prefix}-dropdown-selected`; + } + + /** + * The name of the custom event fired before this dropdown item is being toggled upon a user gesture. + * Cancellation of this event stops the user-initiated action of toggling this dropdown item. + */ + static get eventBeforeToggle() { + return `${prefix}-dropdown-beingtoggled`; + } + + /** + * The name of the custom event fired after this dropdown item is toggled upon a user gesture. + */ + static get eventToggle() { + return `${prefix}-dropdown-toggled`; + } + + /** + * A selector that will return the slug item. + */ + static get slugItem() { + return `${prefix}-slug`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + + static styles = styles; + + /** + * @returns A action for dropdown for the given key symbol. + */ + static getAction(key: string) { + if (key === 'Escape') { + return DROPDOWN_KEYBOARD_ACTION.CLOSING; + } + if (key in NAVIGATION_DIRECTION) { + return DROPDOWN_KEYBOARD_ACTION.NAVIGATING; + } + if (this.TRIGGER_KEYS.has(key)) { + return DROPDOWN_KEYBOARD_ACTION.TRIGGERING; + } + return DROPDOWN_KEYBOARD_ACTION.NONE; + } +} + +export default CDSDropdown; diff --git a/packages/web-components/src/components/dropdown/index.ts b/packages/web-components/src/components/dropdown/index.ts new file mode 100644 index 000000000000..21c23e2d86c8 --- /dev/null +++ b/packages/web-components/src/components/dropdown/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './dropdown'; +import './dropdown-item'; +import './dropdown-skeleton'; diff --git a/packages/web-components/src/components/file-uploader/defs.ts b/packages/web-components/src/components/file-uploader/defs.ts new file mode 100644 index 000000000000..729a23a31341 --- /dev/null +++ b/packages/web-components/src/components/file-uploader/defs.ts @@ -0,0 +1,48 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * The state of ``. + */ +export enum FILE_UPLOADER_ITEM_STATE { + /** + * Upload in progress. + */ + UPLOADING = 'uploading', + + /** + * Upload complete. + */ + COMPLETE = 'complete', + + /** + * Editing. + */ + EDIT = 'edit', +} + +/** + * File uploader item size. + */ +export enum FILE_UPLOADER_ITEM_SIZE { + /** + * Small size. + */ + SMALL = 'sm', + + /** + * Medium size. + */ + MEDIUM = 'md', + + /** + * Large size. + */ + LARGE = 'lg', +} diff --git a/packages/web-components/src/components/file-uploader/demo-file-uploader.ts b/packages/web-components/src/components/file-uploader/demo-file-uploader.ts new file mode 100644 index 000000000000..399a333a6ece --- /dev/null +++ b/packages/web-components/src/components/file-uploader/demo-file-uploader.ts @@ -0,0 +1,250 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html, LitElement } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +import { prefix } from '../../globals/settings'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import './index'; +import { FILE_UPLOADER_ITEM_STATE } from './file-uploader-item'; +import { BUTTON_SIZE } from '../button/button'; +import { FileData } from './stories/types'; + +/** + * A class to manage file uploading states, like sending file contents to server. + * DEMONSTRATION-PURPOSE ONLY. + * Data/state handling in file uploading tends to involve lots of application-specific logics + * and thus abstracting everything in a library won't be a good return on investment + * vs. letting users copy code here and implement features that fit their needs. + */ +@customElement(`${prefix}-ce-demo-file-uploader`) +export default class CDSCEDemoFileUploader extends LitElement { + /** + * The files being uploaded. + */ + private _files: FileData[] = []; + + /** + * Handles `cds-drop-container-changed` on ``. + * + * @param event The event. + */ + private _handleChange(event: CustomEvent) { + const { addedFiles } = event.detail; + const newFiles: FileData[] = addedFiles.map( + (item) => + ({ + id: Math.random().toString(36).slice(2), + file: item, + state: FILE_UPLOADER_ITEM_STATE.UPLOADING, + } as FileData) + ); + const { multiple, _files: files, _simulateUpload: simulateUpload } = this; + if (multiple) { + this._files = files.concat(newFiles); + this.requestUpdate(); + newFiles.forEach(simulateUpload, this); + } else if (addedFiles.length > 0) { + this._files = files.concat(newFiles[0]); + this.requestUpdate(); + this._simulateUpload(newFiles[0]); + } + } + + /** + * Handles `cds-file-uploader-item-deleted` on ``. + * + * @param event The event. + */ + private _handleDelete(event: CustomEvent) { + const { fileId: idToDelete } = (event.target as HTMLElement).dataset; + this._files = this._files.filter(({ id }) => idToDelete !== id); + this.requestUpdate(); + } + + /** + * Simulates updating file. + * + * @param data The data of the file being uploaded. + */ + private async _simulateUpload(data: FileData) { + const { id, file } = data; + if (file.size > 524288) { + this._files = this._files.map((item) => + id !== item.id + ? item + : { + ...item, + state: FILE_UPLOADER_ITEM_STATE.EDIT, + invalid: true, + errorSubject: 'File size exceeds limit', + errorBody: + '500kb max file size. Select a new file and try again.', + } + ); + this.requestUpdate(); + } else { + // Simulates network request time + const rand = Math.random() * 1000; + await new Promise((t) => setTimeout(t, rand)); + this._files = this._files.map((item) => + id !== item.id + ? item + : { + ...item, + state: FILE_UPLOADER_ITEM_STATE.COMPLETE, + } + ); + this.requestUpdate(); + // Shows x icon after 1 second + await new Promise((t) => setTimeout(t, 1000)); + this._files = this._files.map((item) => + id !== item.id + ? item + : { + ...item, + state: FILE_UPLOADER_ITEM_STATE.EDIT, + } + ); + this.requestUpdate(); + } + } + + /** + * The file types the file input should accept, separated by space. + */ + @property() + accept = ''; + + /** + * `true` if the drop container should be disabled. + */ + @property({ type: Boolean, reflect: true }) + button = false; + + /** + * Button kind. + */ + @property({ attribute: 'button-kind' }) + buttonKind = 'primary'; + + /** + * Button label. + */ + @property({ attribute: 'button-label' }) + buttonLabel = 'Add file'; + + /** + * `true` if the drop container should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * Icon description. + */ + @property({ attribute: 'icon-description' }) + iconDescription = ''; + + /** + * The input name. + */ + @property({ attribute: 'input-name' }) + inputName = ''; + + /** + * The label description text. + */ + @property({ attribute: 'label-description' }) + labelDescription = ''; + + /** + * The label title. + */ + @property({ attribute: 'label-title' }) + labelTitle = ''; + + /** + * `true` if the drop container should accept more than one files at once. + * Note that even with `false` set here, user _can_ select multiple files one by one. + */ + @property({ type: Boolean, reflect: true }) + multiple = false; + + /** + * The size of the button item. + */ + @property({ reflect: true }) + size = BUTTON_SIZE.MEDIUM; + + /** + * The state of this file uploader item. + */ + @property({ reflect: true, attribute: 'input-state' }) + inputState = ''; + + render() { + const { + accept, + button, + buttonKind, + buttonLabel, + disabled, + labelDescription, + labelTitle, + multiple, + size, + inputState, + iconDescription, + _files: files, + _handleChange: handleChange, + _handleDelete: handleDelete, + } = this; + return html` + + ${!button + ? html` + Drag and drop files here or click to upload + ` + : html` + ${buttonLabel} + `} + ${files.map( + ({ id, invalid, file, state, errorSubject, errorBody }) => html` + + ${file.name} + + ` + )} + + `; + } +} diff --git a/packages/web-components/src/components/file-uploader/docs/overview.mdx b/packages/web-components/src/components/file-uploader/docs/overview.mdx new file mode 100644 index 000000000000..90c6af7d759c --- /dev/null +++ b/packages/web-components/src/components/file-uploader/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/file-uploader/file-uploader-button.ts b/packages/web-components/src/components/file-uploader/file-uploader-button.ts new file mode 100644 index 000000000000..0c2c52abc653 --- /dev/null +++ b/packages/web-components/src/components/file-uploader/file-uploader-button.ts @@ -0,0 +1,211 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { prefix } from '../../globals/settings'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import ifNonEmpty from '../../globals/directives/if-non-empty'; +import styles from './file-uploader.scss?lit'; +import { BUTTON_KIND, BUTTON_SIZE } from '../button/defs'; + +export { FORM_ELEMENT_COLOR_SCHEME as TILE_COLOR_SCHEME } from '../../globals/shared-enums'; + +/** + * File uploader button . + * + * @element cds-file-uploader-container + * @fires cds-file-uploader-button-changed The custom event fired when there is a user gesture to select files to upload. + */ +@customElement(`${prefix}-file-uploader-button`) +class CDSFileUploaderButton extends HostListenerMixin(LitElement) { + /** + * Handles `click` event on the button. + */ + private _handleClick(event) { + event.target.value = null; + const { selectorInput } = this.constructor as typeof CDSFileUploaderButton; + this?.shadowRoot?.querySelector(selectorInput)?.setAttribute('value', ''); + (this?.shadowRoot?.querySelector(selectorInput) as HTMLElement).click(); + } + + /** + * Handles `keydown` event on the button. + */ + private _handleKeyDown(event) { + const { selectorInput } = this.constructor as typeof CDSFileUploaderButton; + if (event.key === 'Enter' || event.key === 'Space') { + this?.shadowRoot?.querySelector(selectorInput)?.setAttribute('value', ''); + (this?.shadowRoot?.querySelector(selectorInput) as HTMLElement).click(); + } + } + + /** + * Handles user gesture to select files to upload. + * + * @param event The event. + */ + private _handleChange(event: Event | DragEvent) { + const addedFiles = this._getFiles(event); + const { eventChange, selectorInput } = this + .constructor as typeof CDSFileUploaderButton; + this.dispatchEvent( + new CustomEvent(eventChange, { + bubbles: true, + composed: true, + detail: { + addedFiles, + }, + }) + ); + + const fileInput = this?.shadowRoot?.querySelector(selectorInput); + if (fileInput) { + (fileInput as HTMLInputElement).value = ''; + } + } + + /** + * @param event The event. + * @returns The list of files user chose to upload. + */ + private _getFiles(event: Event | DragEvent) { + const { files } = + (event.type === 'drop' + ? (event as DragEvent).dataTransfer + : (event.target as HTMLInputElement)) ?? {}; + const { accept } = this; + if (!accept || !/^(change|drop)$/.test(event.type)) { + return Array.from(files ?? []); + } + const acceptedTypes = new Set(accept.split(' ')); + return Array.prototype.filter.call( + files, + ({ name, type: mimeType = '' }) => { + const fileExtensionRegExp = /\.[^.]+$/; + const hasFileExtension = fileExtensionRegExp.test(name); + const [fileExtension] = !hasFileExtension + ? [undefined] + : fileExtensionRegExp.exec(name) ?? []; + + return ( + acceptedTypes.has(mimeType) || + (fileExtension && acceptedTypes.has(fileExtension)) + ); + } + ) as File[]; + } + + /** + * Button kind. + */ + @property({ reflect: true, attribute: 'button-kind' }) + buttonKind = BUTTON_KIND.PRIMARY; + + /** + * Button size. + */ + @property({ reflect: true }) + size = BUTTON_SIZE.MEDIUM; + + /** + * The file types the file input should accept, separated by space. + */ + @property() + accept = ''; + + /** + * `true` if this drop container should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * `true` if this drop container should accept more than one files at once. + * Note that even with `false` set here, user _can_ select multiple files one by one. + */ + @property({ type: Boolean, reflect: true }) + multiple = false; + + /** + * The name of the input. + */ + @property({ reflect: true }) + name = ''; + + /** + * The shadow DOM slot to put this drop container in. + */ + @property({ reflect: true }) + slot = 'drop-container'; + + render() { + const { + accept, + disabled, + multiple, + name, + buttonKind, + size, + _handleChange: handleChange, + } = this; + + const labelClasses = classMap({ + [`${prefix}--file-browse-btn`]: true, + [`${prefix}--file-browse-btn--disabled`]: disabled, + }); + const buttonClasses = classMap({ + [`${prefix}--btn`]: true, + [`${prefix}--btn--${buttonKind}`]: buttonKind, + [`${prefix}--layout--size-${size}`]: size, + [`${prefix}--btn--disabled`]: disabled, + [`${prefix}--btn--${size}`]: size, + }); + return html` + + + + `; + } + + /** + * The name of the custom event fired when there is a user gesture to select files to upload. + */ + static get eventChange() { + return `${prefix}-file-uploader-button-changed`; + } + + /** + * A selector that will return the file ``. + */ + static get selectorInput() { + return `.${prefix}--file-input`; + } + + static styles = styles; +} + +export default CDSFileUploaderButton; diff --git a/packages/web-components/src/components/file-uploader/file-uploader-drop-container.ts b/packages/web-components/src/components/file-uploader/file-uploader-drop-container.ts new file mode 100644 index 000000000000..40a8a1910470 --- /dev/null +++ b/packages/web-components/src/components/file-uploader/file-uploader-drop-container.ts @@ -0,0 +1,210 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import HostListener from '../../globals/decorators/host-listener'; +import ifNonEmpty from '../../globals/directives/if-non-empty'; +import styles from './file-uploader.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { FORM_ELEMENT_COLOR_SCHEME as TILE_COLOR_SCHEME } from '../../globals/shared-enums'; + +/** + * The value to set to `event.dataTransfer.dropEffect`, keyed by the event nane. + */ +const dropEffects = { + dragover: 'copy', + dragleave: 'move', +}; + +/** + * File uploader drop container. + * + * @element cds-file-uploader-drop-container + * @fires cds-file-uploader-drop-container-changed The custom event fired when there is a user gesture to select files to upload. + */ +@customElement(`${prefix}-file-uploader-drop-container`) +class CDSFileUploaderDropContainer extends HostListenerMixin(LitElement) { + /** + * `true` to show the active state of this UI. + */ + private _active = false; + + /** + * Handles user gesture to select files to upload. + * + * @param event The event. + */ + private _handleChange(event: Event | DragEvent) { + const { eventChange, selectorInput } = this + .constructor as typeof CDSFileUploaderDropContainer; + const { files } = + (event.type === 'drop' + ? (event as DragEvent).dataTransfer + : (event.target as HTMLInputElement)) ?? {}; + const addedFiles = this._getFiles(event, files); + + this.dispatchEvent( + new CustomEvent(eventChange, { + bubbles: true, + composed: true, + detail: { + addedFiles, + }, + }) + ); + + const fileInput = this?.shadowRoot?.querySelector(selectorInput); + if (fileInput) { + (fileInput as HTMLInputElement).value = ''; // carbon-web-components#904 + } + } + + /** + * Handles `dragover`, `dragleave` and `drop` events. + * + * @param event The event. + */ + @HostListener('dragover') + @HostListener('dragleave') + @HostListener('drop') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleDrag(event: DragEvent) { + event.preventDefault(); // Prevents page navigation upon dropping + if (this.disabled) { + return; + } + const { dataTransfer, type } = event; + const dropEffect = dropEffects[type]; + if (dataTransfer && dropEffect) { + dataTransfer.dropEffect = dropEffect; + } + this._active = type === 'dragover'; + if (type === 'drop') { + this._handleChange(event); + } + this.requestUpdate(); + } + + /** + * @param event The event. + * @returns The list of files user chose to upload. + */ + private _getFiles(event, files) { + const { accept } = this; + if (!accept || !/^(change|drop)$/.test(event.type)) { + return Array.from(files ?? []); + } + const acceptedTypes = new Set(accept.split(' ')); + return Array.prototype.filter.call( + files, + ({ name, type: mimeType = '' }) => { + const fileExtensionRegExp = /\.[^.]+$/; + const hasFileExtension = fileExtensionRegExp.test(name); + const [fileExtension] = !hasFileExtension + ? [undefined] + : fileExtensionRegExp.exec(name) ?? []; + + return ( + acceptedTypes.has(mimeType) || + (fileExtension && acceptedTypes.has(fileExtension)) + ); + } + ) as File[]; + } + + /** + * The file types the file input should accept, separated by space. + */ + @property() + accept = ''; + + /** + * `true` if this drop container should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * `true` if this drop container should accept more than one files at once. + * Note that even with `false` set here, user _can_ select multiple files one by one. + */ + @property({ type: Boolean, reflect: true }) + multiple = false; + + /** + * The name of the input. + */ + @property({ reflect: true }) + name = ''; + + /** + * The shadow DOM slot to put this drop container in. + */ + @property({ reflect: true }) + slot = 'drop-container'; + + render() { + const { + accept, + disabled, + multiple, + name, + _active: active, + _handleChange: handleChange, + } = this; + const labelClasses = classMap({ + [`${prefix}--file-browse-btn`]: true, + [`${prefix}--file-browse-btn--disabled`]: disabled, + }); + const dropareaClasses = classMap({ + [`${prefix}--file__drop-container`]: true, + [`${prefix}--file__drop-container--drag-over`]: active, + }); + return html` + + `; + } + + /** + * The name of the custom event fired when there is a user gesture to select files to upload. + */ + static get eventChange() { + return `${prefix}-file-uploader-drop-container-changed`; + } + + /** + * A selector that will return the file ``. + */ + static get selectorInput() { + return `.${prefix}--file-input`; + } + + static styles = styles; +} + +export default CDSFileUploaderDropContainer; diff --git a/packages/web-components/src/components/file-uploader/file-uploader-item.ts b/packages/web-components/src/components/file-uploader/file-uploader-item.ts new file mode 100644 index 000000000000..5b0866da0752 --- /dev/null +++ b/packages/web-components/src/components/file-uploader/file-uploader-item.ts @@ -0,0 +1,187 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import CheckmarkFilled16 from '@carbon/icons/lib/checkmark--filled/16'; +import Close16 from '@carbon/icons/lib/close/16'; +import WarningFilled16 from '@carbon/icons/lib/warning--filled/16'; +import { prefix } from '../../globals/settings'; +import { LOADING_TYPE } from '../loading/loading'; +import { FILE_UPLOADER_ITEM_SIZE, FILE_UPLOADER_ITEM_STATE } from './defs'; +import styles from './file-uploader.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { FILE_UPLOADER_ITEM_SIZE, FILE_UPLOADER_ITEM_STATE }; + +/** + * File uploader item. + * + * @element cds-file-uploader-item + * @slot validity-message The validity message. + * @slot validity-message-supplement The supplemental validity message. + * @fires cds-file-uploader-item-beingdeleted + * The custom event fired before this file uploader item is being deleted upon a user gesture. + * Cancellation of this event stops the user-initiated action of deleting this file uploader item. + * @fires cds-file-uploader-item-deleted - The custom event fired after this file uploader item is deleted upon a user gesture. + */ +@customElement(`${prefix}-file-uploader-item`) +class CDSFileUploaderItem extends LitElement { + /** + * Handles `click` event on the delete button. + */ + private _handleClickDeleteButton() { + const init = { + bubbles: true, + cancelable: true, + composed: true, + }; + const { eventBeforeDelete, eventDelete } = this + .constructor as typeof CDSFileUploaderItem; + if (this.dispatchEvent(new CustomEvent(eventBeforeDelete, init))) { + this.dispatchEvent(new CustomEvent(eventDelete, init)); + } + } + + /** + * @returns The content showing the editing UI of this file uploader item. + */ + private _renderEditing() { + const { + iconDescription, + invalid, + _handleClickDeleteButton: handleClickDeleteButton, + } = this; + return html` + ${!invalid + ? undefined + : WarningFilled16({ class: `${prefix}--file-invalid` })} + + `; + } + + /** + * @returns The content showing this file uploader's file uploading status as in progress. + */ + private _renderUploading() { + const { iconDescription } = this; + return html` + + `; + } + + /** + * @returns The content showing this file uploader's file uploading status as complete. + */ + private _renderUploaded() { + const { iconDescription } = this; + return CheckmarkFilled16({ + class: `${prefix}--file-complete`, + 'aria-label': iconDescription, + }); + } + + /** + * @returns The content showing this file uploader's status. + */ + private _renderStatus() { + const { state } = this; + switch (state) { + case FILE_UPLOADER_ITEM_STATE.EDIT: + return this._renderEditing(); + case FILE_UPLOADER_ITEM_STATE.UPLOADING: + return this._renderUploading(); + case FILE_UPLOADER_ITEM_STATE.COMPLETE: + return this._renderUploaded(); + default: + return undefined; + } + } + + /** + * The `aria-label` attribute for the icon to delete this file uploader item. + */ + @property({ attribute: 'icon-description' }) + iconDescription = 'Delete this file'; + + /** + * Controls the invalid state and visibility of the `validityMessage`. + */ + @property({ type: Boolean, reflect: true }) + invalid = false; + + /** + * The size of this file uploader item. + */ + @property({ reflect: true }) + size = FILE_UPLOADER_ITEM_SIZE.MEDIUM; + + /** + * The state of this file uploader item. + */ + @property({ reflect: true }) + state = FILE_UPLOADER_ITEM_STATE.UPLOADING; + + /** + * The error subject text. + */ + @property({ attribute: 'error-subject' }) + errorSubject = ''; + + /** + * The error body text + */ + @property({ attribute: 'error-body' }) + errorBody = ''; + + render() { + const { invalid, errorSubject, errorBody } = this; + return html`

    + ${this._renderStatus()} +
    +
    ${errorSubject}
    +

    + ${errorBody} +

    +
    `; + } + + /** + * The name of the custom event fired before this file uplodaer item is being deleted upon a user gesture. + * Cancellation of this event stops the user-initiated action of deleting this file uploader item. + */ + static get eventBeforeDelete() { + return `${prefix}-file-uploader-item-beingdeleted`; + } + + /** + * The name of the custom event fired after this file uplodaer item is deleted upon a user gesture. + */ + static get eventDelete() { + return `${prefix}-file-uploader-item-deleted`; + } + + static styles = styles; +} + +export default CDSFileUploaderItem; diff --git a/packages/web-components/src/components/file-uploader/file-uploader-skeleton.ts b/packages/web-components/src/components/file-uploader/file-uploader-skeleton.ts new file mode 100644 index 000000000000..82506b4739e2 --- /dev/null +++ b/packages/web-components/src/components/file-uploader/file-uploader-skeleton.ts @@ -0,0 +1,35 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import '../skeleton-text/skeleton-text'; +import { SKELETON_TEXT_TYPE } from '../skeleton-text/skeleton-text'; +import '../button/button-skeleton'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * The File uploader skeleton. + * + * @element cds-file-uploader-skeleton + */ +@customElement(`${prefix}-file-uploader-skeleton`) +class CDSFileUploaderSkeleton extends LitElement { + render() { + return html` + + + + `; + } +} + +export default CDSFileUploaderSkeleton; diff --git a/packages/web-components/src/components/file-uploader/file-uploader.mdx b/packages/web-components/src/components/file-uploader/file-uploader.mdx new file mode 100644 index 000000000000..4c633b459694 --- /dev/null +++ b/packages/web-components/src/components/file-uploader/file-uploader.mdx @@ -0,0 +1,62 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as FileUploaderStories from './file-uploader.stories'; + + + +# File uploader + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/file-uploader) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/file-uploader) + +File uploaders allow users to select one or more files to upload to a specific +location. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/file-uploader/index.js'; +``` + +{`${cdnJs({ components: ['file-uploader'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + + Drag and drop files here or click to upload +
    + +``` + +## `` attributes, properties and events + + + +## `` attributes, properties and events + + + +## `` attributes, properties and events + + + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `invalid` attribute). + + diff --git a/packages/web-components/src/components/file-uploader/file-uploader.scss b/packages/web-components/src/components/file-uploader/file-uploader.scss new file mode 100644 index 000000000000..0be569383d1b --- /dev/null +++ b/packages/web-components/src/components/file-uploader/file-uploader.scss @@ -0,0 +1,67 @@ +// +// Copyright IBM Corp. 2020, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/type' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/components/file-uploader/file-uploader' as *; +@use '@carbon/styles/scss/layout' as *; + +// https://github.com/carbon-design-system/carbon/issues/11408 +@include file-uploader; + +:host(#{$prefix}-file-uploader-shell) { + @extend .#{$prefix}--form-item; + + align-items: stretch; +} + +:host(#{$prefix}-file-drop-container) { + @extend .#{$prefix}--file; +} + +:host(#{$prefix}-file-uploader-item) { + @extend .#{$prefix}--file__selected-file; + + .#{$prefix}--file-filename { + margin-block: 0; + } + + .#{$prefix}--form-requirement[hidden] { + display: none; + } +} + +:host(#{$prefix}-file-uploader-item[invalid]) { + @extend .#{$prefix}--file__selected-file--invalid; + + .#{$prefix}--form-requirement__supplement { + margin: 0; + } +} + +:host(#{$prefix}-file-uploader-item[size='md']) { + @extend .#{$prefix}--file__selected-file--md; +} + +:host(#{$prefix}-file-uploader-item[size='sm']) { + @extend .#{$prefix}--file__selected-file--sm; +} + +:host(#{$prefix}-file-uploader) { + @include emit-layout-tokens(); + + .#{$prefix}--label-description, + .#{$prefix}--file--label { + margin-block-start: 0; + } + + .#{$prefix}--file-container { + margin-block-start: $spacing-03; + } +} diff --git a/packages/web-components/src/components/file-uploader/file-uploader.stories.ts b/packages/web-components/src/components/file-uploader/file-uploader.stories.ts new file mode 100644 index 000000000000..bc9f2b9e4028 --- /dev/null +++ b/packages/web-components/src/components/file-uploader/file-uploader.stories.ts @@ -0,0 +1,211 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { prefix } from '../../globals/settings'; +import './index'; +import './demo-file-uploader'; +import { FILE_UPLOADER_ITEM_STATE } from './file-uploader-item'; +import { BUTTON_KIND, BUTTON_SIZE } from '../button/button'; + +const kind = { + [`Primary button (${BUTTON_KIND.PRIMARY})`]: BUTTON_KIND.PRIMARY, + [`Secondary button (${BUTTON_KIND.SECONDARY})`]: BUTTON_KIND.SECONDARY, + [`Tertiary button (${BUTTON_KIND.TERTIARY})`]: BUTTON_KIND.TERTIARY, + [`Danger primary button (${BUTTON_KIND.DANGER_PRIMARY})`]: + BUTTON_KIND.DANGER_PRIMARY, + [`Danger button (${BUTTON_KIND.DANGER})`]: BUTTON_KIND.DANGER, + [`Ghost button (${BUTTON_KIND.GHOST})`]: BUTTON_KIND.GHOST, +}; + +const states = { + [`Upload in progress (${FILE_UPLOADER_ITEM_STATE.UPLOADING})`]: + FILE_UPLOADER_ITEM_STATE.UPLOADING, + [`Upload complete (${FILE_UPLOADER_ITEM_STATE.COMPLETE})`]: + FILE_UPLOADER_ITEM_STATE.COMPLETE, + [`Edit upload (${FILE_UPLOADER_ITEM_STATE.EDIT})`]: + FILE_UPLOADER_ITEM_STATE.EDIT, +}; + +const sizes = { + [`sm (${BUTTON_SIZE.SMALL})`]: BUTTON_SIZE.SMALL, + [`md (${BUTTON_SIZE.MEDIUM})`]: BUTTON_SIZE.MEDIUM, + [`lg (${BUTTON_SIZE.LARGE})`]: BUTTON_SIZE.LARGE, +}; + +const args = { + buttonKind: BUTTON_KIND.PRIMARY, + buttonLabel: 'Add file', + disabled: false, + state: FILE_UPLOADER_ITEM_STATE.UPLOADING, + iconDescription: 'Delete file', + labelDescription: 'Max file size is 500kb. Only .jpg files are supported.', + labelTitle: 'Upload files', + name: '', + multiple: false, + size: BUTTON_SIZE.MEDIUM, +}; + +const argTypes = { + buttonKind: { + control: 'select', + options: kind, + description: + 'Specify the types of files that this input should be able to receive.', + }, + buttonLabel: { + control: 'text', + description: + 'Provide the label text to be read by screen readers when interacting with the <cds-file-uploader-button>.', + }, + disabled: { + control: 'boolean', + description: 'Specify whether file input is disabled.', + }, + state: { + control: 'select', + description: 'File uploader item state (state)', + options: states, + }, + iconDescription: { + control: 'text', + description: + 'Provide a description for the complete/close icon that can be read by screen readers.', + }, + labelDescription: { + control: 'text', + description: + 'Specify the description text of this <cds-file-uploader>.', + }, + labelTitle: { + control: 'text', + description: + 'Specify the title text of this <cds-file-uploader>.', + }, + name: { + control: 'text', + description: + 'Provide a name for the underlying <input> node.', + }, + multiple: { + control: 'boolean', + description: + 'Specify if the component should accept multiple files to upload.', + }, + size: { + control: 'select', + description: + 'Specify the size of the <cds-file-uploader-button>, from a list of available sizes.', + options: sizes, + }, + onDelete: { + action: `${prefix}-file-uploader-item-deleted`, + }, + onChange: { + action: `${prefix}-drop-container-changed`, + }, +}; + +export const Default = { + render: () => { + return html` + + + `; + }, +}; + +export const DragAndDropUploadContainerExampleApplication = { + render: () => { + return html` + + + `; + }, +}; + +export const FileUploaderDropContainer = { + render: () => { + return html` + + Drag and drop files here or click to upload + + `; + }, +}; + +export const FileUploaderItem = { + render: () => { + return html` + + README.md + + `; + }, +}; + +export const Skeleton = { + render: () => { + return html` `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + buttonKind, + buttonLabel, + disabled, + state, + iconDescription, + labelDescription, + labelTitle, + multiple, + onDelete, + onChange, + name, + size, + } = args ?? {}; + + return html` + + + `; + }, +}; + +const meta = { + title: 'Components/File uploader', +}; + +export default meta; diff --git a/packages/web-components/src/components/file-uploader/file-uploader.ts b/packages/web-components/src/components/file-uploader/file-uploader.ts new file mode 100644 index 000000000000..436de0bf9069 --- /dev/null +++ b/packages/web-components/src/components/file-uploader/file-uploader.ts @@ -0,0 +1,92 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './file-uploader.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * The shell UI for file uploader. + * + * @element cds-file-uploader + * @slot label-title. + * @slot lebel-description. + */ +@customElement(`${prefix}-file-uploader`) +class CDSFileUploader extends LitElement { + /** + * `true` if the file uploader should disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * The description text. + */ + @property({ attribute: 'label-description' }) + labelDescription = ''; + + /** + * The label title. + */ + @property({ attribute: 'label-title' }) + labelTitle = ''; + + updated(changedProperties) { + if (changedProperties.has('disabled')) { + const { selectorUploaderItem } = this + .constructor as typeof CDSFileUploader; + const uploaderItem = this.querySelector( + selectorUploaderItem + ) as CDSFileUploader; + uploaderItem.disabled = this.disabled; + } + } + + render() { + const { disabled, labelDescription, labelTitle } = this; + + const labelClasses = classMap({ + [`${prefix}--file--label`]: true, + [`${prefix}--label-description--disabled`]: disabled, + }); + + const descriptionClasses = classMap({ + [`${prefix}--label-description`]: true, + [`${prefix}--label-description--disabled`]: disabled, + }); + + return html` +

    + ${labelTitle} +

    +

    + ${labelDescription} +

    + +
    + +
    + `; + } + + /** + * A selector that will return the `` to enter starting date. + */ + static get selectorUploaderItem() { + return `${prefix}-file-uploader-button,${prefix}-file-uploader-drop-container`; + } + + static styles = styles; +} + +export default CDSFileUploader; diff --git a/packages/web-components/src/components/file-uploader/index.ts b/packages/web-components/src/components/file-uploader/index.ts new file mode 100644 index 000000000000..84ae026ea8c2 --- /dev/null +++ b/packages/web-components/src/components/file-uploader/index.ts @@ -0,0 +1,14 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './file-uploader'; +import './file-uploader-item'; +import './file-uploader-drop-container'; +import './file-uploader-button'; +import './file-uploader-skeleton'; diff --git a/packages/web-components/src/components/file-uploader/stories/types.ts b/packages/web-components/src/components/file-uploader/stories/types.ts new file mode 100644 index 000000000000..b2c115c136ba --- /dev/null +++ b/packages/web-components/src/components/file-uploader/stories/types.ts @@ -0,0 +1,45 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { FILE_UPLOADER_ITEM_STATE } from '../file-uploader-item'; + +/** + * The data for each file uploaded. + */ +export interface FileData { + /** + * The unique ID. + */ + id: string; + + /** + * `true` if there is something wrong with the uploaded file. + */ + invalid?: boolean; + + /** + * The file blob data. + */ + file: File; + + /** + * The file uploading state. + */ + state: FILE_UPLOADER_ITEM_STATE; + + /** + * The subject error message. + */ + errorSubject?: string; + + /** + * The body error message. + */ + errorBody?: string; +} diff --git a/packages/web-components/src/components/floating-menu/defs.ts b/packages/web-components/src/components/floating-menu/defs.ts new file mode 100644 index 000000000000..95277146af72 --- /dev/null +++ b/packages/web-components/src/components/floating-menu/defs.ts @@ -0,0 +1,38 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * The LTR/RTL direction used for positioning floating menu. + */ +export enum FLOATING_MENU_POSITION_DIRECTION { + /** + * LTR. + */ + LTR = 'ltr', + + /** + * RTL. + */ + RTL = 'rtl', +} + +/** + * The direction/positioning/orientation choices of floating menu. + */ +export enum FLOATING_MENU_DIRECTION { + /** + * Put menu body at the top of its trigger button. + */ + TOP = 'top', + + /** + * Put menu body at the bottom of its trigger button. + */ + BOTTOM = 'bottom', +} diff --git a/packages/web-components/src/components/floating-menu/floating-menu-trigger.ts b/packages/web-components/src/components/floating-menu/floating-menu-trigger.ts new file mode 100644 index 000000000000..2ad8c0eef8a0 --- /dev/null +++ b/packages/web-components/src/components/floating-menu/floating-menu-trigger.ts @@ -0,0 +1,26 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * The interface of floating menus containing the trigger button. + */ +interface CDSFloatingMenuTrigger extends HTMLElement { + /** + * `true` if the menu should be open. + */ + open: boolean; + + /** + * The position of the trigger button. + */ + triggerPosition: ClientRect; +} + +// eslint-disable-next-line no-undef +export default CDSFloatingMenuTrigger; diff --git a/packages/web-components/src/components/floating-menu/floating-menu.ts b/packages/web-components/src/components/floating-menu/floating-menu.ts new file mode 100644 index 000000000000..36aadb38422c --- /dev/null +++ b/packages/web-components/src/components/floating-menu/floating-menu.ts @@ -0,0 +1,323 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement } from 'lit'; +import HostListener from '../../globals/decorators/host-listener'; +import FocusMixin from '../../globals/mixins/focus'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import Handle from '../../globals/internal/handle'; +import { + FLOATING_MENU_DIRECTION, + FLOATING_MENU_POSITION_DIRECTION, +} from './defs'; +import CDSFloatingMenuTrigger from './floating-menu-trigger'; +import { prefix } from '../../globals/settings'; + +export { FLOATING_MENU_DIRECTION, FLOATING_MENU_POSITION_DIRECTION }; + +/** + * Position of floating menu, or trigger button of floating menu. + */ +export interface FloatingMenuPosition { + /** + * The LTR/RTL direction used for positioning floating menu. + */ + direction: FLOATING_MENU_POSITION_DIRECTION; + + /** + * The start position (Left position for LTR, right position for RTL). + */ + start: number; + + /** + * The top position. + */ + top: number; +} + +/** + * Observes resize of the given element with the given resize observer. + * + * @param observer The resize observer. + * @param elem The element to observe the resize. + */ +const observeResize = (observer: ResizeObserver, elem: Element) => { + observer.observe(elem); + return { + release() { + observer.unobserve(elem); + return null; + }, + } as Handle; +}; + +/** + * @param elem The starting element. + * @param selector The CSS selector. + * @returns {Element} + * The closest ancestor node of the given element that matches the given selector, crossing Shadow DOM boundary. + */ +const closestComposed = (elem: Element, selector: string) => { + const found = elem.closest(selector); + if (found) { + return found; + } + const { host } = elem.getRootNode() as ShadowRoot; + if (host) { + return closestComposed(host, selector); + } + return null; +}; + +/** + * Floating menu. + */ +abstract class CDSFloatingMenu extends HostListenerMixin( + FocusMixin(LitElement) +) { + /** + * The handle for observing resize of the element containing the trigger button. + */ + private _hObserveResizeParent: Handle | null = null; + + /** + * The handle for observing resize of the floating menu container. + */ + private _hObserveResizeContainer: Handle | null = null; + + /** + * The `ResizeObserver` instance for observing element resizes for re-positioning floating menu position. + */ + // TODO: Wait for `.d.ts` update to support `ResizeObserver` + // @ts-ignore + private _resizeObserver = new ResizeObserver(() => { + const { container, open, parent, position } = this; + if (container && open && parent) { + const { direction, start, top } = position; + this.style[ + direction !== FLOATING_MENU_POSITION_DIRECTION.RTL ? 'left' : 'right' + ] = `${start}px`; + this.style.top = `${top}px`; + } + }); + + @HostListener('focusout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleBlur = ({ relatedTarget }: FocusEvent) => { + if (!this.contains(relatedTarget as Node)) { + const { parent } = this; + if (parent && parent !== relatedTarget) { + parent.open = false; + HTMLElement.prototype.focus.call(this.parent); // SVGElement in IE11 does not have `.focus()` method + } + } + }; + + @HostListener('click') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _click = () => { + const { parent } = this; + if (parent) { + parent.open = false; + } + }; + + @HostListener('keydown') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Tab') { + if (event.shiftKey) { + const { parent } = this; + if (parent) { + parent.open = false; + } + } + } + }; + + /** + * The DOM element, typically a custom element in this library, launching this floating menu. + */ + protected parent: CDSFloatingMenuTrigger | null = null; + + /** + * The menu direction. + */ + abstract direction: FLOATING_MENU_DIRECTION; + + /** + * `true` if the menu should be open. + */ + abstract open: boolean; + + /** + * `true` if the menu alignment should be flipped. + */ + abstract flipped: boolean; + + /** + * The DOM element to put this menu into. + */ + get container() { + return ( + closestComposed( + this, + (this.constructor as typeof CDSFloatingMenu).selectorContainer + ) || this.ownerDocument!.body + ); + } + + /** + * The position of this floating menu. + */ + get position(): FloatingMenuPosition { + const { triggerPosition } = this.parent!; + if (!triggerPosition) { + throw new TypeError('Missing information of trigger button position.'); + } + + const { container } = this; + const { + left: refLeft = 0, + top: refTop = 0, + right: refRight = 0, + } = triggerPosition; + let { bottom: refBottom = 0 } = triggerPosition; + const { width, height } = this.getBoundingClientRect(); + const { + left: containerLeft = 0, + right: containerRight = 0, + top: containerTop = 0, + } = container.getBoundingClientRect(); + refBottom = refBottom - containerTop; + + const containerComputedStyle = + container.ownerDocument!.defaultView!.getComputedStyle(container); + const positionDirection = containerComputedStyle.getPropertyValue( + 'direction' + ) as FLOATING_MENU_POSITION_DIRECTION; + const isRtl = positionDirection === FLOATING_MENU_POSITION_DIRECTION.RTL; + const containerStartFromViewport = !isRtl + ? containerLeft + : container.ownerDocument!.defaultView!.innerWidth - containerRight; + const refStartFromContainer = !isRtl + ? refLeft - containerLeft + : containerRight - refRight; + const refEndFromContainer = !isRtl + ? refRight - containerLeft + : containerRight - refLeft; + const refTopFromContainer = refTop - containerTop; + + if ( + (container !== this.ownerDocument!.body || + containerStartFromViewport !== 0 || + containerTop !== 0) && + containerComputedStyle.getPropertyValue('position') === 'static' + ) { + throw new Error( + 'Floating menu container must not have `position:static`.' + ); + } + + const { flipped, direction } = this; + if (Object.values(FLOATING_MENU_DIRECTION).indexOf(direction) < 0) { + throw new Error(`Wrong menu position direction: ${direction}`); + } + + const alignmentStart = flipped + ? refEndFromContainer - width + : refStartFromContainer; + + const { start, top } = { + [FLOATING_MENU_DIRECTION.TOP]: () => ({ + start: alignmentStart, + top: refTopFromContainer - height, + }), + [FLOATING_MENU_DIRECTION.BOTTOM]: () => ({ + start: alignmentStart, + top: refBottom, + }), + }[direction](); + + return { + direction: positionDirection, + start, + top, + }; + } + + disconnectedCallback() { + if (this._hObserveResizeContainer) { + this._hObserveResizeContainer = this._hObserveResizeContainer.release(); + } + if (this._hObserveResizeParent) { + this._hObserveResizeParent = this._hObserveResizeParent.release(); + } + } + + updated(changedProperties) { + const { container, open, parent } = this; + if ( + (changedProperties.has('flipped') || + changedProperties.has('direction') || + changedProperties.has('open')) && + open + ) { + if (!parent) { + this.parent = this.parentElement as CDSFloatingMenuTrigger; + container.appendChild(this); + } + // Note: `this.position` cannot be referenced until `this.parent` is set + const { direction, start, top } = this.position; + this.style[ + direction !== FLOATING_MENU_POSITION_DIRECTION.RTL ? 'left' : 'right' + ] = `${start}px`; + this.style.top = `${top}px`; + } + if (changedProperties.has('open')) { + if (this._hObserveResizeContainer) { + this._hObserveResizeContainer = this._hObserveResizeContainer.release(); + } + if (this._hObserveResizeParent) { + this._hObserveResizeParent = this._hObserveResizeParent.release(); + } + if (open) { + const { parentElement } = this.parent ?? {}; + this._hObserveResizeContainer = observeResize( + this._resizeObserver, + container + ); + if (parentElement) { + this._hObserveResizeParent = observeResize( + this._resizeObserver, + parentElement + ); + } + } + } + } + + /** + * A constant indicating that this class is a floating menu. + */ + static FLOATING_MENU = true; + + /** + * The CSS selector to find the element to put this floating menu in. + */ + static get selectorContainer() { + return `[data-floating-menu-container],${prefix}-modal`; + } + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; +} + +export default CDSFloatingMenu; diff --git a/packages/web-components/src/components/floating-menu/index.ts b/packages/web-components/src/components/floating-menu/index.ts new file mode 100644 index 000000000000..97ef65de0a0a --- /dev/null +++ b/packages/web-components/src/components/floating-menu/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './floating-menu'; diff --git a/packages/web-components/src/components/form-group/form-group.mdx b/packages/web-components/src/components/form-group/form-group.mdx new file mode 100644 index 000000000000..bb46fb253811 --- /dev/null +++ b/packages/web-components/src/components/form-group/form-group.mdx @@ -0,0 +1,63 @@ +import { ArgTypes, Meta, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as FormGroupStories from './form-group.stories'; + + + +# Form Group + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/form-group) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/form-group) + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/form-group/index.js'; +``` + +{`${cdnJs({ components: ['form-group'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + + + + + + + + + Submit + + +``` + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `message` attribute). + + diff --git a/packages/web-components/src/components/form-group/form-group.scss b/packages/web-components/src/components/form-group/form-group.scss new file mode 100644 index 000000000000..07d273196e91 --- /dev/null +++ b/packages/web-components/src/components/form-group/form-group.scss @@ -0,0 +1,23 @@ +// +// Copyright IBM Corp. 2020, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/type' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/components/form/index' as *; + +:host(#{$prefix}-form-group) fieldset { + @extend .#{$prefix}--fieldset; + + padding: 0; + border: 0; + margin: 0; + font: inherit; + font-size: 100%; + vertical-align: baseline; +} diff --git a/packages/web-components/src/components/form-group/form-group.stories.ts b/packages/web-components/src/components/form-group/form-group.stories.ts new file mode 100644 index 000000000000..ac10584d9f5b --- /dev/null +++ b/packages/web-components/src/components/form-group/form-group.stories.ts @@ -0,0 +1,116 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import './form-group'; +import '../text-input'; +import '../stack'; +import '../radio-button/index'; +import '../button'; + +const args = { + legendText: 'FormGroup Legend', + message: false, +}; + +const argTypes = { + legendText: { + control: 'text', + description: 'Provide the text to be rendered inside of the fieldset.', + }, + message: { + control: 'boolean', + description: + 'Specify whether the message should be displayed in the form group.', + }, + messageText: { + control: 'text', + description: 'Provide the text for the message in the form group.', + }, +}; + +export const Default = { + render: () => { + return html` + + + + + + + + + + Submit + + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { legendText, message, messageText } = args ?? {}; + return html` + + + + + + + + + + Submit + + + `; + }, +}; + +const meta = { + title: 'Components/Form Group', + decorators: [ + (story) => { + return html`
    ${story()}
    `; + }, + ], +}; + +export default meta; diff --git a/packages/web-components/src/components/form-group/form-group.ts b/packages/web-components/src/components/form-group/form-group.ts new file mode 100644 index 000000000000..ee072770a2c9 --- /dev/null +++ b/packages/web-components/src/components/form-group/form-group.ts @@ -0,0 +1,78 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { prefix } from '../../globals/settings'; +import styles from './form-group.scss?lit'; + +/** + * The shell UI for file uploader. + * + * @element cds-form-group + * @slot label-title. + * @slot lebel-description. + */ +@customElement(`${prefix}-form-group`) +class CDSFormGroup extends LitElement { + /** + * Specify whether the Form Group is invalid + */ + @property({ type: Boolean, reflect: true }) + invalid = false; + + /** + * Provide id for the fieldset which corresponds to the fieldset + * `aria-labelledby` + */ + @property({ attribute: 'legend-id' }) + legendId; + + /** + * Provide the text to be rendered inside of the fieldset + */ + @property({ attribute: 'legend-text' }) + legendText!: string; + + /** + * Specify whether the message should be displayed in the Form Group + */ + @property({ type: Boolean, reflect: true }) + message = false; + + /** + * Provide the text for the message in the Form Group + */ + @property({ type: String, attribute: 'message-text', reflect: true }) + messageText; + + render() { + const { invalid, legendId, legendText, message, messageText } = this; + + return html` +
    + ${legendText} + + ${message + ? html`
    + ${messageText} +
    ` + : null} +
    + `; + } + + static styles = styles; +} + +export default CDSFormGroup; diff --git a/packages/web-components/src/components/form-group/index.ts b/packages/web-components/src/components/form-group/index.ts new file mode 100644 index 000000000000..0867b33ac76e --- /dev/null +++ b/packages/web-components/src/components/form-group/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './form-group'; diff --git a/packages/web-components/src/components/form/form-data.md b/packages/web-components/src/components/form/form-data.md new file mode 100644 index 000000000000..aaa2027498d0 --- /dev/null +++ b/packages/web-components/src/components/form/form-data.md @@ -0,0 +1,84 @@ +# Event-based form participation + +This document is for assessing if `carbon-web-components` library can support +event-based form participation spec, as a stop-gap solution until full-blown +[form-associated custom element API](https://github.com/whatwg/html/pull/4383) +in order for our components to support use cases seen e.g. with `` in +``. + +## Specifications and tests + +### `formdata` event + +- Explainer: + https://docs.google.com/document/d/1JO8puctCSpW-ZYGU8lF-h4FWRIDQNDVexzHoOQ2iQmY/edit +- Spec: https://github.com/whatwg/html/pull/4239 +- Tests: + - https://github.com/web-platform-tests/wpt/pull/14637 + - https://github.com/web-platform-tests/wpt/pull/18910 + +## Browser support + +### `formdata` event + +- Chrome: + [Starting Chrome 77](https://bugs.chromium.org/p/chromium/issues/detail?id=825684) +- Firefox: + [Starting Firefox 71](https://bugzilla.mozilla.org/show_bug.cgi?id=1518442) +- Safari: [No roadmap yet](https://bugs.webkit.org/show_bug.cgi?id=193231) + +### `FormData` object + +Supported by all major browsers including IE11: +https://developer.mozilla.org/en-US/docs/Web/API/FormData + +## Behaviours + +- `formdata` event bubbles, not cancelable, not composed. +- `formdata` event is fired on ``, upon submitting it. (e.g. upon + `HTMLFormElement#submit()` call) + +## The story with full-blown form-associated custom element API + +From the +[explainer](https://docs.google.com/document/d/1JO8puctCSpW-ZYGU8lF-h4FWRIDQNDVexzHoOQ2iQmY/edit#heading=h.m351ojpczvcd): + +> UA handles them as submittable elements. In constructing the entry list +> algorithm, UA creates an entry with name attribute value of the +> form-associated custom element, and the value set by `setFormValue()` of +> `ElementInternals` interface. Authors don’t need to register `formdata` event +> handlers. + +## What we do for now + +Our components code handles `formdata` event for the time being (until we are +ready, which means full-blown form-associated custom element API is supported by +all browsers we support), and switches to full-blown form-associated custom +element API once we are ready. + +## Non-goal: High-fidelity shim/polyfill + +Instead, it's likely that we merely define `formdata` event handler in our +custom elements (components). One scenario in mind is application manually fires +`formdata` event (upon user's gesture on form submit button, etc.) to let our +components populate `event.formData`, and run XHR/`fetch()` with the populated +`event.formData`. + +## Non-goal: Feature-detection of full-blown form-associated custom element API + +Given we require application to manually handle user's gesture for form +submission, and manually handle the data gathered from `formdata` event, +feature-detection of full-blown form-associated custom element API means that +application needs to maintain two codebase to use our components, one for +browsers with full-blown form-associated custom element API, one without. That +said, we are not likely to do feature-detection of full-blown form-associated +custom element API, at least for now. + +## Non-goal: Supporting constraint validation API + +For supporting +[constraint validation API](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-constraint-validation-api), +i.e. `checkValidity()`/`reportValidity()` and `invalid` event, etc., we'll wait +for full-blown +[form-associated custom element API](https://github.com/whatwg/html/pull/4383) +being available in all browsers we support. diff --git a/packages/web-components/src/components/form/form-item.scss b/packages/web-components/src/components/form/form-item.scss new file mode 100644 index 000000000000..128e634d26e5 --- /dev/null +++ b/packages/web-components/src/components/form/form-item.scss @@ -0,0 +1,15 @@ +// +// Copyright IBM Corp. 2019, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/components/form'; + +:host(#{$prefix}-form-item) { + @extend .#{$prefix}--form-item; +} diff --git a/packages/web-components/src/components/form/form-item.ts b/packages/web-components/src/components/form/form-item.ts new file mode 100644 index 000000000000..49db42c64277 --- /dev/null +++ b/packages/web-components/src/components/form/form-item.ts @@ -0,0 +1,29 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './form-item.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Presentational element for form items + * + * @element cds-form-item + */ +@customElement(`${prefix}-form-item`) +class CDSFormItem extends LitElement { + render() { + return html` `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSFormItem; diff --git a/packages/web-components/src/components/form/index.ts b/packages/web-components/src/components/form/index.ts new file mode 100644 index 000000000000..9625990ee685 --- /dev/null +++ b/packages/web-components/src/components/form/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './form-item'; diff --git a/packages/web-components/src/components/icon-button/defs.ts b/packages/web-components/src/components/icon-button/defs.ts new file mode 100644 index 000000000000..89b81398860e --- /dev/null +++ b/packages/web-components/src/components/icon-button/defs.ts @@ -0,0 +1,73 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Icon Button size. + */ +export enum ICON_BUTTON_SIZE { + /** + * Small size. + */ + SMALL = 'sm', + + /** + * Medium size. + */ + MEDIUM = 'md', + + /** + * Large size. + */ + LARGE = 'lg', +} + +/** + * Icon Button Tooltip alignment. + */ +export enum ICON_BUTTON_TOOLTIP_ALIGNMENT { + /** + * Align the top position for the tooltip content. + */ + TOP = 'top', + + /** + * Align the top-left position for the tooltip content. + */ + TOP_LEFT = 'top-left', + + /** + * Align the top right position for the tooltip content. + */ + TOP_RIGHT = 'top-right', + + /** + * Align the bottom position for the tooltip content. + */ + BOTTOM = 'bottom', + + /** + * Align the bottom left position for the tooltip content. + */ + BOTTOM_LEFT = 'bottom-left', + + /** + * Align the bottom right position for the tooltip content. + */ + BOTTOM_RIGHT = 'bottom-right', + + /** + * Align the left position for the tooltip content. + */ + LEFT = 'left', + + /** + * Align the right position for the tooltip content. + */ + RIGHT = 'right', +} diff --git a/packages/web-components/src/components/icon-button/icon-button.mdx b/packages/web-components/src/components/icon-button/icon-button.mdx new file mode 100644 index 000000000000..e89aa6f11dc7 --- /dev/null +++ b/packages/web-components/src/components/icon-button/icon-button.mdx @@ -0,0 +1,47 @@ +import { ArgTypes, Meta, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as IconButtonStories from './icon-button.stories'; + + + +# Icon Button + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/icon-button) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/icon-button) + +The `icon-button` component is useful when you have a button where the content +is an icon. In this situation, it's important that the button itself is labeled +in a way that can be understandable by mouse, keyboard, and screen readers. As a +result, this component makes it easy to create accessible icon buttons + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/icon-button/index.js'; +``` + +{`${cdnJs({ components: ['icon-button'] })}`} +{`${cdnCss()}`} + +```javascript +import '@carbon/web-components/es/components/icon-button/index.js'; +import Edit16 from '@carbon/icons/lib/edit/16'; + +function App() { + return html` + ${Edit16({ slot: 'icon' })} + Tooltip text + `; +} +``` + +## `` attributes and properties + + diff --git a/packages/web-components/src/components/icon-button/icon-button.scss b/packages/web-components/src/components/icon-button/icon-button.scss new file mode 100644 index 000000000000..f8fed4d72833 --- /dev/null +++ b/packages/web-components/src/components/icon-button/icon-button.scss @@ -0,0 +1,24 @@ +// +// Copyright IBM Corp. 2019, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/breakpoint' as *; +@use '@carbon/styles/scss/layout' as *; +@use '@carbon/styles/scss/theme' as *; +@use '../tooltip/tooltip'; +@use '../button/button'; + +:host(#{$prefix}-icon-button) { + @include emit-layout-tokens(); +} + +:host(#{$prefix}-icon-button[kind='ghost']) ::slotted([slot='icon']) { + color: $icon-primary; +} diff --git a/packages/web-components/src/components/icon-button/icon-button.stories.ts b/packages/web-components/src/components/icon-button/icon-button.stories.ts new file mode 100644 index 000000000000..d2fa901bee63 --- /dev/null +++ b/packages/web-components/src/components/icon-button/icon-button.stories.ts @@ -0,0 +1,152 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './index'; +import '../button/index'; +import { ICON_BUTTON_TOOLTIP_ALIGNMENT } from './defs'; +import Edit16 from '@carbon/icons/lib/edit/16'; +import { ICON_BUTTON_SIZE } from './defs'; +import { BUTTON_KIND } from '../button/defs'; + +const kinds = { + [`Primary button (${BUTTON_KIND.PRIMARY})`]: BUTTON_KIND.PRIMARY, + [`Secondary button (${BUTTON_KIND.SECONDARY})`]: BUTTON_KIND.SECONDARY, + [`Tertiary button (${BUTTON_KIND.TERTIARY})`]: BUTTON_KIND.TERTIARY, + [`Danger button (${BUTTON_KIND.DANGER})`]: BUTTON_KIND.DANGER, + [`Danger tertiary button (${BUTTON_KIND.DANGER_TERTIARY})`]: + BUTTON_KIND.DANGER_TERTIARY, + [`Danger ghost button (${BUTTON_KIND.DANGER_GHOST})`]: + BUTTON_KIND.DANGER_GHOST, + [`Ghost button (${BUTTON_KIND.GHOST})`]: BUTTON_KIND.GHOST, +}; + +const tooltipAlignments = { + [`top`]: ICON_BUTTON_TOOLTIP_ALIGNMENT.TOP, + [`top-left`]: ICON_BUTTON_TOOLTIP_ALIGNMENT.TOP_LEFT, + [`top-right`]: ICON_BUTTON_TOOLTIP_ALIGNMENT.TOP_RIGHT, + [`bottom`]: ICON_BUTTON_TOOLTIP_ALIGNMENT.BOTTOM, + [`bottom-left`]: ICON_BUTTON_TOOLTIP_ALIGNMENT.BOTTOM_LEFT, + [`bottom-right`]: ICON_BUTTON_TOOLTIP_ALIGNMENT.BOTTOM_RIGHT, + [`left`]: ICON_BUTTON_TOOLTIP_ALIGNMENT.LEFT, + [`right`]: ICON_BUTTON_TOOLTIP_ALIGNMENT.RIGHT, +}; + +const args = { + align: ICON_BUTTON_TOOLTIP_ALIGNMENT.BOTTOM, + defaultOpen: true, + disabled: false, + isSelected: false, + kind: BUTTON_KIND.PRIMARY, + label: 'Custom label', + size: ICON_BUTTON_SIZE.MEDIUM, +}; + +const argTypes = { + align: { + control: 'select', + description: 'Specify how the trigger should align with the tooltip.', + options: tooltipAlignments, + }, + closeOnActivation: { + control: 'boolean', + description: + 'Determines whether the tooltip should close when inner content is activated (click, Enter or Space).', + }, + defaultOpen: { + control: 'boolean', + description: + 'Specify whether the tooltip should be open when it first renders.', + }, + disabled: { + control: 'boolean', + description: 'Specify whether the Button should be disabled, or not.', + }, + enterDelayMs: { + control: 'number', + description: + 'Specify the duration in milliseconds to delay before displaying the tooltip.', + }, + isSelected: { + control: 'boolean', + description: 'Specify whether the Icon Button is currently selected.', + }, + kind: { + control: 'select', + description: + 'Specify the type of button to be used as the base for the Icon Button.', + options: kinds, + }, + label: { + control: 'text', + description: + 'Provide the label to be rendered inside of the Tooltip. The label will use aria-labelledby and will fully describe the child node that is provided. This means that if you have text in the child node it will not be announced to the screen reader.', + }, + leaveDelayMs: { + control: 'number', + description: + 'Specify the duration in milliseconds to delay before hiding the tooltip.', + }, + size: { + control: 'select', + description: 'Specify the size of the Button. Defaults to md.', + options: ICON_BUTTON_SIZE, + }, +}; + +export const Default = { + render: () => { + return html` + + ${Edit16({ slot: 'icon' })} + label + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: ({ + align, + closeOnActivation, + defaultOpen, + disabled, + enterDelayMs, + isSelected, + kind, + label, + leaveDelayMs, + size, + }) => { + return html` + + ${Edit16({ slot: 'icon' })} + ${label} + + `; + }, +}; + +const meta = { + decorators: [(story) => html`
    ${story()}
    `], + title: 'Components/Icon Button', +}; + +export default meta; diff --git a/packages/web-components/src/components/icon-button/icon-button.ts b/packages/web-components/src/components/icon-button/icon-button.ts new file mode 100644 index 000000000000..54056bb174e8 --- /dev/null +++ b/packages/web-components/src/components/icon-button/icon-button.ts @@ -0,0 +1,121 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { prefix } from '../../globals/settings'; +import '../tooltip/index'; +import '../button/index'; +import CDSButton from '../button/button'; +import { ICON_BUTTON_SIZE, ICON_BUTTON_TOOLTIP_ALIGNMENT } from './defs'; +import styles from './icon-button.scss?lit'; + +export { ICON_BUTTON_SIZE, ICON_BUTTON_TOOLTIP_ALIGNMENT }; + +/** + * Icon Button + * + */ +@customElement(`${prefix}-icon-button`) +class CDSIconButton extends CDSButton { + /** + * Specify how the trigger should align with the tooltip + */ + @property({ reflect: true, type: String }) + align = 'top'; + + /** + * Specify whether a auto align functionality should be applied + */ + @property({ type: Boolean, reflect: true }) + autoalign = false; + + /** + * Determines whether the tooltip should close when inner content is activated (click, Enter or Space) + */ + @property({ attribute: 'close-on-activation', reflect: true, type: Boolean }) + closeOnActivation = true; + + /** + * Specify whether the tooltip should be open when it first renders + */ + @property({ reflect: true, type: Boolean }) + defaultOpen = false; + + /** + * Specify the duration in milliseconds to delay before displaying the tooltip + */ + @property({ attribute: 'enter-delay-ms', type: Number }) + enterDelayMs = 100; + + /** + * Specify the duration in milliseconds to delay before hiding the tooltip + */ + @property({ attribute: 'leave-delay-ms', type: Number }) + leaveDelayMs = 300; + + /** + * Specify the size of the Button. Defaults to `md`. + */ + @property({ reflect: true }) + size = 'md'; + + updated(changedProperties) { + if (changedProperties) { + this.shadowRoot + ?.querySelector(`${prefix}-tooltip`) + ?.shadowRoot?.querySelector(`.${prefix}--tooltip`) + ?.classList.add(`${prefix}--icon-tooltip`); + + const tooltipContent = this.querySelector( + '[slot=tooltip-content]' + )?.textContent; + this.shadowRoot + ?.querySelector(`${prefix}-tooltip`) + ?.querySelector(`button`) + ?.setAttribute('aria-label', String(tooltipContent)); + } + } + + // eslint-disable-next-line class-methods-use-this + protected _renderTooltipContent() { + return html` + + + + `; + } + + render() { + const { + align, + autoalign, + closeOnActivation, + defaultOpen, + enterDelayMs, + leaveDelayMs, + } = this; + return html` + + ${super.render()} ${this._renderTooltipContent()} + + `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSIconButton; diff --git a/packages/web-components/src/components/icon-button/index.ts b/packages/web-components/src/components/icon-button/index.ts new file mode 100644 index 000000000000..eccadabc6353 --- /dev/null +++ b/packages/web-components/src/components/icon-button/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './icon-button'; diff --git a/packages/web-components/src/components/icon/docs/overview.mdx b/packages/web-components/src/components/icon/docs/overview.mdx new file mode 100644 index 000000000000..0872f025245b --- /dev/null +++ b/packages/web-components/src/components/icon/docs/overview.mdx @@ -0,0 +1,24 @@ +## Live demo + + diff --git a/packages/web-components/src/components/icon/icon.mdx b/packages/web-components/src/components/icon/icon.mdx new file mode 100644 index 000000000000..e0f79f5679cc --- /dev/null +++ b/packages/web-components/src/components/icon/icon.mdx @@ -0,0 +1,31 @@ +import { ArgTypes, Meta } from "@storybook/blocks"; +import * as IconStories from "./icon.stories"; + + + +# Icon + +Icons can be utilized by specifying the icon name and size in the import. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import Add16 from '@carbon/icons/lib/add/16'; + +function App() { + return ( + html` + ${Add16({ + class: 'test-class', + 'aria-label': 'add', + 'aria-describedby': 'id-title-1', + children: svg`add`, })}` + ); +``` + +Icon library can be found +[here](https://www.carbondesignsystem.com/guidelines/icons/library). diff --git a/packages/web-components/src/components/icon/icon.stories.ts b/packages/web-components/src/components/icon/icon.stories.ts new file mode 100644 index 000000000000..9cee6aad6f22 --- /dev/null +++ b/packages/web-components/src/components/icon/icon.stories.ts @@ -0,0 +1,78 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html, svg } from 'lit'; + +// Below path will be there when an application installs `@carbon/web-components` package. +// In our dev env, we auto-generate the file and re-map below path to to point to the generated file. +// @ts-ignore +import Add16 from '@carbon/icons/lib/add/16'; +// @ts-ignore +import Add20 from '@carbon/icons/lib/add/20'; +// @ts-ignore +import Add24 from '@carbon/icons/lib/add/24'; +// @ts-ignore +import Add32 from '@carbon/icons/lib/add/32'; + +export const Default = { + render: () => html` ${Add16()} ${Add20()} ${Add24()} ${Add32()} `, +}; + +export const withCustomClass = { + name: 'With custom class', + render: () => html` + + ${Add16({ class: 'test-class' })} ${Add20({ class: 'test-class' })} + ${Add24({ class: 'test-class' })} ${Add32({ class: 'test-class' })} + `, +}; + +export const withAriaLabel = { + name: 'With aria label', + render: () => html` + ${Add16({ 'aria-label': 'add' })} ${Add20({ 'aria-label': 'add' })} + ${Add24({ 'aria-label': 'add' })} ${Add32({ 'aria-label': 'add' })} + `, +}; + +export const withTitle = { + name: 'With title', + render: () => html` + ${Add16({ + 'aria-describedby': 'id-title-1', + // @ts-ignore + children: svg`add`, + })} + ${Add20({ + 'aria-describedby': 'id-title-2', + // @ts-ignore + children: svg`add`, + })} + ${Add24({ + 'aria-describedby': 'id-title-3', + // @ts-ignore + children: svg`add`, + })} + ${Add32({ + 'aria-describedby': 'id-title-4', + // @ts-ignore + children: svg`add`, + })} + `, +}; + +const meta = { + title: 'Components/Icon', +}; + +export default meta; diff --git a/packages/web-components/src/components/inline-loading/defs.ts b/packages/web-components/src/components/inline-loading/defs.ts new file mode 100644 index 000000000000..3cf264728cdf --- /dev/null +++ b/packages/web-components/src/components/inline-loading/defs.ts @@ -0,0 +1,33 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Loading state for inline loading spinner. + */ +export enum INLINE_LOADING_STATE { + /** + * Inactive state. + */ + INACTIVE = 'inactive', + + /** + * State for loading in progress. + */ + ACTIVE = 'active', + + /** + * State for loading successful. + */ + FINISHED = 'finished', + + /** + * State for loading failure. + */ + ERROR = 'error', +} diff --git a/packages/web-components/src/components/inline-loading/docs/overview.mdx b/packages/web-components/src/components/inline-loading/docs/overview.mdx new file mode 100644 index 000000000000..e5386c32cc53 --- /dev/null +++ b/packages/web-components/src/components/inline-loading/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/inline-loading/index.ts b/packages/web-components/src/components/inline-loading/index.ts new file mode 100644 index 000000000000..33fd8bc0babf --- /dev/null +++ b/packages/web-components/src/components/inline-loading/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './inline-loading'; diff --git a/packages/web-components/src/components/inline-loading/inline-loading.mdx b/packages/web-components/src/components/inline-loading/inline-loading.mdx new file mode 100644 index 000000000000..a5f1e6fa236b --- /dev/null +++ b/packages/web-components/src/components/inline-loading/inline-loading.mdx @@ -0,0 +1,47 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as InlineLoadingStories from './inline-loading.stories'; + + + +# Inline loading + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/inline-loading) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/inline-loading) + +Inline loading spinners are used when performing actions. They help notify +user’s that their action is being processed. The waiting experience is a crucial +design opportunity. Although it may not be obvious what is occurring on the +back-end, we can communicate clearly to reassure the user that progress is +happening. + +It is best practice to use an Inline loading component for any Create, Update, +or Delete actions. The component provides feedback to the user about the +progress of the action they took. This could be in a table, after a primary or +secondary button click, or even in a modal. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/inline-loading/index.js'; +``` + +{`${cdnJs({ components: ['inline-loading'] })}`} +{`${cdnCss()}`} + +### HTML + +```html +Loading data... +``` + +## `` attributes and properties + + diff --git a/packages/web-components/src/components/inline-loading/inline-loading.scss b/packages/web-components/src/components/inline-loading/inline-loading.scss new file mode 100644 index 000000000000..73e90d7bec7c --- /dev/null +++ b/packages/web-components/src/components/inline-loading/inline-loading.scss @@ -0,0 +1,18 @@ +// +// Copyright IBM Corp. 2019, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/type'; +@use '@carbon/styles/scss/components/loading'; +@use '@carbon/styles/scss/components/inline-loading/inline-loading' as *; + +@include inline-loading; + +:host(#{$prefix}-inline-loading) { + @extend .#{$prefix}--inline-loading; +} diff --git a/packages/web-components/src/components/inline-loading/inline-loading.stories.ts b/packages/web-components/src/components/inline-loading/inline-loading.stories.ts new file mode 100644 index 000000000000..46c8f741f75d --- /dev/null +++ b/packages/web-components/src/components/inline-loading/inline-loading.stories.ts @@ -0,0 +1,67 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { INLINE_LOADING_STATE } from './inline-loading'; + +const states = { + [`Inactive (${INLINE_LOADING_STATE.INACTIVE})`]: + INLINE_LOADING_STATE.INACTIVE, + [`Active (${INLINE_LOADING_STATE.ACTIVE})`]: INLINE_LOADING_STATE.ACTIVE, + [`Finished (${INLINE_LOADING_STATE.FINISHED})`]: + INLINE_LOADING_STATE.FINISHED, + [`Failed (${INLINE_LOADING_STATE.ERROR})`]: INLINE_LOADING_STATE.ERROR, +}; + +const defaultArgs = { + description: 'Loading data...', + assistiveText: 'Loading', + status: INLINE_LOADING_STATE.ACTIVE, +}; + +const controls = { + description: { + control: 'text', + description: 'Specify the description for the inline loading text.', + }, + assistiveText: { + control: 'text', + description: + 'Specify a description that would be used to best describe the loading state.', + }, + status: { + control: 'select', + description: 'Specify the loading status.', + options: states, + }, +}; + +export const Default = { + render: () => html`Loading data...`, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + parameters: { + percy: { skip: true }, + }, + render: ({ assistiveText, description, status }) => + html` + + ${description} + + `, +}; + +const meta = { + title: 'Components/Inline loading', +}; + +export default meta; diff --git a/packages/web-components/src/components/inline-loading/inline-loading.ts b/packages/web-components/src/components/inline-loading/inline-loading.ts new file mode 100644 index 000000000000..f0cabe8df1e9 --- /dev/null +++ b/packages/web-components/src/components/inline-loading/inline-loading.ts @@ -0,0 +1,101 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import CheckmarkFilled16 from '@carbon/icons/lib/checkmark--filled/16'; +import ErrorFilled16 from '@carbon/icons/lib/error--filled/16'; +import { prefix } from '../../globals/settings'; +import LOADING_TYPE from '../loading/types'; +import getLoadingIcon from '../loading/loading-icon'; +import { INLINE_LOADING_STATE } from './defs'; +import styles from './inline-loading.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { INLINE_LOADING_STATE }; + +/** + * Lnline loading spinner. + * + * @element cds-inline-loading + */ +@customElement(`${prefix}-inline-loading`) +class CDSInlineLoading extends LitElement { + /** + * The assistive text for the spinner icon. + */ + @property({ attribute: 'assistive-text' }) + assistiveText = 'Loading'; + + /** + * @returns The template for the status icon. + */ + private _renderIcon() { + const { assistiveText, status } = this; + if (status === INLINE_LOADING_STATE.ERROR) { + return ErrorFilled16({ + class: `${prefix}--inline-loading--error`, + }); + } + if (status === INLINE_LOADING_STATE.FINISHED) { + return CheckmarkFilled16({ + class: `${prefix}--inline-loading__checkmark-container`, + }); + } + if ( + status === INLINE_LOADING_STATE.INACTIVE || + status === INLINE_LOADING_STATE.ACTIVE + ) { + const classes = classMap({ + [`${prefix}--loading`]: true, + [`${prefix}--loading--small`]: true, + [`${prefix}--loading--stop`]: status === INLINE_LOADING_STATE.INACTIVE, + }); + return html` +
    + ${getLoadingIcon({ assistiveText, type: LOADING_TYPE.SMALL })} +
    + `; + } + return undefined; + } + + /** + * The loading status. + */ + @property({ reflect: true }) + status = INLINE_LOADING_STATE.ACTIVE; + + connectedCallback() { + if (!this.hasAttribute('aria-live')) { + this.setAttribute('aria-live', 'assertive'); + } + super.connectedCallback(); + } + + render() { + const statusIconResult = this._renderIcon(); + const statusIconWrapperResult = !statusIconResult + ? undefined + : html` +
    + ${statusIconResult} +
    + `; + return html` + ${statusIconWrapperResult} +

    + `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSInlineLoading; diff --git a/packages/web-components/src/components/input/docs/overview.mdx b/packages/web-components/src/components/input/docs/overview.mdx new file mode 100644 index 000000000000..76de69388070 --- /dev/null +++ b/packages/web-components/src/components/input/docs/overview.mdx @@ -0,0 +1,20 @@ +## Live demo + + diff --git a/packages/web-components/src/components/layer/index.ts b/packages/web-components/src/components/layer/index.ts new file mode 100644 index 000000000000..b64000f6bf05 --- /dev/null +++ b/packages/web-components/src/components/layer/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './layer'; diff --git a/packages/web-components/src/components/layer/layer-story.scss b/packages/web-components/src/components/layer/layer-story.scss new file mode 100644 index 000000000000..a3fbef8cf635 --- /dev/null +++ b/packages/web-components/src/components/layer/layer-story.scss @@ -0,0 +1,15 @@ +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; + +.example-layer-test-component { + padding: $spacing-05; + background: $layer; + color: $text-primary; +} diff --git a/packages/web-components/src/components/layer/layer.mdx b/packages/web-components/src/components/layer/layer.mdx new file mode 100644 index 000000000000..09caeeef02b8 --- /dev/null +++ b/packages/web-components/src/components/layer/layer.mdx @@ -0,0 +1,114 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as LayerStories from './layer.stories'; + + + +# Layer + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/layer) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/layer) + +The `Layer` component is used to render components on different layers. Each +layer has a specific set of token values associated with it. You can use these +tokens directly, or use contextual tokens from our styles package like `$layer` +or `$field`. + +The `Layer` component accepts any `children`. Each child of a `Layer` component +is rendered using the layer tokens at that layer. `Layer` components can be +nested indefinitely, but the token sets typically end after 3 layers. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/layer/index.js'; +``` + +{`${cdnJs({ components: ['layer'] })}`} +{`${cdnCss()}`} + +### HTML + +Here we define a custom test class to define a custom padding. + +```css +.example-layer-test-component { + padding: 1rem; +} +``` + +```html + +
    Layer 1
    + +
    Layer 2
    + +
    Layer 3
    +
    +
    +
    +``` + +## Setting a custom level + +You can override the `level` of a `Layer` if you would like to change the +presentation of a layer in your application. This is particularly helpful if you +would like to reset the `Layer` level back to `0` or if you want to make sure a +part of a page always renders in a certain level. + +```html + +
    Layer 1
    + +
    Layer 1 as well
    + +
    Layer 2
    +
    +
    +
    +``` + +## Get the current layer + +If you are building a component and would like to know what layer the component +resides within, you can use the `cds-use-layer` event. + +This event returns a `CustomEvent` with the current element firing the event, as +well as its layer: + +```js + document.addEventListener(`${prefix}-use-layer`, (e) => { + const { layer, level } = (e as any).detail; + + // use values here + }) +``` + +If the structure of `Layer` components in your app change, the event will +automatically fire with the new level. + +The level value can be one of: 0, 1, or 2 and will correspond to the level of +the current layer. This value mirrors the level prop on the Layer component. + +## Layer role + +As `Layer` is effectively a container component, and you can configure what the +`Layer` should be seen as in the DOM using `role`. For example, if you would +like the Layer component to be seen as a section you could write the following: + +```html + +
    Layer 1
    +
    +``` + +## `` attributes, properties and events + + diff --git a/packages/web-components/src/components/layer/layer.scss b/packages/web-components/src/components/layer/layer.scss new file mode 100644 index 000000000000..6a07642a0ab6 --- /dev/null +++ b/packages/web-components/src/components/layer/layer.scss @@ -0,0 +1,23 @@ +// +// Copyright IBM Corp. 2019, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/layer' as *; +@use '@carbon/styles/scss/config' as *; + +:host(#{$prefix}-layer[level='0']) { + @extend .#{$prefix}--layer-one; +} + +:host(#{$prefix}-layer[level='1']) { + @extend .#{$prefix}--layer-two; +} + +:host(#{$prefix}-layer[level='2']) { + @extend .#{$prefix}--layer-three; +} diff --git a/packages/web-components/src/components/layer/layer.stories.ts b/packages/web-components/src/components/layer/layer.stories.ts new file mode 100644 index 000000000000..c3cefb394567 --- /dev/null +++ b/packages/web-components/src/components/layer/layer.stories.ts @@ -0,0 +1,108 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './layer-story.scss?lit'; +import './index'; + +const levels = { + 'First layer': '0', + 'Second layer': '1', + 'Third layer': '2', +}; + +const defaultArgs = { + level: '0', +}; + +const controls = { + level: { + control: 'radio', + options: levels, + description: `Specify the layer level.`, + }, +}; + +export const Default = { + render: () => html` + +
    Test component
    + +
    Test component
    + +
    Test component
    +
    +
    +
    + + `, +}; + +export const CustomLevel = { + name: 'Custom level', + render: () => html` + +
    Test component
    +
    + + `, +}; + +export const UseLayer = { + name: 'useLayer', + render: () => { + document.addEventListener(`${prefix}-use-layer`, (e) => { + const { layer, level } = (e as any).detail; + layer.querySelector( + '.example-layer-test-component.use-layer' + ).innerText = `The current layer level is: ${level + 1}`; + }); + + return html` + +
    + +
    +
    +
    + + `; + }, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + parameters: { + percy: { + skip: true, + }, + }, + render: ({ level }) => html` + +
    Test component
    +
    + + `, +}; + +const meta = { + title: 'Components/Layer', +}; + +export default meta; diff --git a/packages/web-components/src/components/layer/layer.ts b/packages/web-components/src/components/layer/layer.ts new file mode 100644 index 000000000000..1fd27c68153f --- /dev/null +++ b/packages/web-components/src/components/layer/layer.ts @@ -0,0 +1,83 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { prefix } from '../../globals/settings'; +import styles from './layer.scss?lit'; + +/** + * Basic layer + * + * @element cds-layer + * @fires cds-use-layer + * The name of the custom event fired when the "use layer" action occurs. + * @slot children - The elements contained within the component. + */ +@customElement(`${prefix}-layer`) +class CDSLayer extends LitElement { + /** + * Specify the layer level and override any existing levels based on hierarchy + */ + @property({ type: Number, reflect: true }) + level = 0; + + @property() + layers; + + updated() { + if (!this.layers) { + this.layers = this.querySelectorAll( + (this.constructor as typeof CDSLayer).selectorLayer + ); + } + + this.layers.forEach((item) => { + (item as HTMLElement).setAttribute( + 'level', + ((this.level + 1) % 3).toString() + ); + }); + + this.dispatchEvent( + new CustomEvent((this.constructor as typeof CDSLayer).eventUseLayer, { + bubbles: true, + cancelable: true, + composed: true, + detail: { + layer: this, + level: this.level, + }, + }) + ); + } + + render() { + return html` `; + } + + /** + * A selector that selects a layer component. + */ + static get selectorLayer() { + return `${prefix}-layer`; + } + + /** + * A selector that selects a layer component. + */ + static get eventUseLayer() { + return `${prefix}-use-layer`; + } + + static styles = styles; +} + +export default CDSLayer; diff --git a/packages/web-components/src/components/link/docs/overview.mdx b/packages/web-components/src/components/link/docs/overview.mdx new file mode 100644 index 000000000000..1a6dfa3c776f --- /dev/null +++ b/packages/web-components/src/components/link/docs/overview.mdx @@ -0,0 +1,16 @@ +## Live demo + + diff --git a/packages/web-components/src/components/link/index.ts b/packages/web-components/src/components/link/index.ts new file mode 100644 index 000000000000..dbc26f24a6d1 --- /dev/null +++ b/packages/web-components/src/components/link/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './link'; diff --git a/packages/web-components/src/components/link/link.mdx b/packages/web-components/src/components/link/link.mdx new file mode 100644 index 000000000000..376156fa89d5 --- /dev/null +++ b/packages/web-components/src/components/link/link.mdx @@ -0,0 +1,57 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as LinkStories from './link.stories'; + + + +# Link + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/link) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/link) + +Represents a link. Provided for convenience purpose, you can alternatively use +`` with Carbon style in place in light DOM. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/list/index.js'; +``` + +{`${cdnJs({ components: ['list'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + Link +``` + +## Paired with icon + +Import the desired icon and incorporate with the link text: + +```javascript +import Download16 from '@carbon/icons/lib/download/16'; + +function App() { + return html` + Download ${Download16({ slot: 'icon' })}`; +} +``` + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `disabled` attribute). + + diff --git a/packages/web-components/src/components/link/link.scss b/packages/web-components/src/components/link/link.scss new file mode 100644 index 000000000000..ee4c10c75883 --- /dev/null +++ b/packages/web-components/src/components/link/link.scss @@ -0,0 +1,25 @@ +// +// Copyright IBM Corp. 2019, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/components/link'; + +:host(#{$prefix}-link) { + outline: none; + + // Re-define the ruleset so this wins over `.#{$prefix}--link:visited`, etc. + .#{$prefix}--link--disabled { + color: $text-disabled; + } + + .#{$prefix}--link__icon[hidden] { + display: none; + } +} diff --git a/packages/web-components/src/components/link/link.stories.ts b/packages/web-components/src/components/link/link.stories.ts new file mode 100644 index 000000000000..6fda7939ae12 --- /dev/null +++ b/packages/web-components/src/components/link/link.stories.ts @@ -0,0 +1,105 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import Download16 from '@carbon/icons/lib/download/16'; +import { LINK_SIZE } from './link'; + +const defaultArgs = { + disabled: false, + href: 'https://example.com', + inline: false, + size: LINK_SIZE.MEDIUM, + visited: false, +}; + +const controls = { + disabled: { + control: 'boolean', + description: `Specify if the control should be disabled, or not`, + }, + href: { + control: 'text', + description: `Provide the href attribute for the node`, + }, + size: { + control: 'radio', + options: [LINK_SIZE.SMALL, LINK_SIZE.MEDIUM, LINK_SIZE.LARGE], + description: `Specify the size of the Link. Currently supports either sm, 'md' (default) or 'lg' as an option.`, + }, + visited: { + control: 'boolean', + description: `Specify whether you want the link to receive visited styles after the link has been clicked`, + }, +}; + +export const Default = { + render: () => html` Link `, +}; + +export const Inline = { + render: () => html` + Lorem ipsum dolor sit amet, consectetur adipiscing elit. +

    + Ut facilisis semper lorem in aliquet. Aliquam accumsan ante justo, vitae + fringilla eros vehicula id. Ut at enim quis libero pharetra ullamcorper. + Maecenas feugiat sodales arcu ut porttitor. In blandit ultricies est. + Vivamus risus massa, cursus eu tellus sed, sagittis commodo nunc. + Maecenas nunc mauris, consequat quis mauris sit amet, + finibus suscipit nunc. Phasellus ex quam, placerat quis tempus sit amet, + pretium nec sem. Etiam dictum scelerisque mauris, blandit ultrices erat + pellentesque id. Quisque venenatis purus sit amet sodales condimentum. + Duis at tincidunt orci. Ut velit ipsum, lacinia at ex quis, aliquet + rhoncus purus. Praesent et scelerisque ligula. +

    + `, +}; + +export const PairedWithIcon = { + args: defaultArgs, + parameters: { + controls: { exclude: /(.*?)/ }, + }, + render: ({ disabled, href, size, onClick }) => html` + + Download ${Download16({ slot: 'icon' })} + + `, +}; + +export const Playground = { + argTypes: controls, + args: defaultArgs, + render: ({ disabled, href, inline, size, visited, onClick }) => html` + + Link + + `, +}; + +const meta = { + title: 'Components/Link', +}; + +export default meta; diff --git a/packages/web-components/src/components/link/link.ts b/packages/web-components/src/components/link/link.ts new file mode 100644 index 000000000000..830b1c8bae5b --- /dev/null +++ b/packages/web-components/src/components/link/link.ts @@ -0,0 +1,226 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import styles from './link.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Link size. + */ +export const LINK_SIZE = { + MEDIUM: 'md', + SMALL: 'sm', + LARGE: 'lg', +}; + +// Convert object key in a type +type LINK_SIZE_TYPE = (typeof LINK_SIZE)[keyof typeof LINK_SIZE]; + +/** + * Link. + * + * @element cds-link + * @csspart link The link. + */ +@customElement(`${prefix}-link`) +class CDSLink extends FocusMixin(LitElement) { + /** + * `true` if there is an icon. + */ + private _hasIcon = false; + + /** + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + const { name } = target as HTMLSlotElement; + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .some( + (node) => node.nodeType !== Node.TEXT_NODE || node!.textContent!.trim() + ); + this[name === 'icon' ? '_hasIcon' : ''] = hasContent; + this.requestUpdate(); + } + + @query('#link') + protected _linkNode?: HTMLAnchorElement | HTMLParagraphElement; + + /** + * The CSS class list for the link node. + */ + protected get _classes() { + const { disabled, size, inline, visited, _hasIcon } = this; + return classMap({ + [`${prefix}--link`]: true, + [`${prefix}--link--disabled`]: disabled, + [`${prefix}--link--icon`]: _hasIcon, + [`${prefix}--link--inline`]: inline, + [`${prefix}--link--${size}`]: size, + [`${prefix}--link--visited`]: visited, + }); + } + + /** + * Handles `click` event on the `
    `. + */ + // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars + protected _handleClick(_: MouseEvent) {} + + /** + * @returns The inner content. + */ + // eslint-disable-next-line class-methods-use-this + protected _renderInner() { + const { _hasIcon: hasIcon, _handleSlotChange: handleSlotChange } = this; + return html` + + + `; + } + + /** + * @returns The disabled link content. + */ + protected _renderDisabledLink() { + const { _classes: classes } = this; + return html` + + `; + } + + /** + * @returns The link content. + */ + protected _renderLink() { + const { + download, + href, + hreflang, + linkRole, + ping, + rel, + target, + type, + _classes: classes, + _handleClick: handleClick, + } = this; + return html` + + ${this._renderInner()} + + `; + } + + /** + * `true` if the link should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * The default file name. + */ + @property({ reflect: true }) + download!: string; + + /** + * Link `href`. + */ + @property({ reflect: true }) + href!: string; + + /** + * The language of what `href` points to. + */ + @property({ reflect: true }) + hreflang!: string; + + /** + * `true` if the link should be inline. + */ + @property({ type: Boolean, reflect: true }) + inline = false; + + /** + * The a11y role for ``. + */ + @property({ attribute: 'link-role' }) + linkRole!: string; + + /** + * URLs to ping. + */ + @property({ reflect: true }) + ping!: string; + + /** + * The link type. + */ + @property({ reflect: true }) + rel!: string; + + /** + * Link size. + */ + @property({ reflect: true }) + size: LINK_SIZE_TYPE = LINK_SIZE.MEDIUM; + + /** + * The link target. + */ + @property({ reflect: true }) + target!: string; + + /** + * MIME type of the `target`. + */ + @property({ reflect: true }) + type!: string; + + /** + * `true` if the link has been visited. + */ + @property({ type: Boolean, reflect: true }) + visited = false; + + render() { + const { disabled } = this; + return disabled ? this._renderDisabledLink() : this._renderLink(); + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSLink; diff --git a/packages/web-components/src/components/list/docs/overview.mdx b/packages/web-components/src/components/list/docs/overview.mdx new file mode 100644 index 000000000000..283bde8a07c5 --- /dev/null +++ b/packages/web-components/src/components/list/docs/overview.mdx @@ -0,0 +1,16 @@ +## Live demo + + diff --git a/packages/web-components/src/components/list/index.ts b/packages/web-components/src/components/list/index.ts new file mode 100644 index 000000000000..1a7b397674f7 --- /dev/null +++ b/packages/web-components/src/components/list/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './list-item'; +import './ordered-list'; +import './unordered-list'; diff --git a/packages/web-components/src/components/list/list-item.ts b/packages/web-components/src/components/list/list-item.ts new file mode 100644 index 000000000000..93abc53f62c7 --- /dev/null +++ b/packages/web-components/src/components/list/list-item.ts @@ -0,0 +1,89 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './list.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * List item. + * + * @element cds-list-item + * @slot nested - The nested child list. + */ +@customElement(`${prefix}-list-item`) +class CDSListItem extends LitElement { + /** + * `true` if there is slotted nested child list. + */ + private _hasNestedChild = false; + + /** + * Handles `slotchange` event for the `` for the nested child list. + * + * @param event The event. + * @param event.target The event target. + */ + private _handleSlotChangeNested({ target }: Event) { + this._hasNestedChild = + (target as HTMLSlotElement).assignedNodes().length > 0; + this.requestUpdate(); + } + + /** + * `true` if this list item is a child of a nested list. + * `` or `` automatically sets this property. + */ + @property({ type: Boolean, reflect: true }) + nested = false; + + connectedCallback() { + // Uses attribute for lookup from child + this.toggleAttribute( + 'nested', + Boolean( + this.closest( + (this.constructor as typeof CDSListItem).selectorNestedList + ) + ) + ); + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'listitem'); + } + super.connectedCallback(); + } + + render() { + const { + _hasNestedChild: hasNestedChild, + _handleSlotChangeNested: handleSlotChangeNested, + } = this; + return html` + +
    + +
    + `; + } + + /** + * A selector that will return nested list. + */ + static get selectorNestedList() { + return `${prefix}-ordered-list[slot="nested"],${prefix}-unordered-list[slot="nested"]`; + } + + static styles = styles; +} + +export default CDSListItem; diff --git a/packages/web-components/src/components/list/list.mdx b/packages/web-components/src/components/list/list.mdx new file mode 100644 index 000000000000..81a97ca9875b --- /dev/null +++ b/packages/web-components/src/components/list/list.mdx @@ -0,0 +1,77 @@ +import { ArgTypes, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; + +# List + +Represents a list. + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/list) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/list) + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/list/index.js'; +``` + +{`${cdnJs({ components: ['list'] })}`} +{`${cdnCss()}`} + +### HTML + +```html +

    cds-ordered-list

    + + + + Ordered List level 1 + + Ordered List level 2 + + Ordered List level 2 + + Ordered List level 2 + Ordered List level 2 + + + + + Ordered List level 1 + Ordered List level 1 + + +

    cds-unordered-list

    + + + + Unordered List level 1 + + Unordered List level 2 + + Unordered List level 2 + + Unordered List level 2 + Unordered List level 2 + + + + + Unordered List level 1 + Unordered List level 1 + +``` + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `nested` attribute). + + diff --git a/packages/web-components/src/components/list/list.scss b/packages/web-components/src/components/list/list.scss new file mode 100644 index 000000000000..859def5e02d5 --- /dev/null +++ b/packages/web-components/src/components/list/list.scss @@ -0,0 +1,99 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/components/list'; + +:host(#{$prefix}-ordered-list), +:host(#{$prefix}-unordered-list) { + .#{$prefix}--list--nested { + margin-inline-start: $spacing-07; + } + + .#{$prefix}--list--nested ::slotted(#{$prefix}-list-item) { + padding-inline-start: $spacing-02; + } +} + +// ordered list +:host(#{$prefix}-ordered-list) { + .#{$prefix}--list--ordered.#{$prefix}--list--nested { + list-style-type: lower-latin; + } + + &:not(.#{$prefix}--list--nested) { + counter-reset: item; + } + + &:not(.#{$prefix}--list--nested) ::slotted(#{$prefix}-list-item) { + position: relative; + } + + .#{$prefix}--list--ordered:not(.#{$prefix}--list--nested) + ::slotted(#{$prefix}-list-item)::before { + position: absolute; + content: counter(item) '.'; + counter-increment: item; + inset-inline-start: rem(-24px); + } +} + +// unordered list +:host(#{$prefix}-unordered-list) { + // – en dash + --#{$prefix}-ce--list-marker: '\002013'; + + &[slot='nested'] { + // ▪ square + --#{$prefix}-ce--list-marker: '\0025AA'; + } +} + +:host(#{$prefix}-unordered-list) ::slotted(#{$prefix}-list-item) { + position: relative; + + &::before { + position: absolute; + // – en dash + content: '\002013'; + inset-inline-start: calc(-1 * #{$spacing-05}); + } +} + +:host(#{$prefix}-unordered-list[slot='nested']) + ::slotted(#{$prefix}-list-item)::before { + // ▪ square + content: '\0025AA'; + // offset to account for smaller ▪ vs – + inset-inline-start: calc(-1 * #{$spacing-04}); +} + +:host(#{$prefix}-list-item) { + display: list-item; + color: $text-primary; + + &::before { + // Workaround for https://bugs.webkit.org/show_bug.cgi?id=178237. + // For non-WebKit browsers, `:host(#{$prefix}-unordered-list) ::slotted(#{$prefix}-list-item)` takes this over. + position: absolute; + content: var(--#{$prefix}-ce--list-marker, none); + inset-inline-start: -$spacing-05; + } +} + +:host(#{$prefix}-list-item[nested]) { + margin-block: 0; + + .#{$prefix}-ce--list__item__nested-child { + padding-block-start: 0; + } +} diff --git a/packages/web-components/src/components/list/ordered-list.stories.ts b/packages/web-components/src/components/list/ordered-list.stories.ts new file mode 100644 index 000000000000..6771ae556a4e --- /dev/null +++ b/packages/web-components/src/components/list/ordered-list.stories.ts @@ -0,0 +1,138 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import storyDocs from './list.mdx'; +import './index'; + +const defaultArgs = { + isExpressive: false, + native: true, +}; + +const controls = { + isExpressive: { + control: 'boolean', + description: 'Specify whether this ordered list expressive or not.', + }, + native: { + control: 'boolean', + description: + 'Specify whether this ordered list should use native list styles instead of custom counter.', + }, +}; + +export const Default = { + render: () => html` + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + `, +}; + +export const NativeListStyles = { + render: () => html` + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + + Ordered List level 1 + + Ordered List level 2 + Ordered List level 2 + Ordered List level 2 + Ordered List level 2 + + + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + `, +}; + +export const Nested = { + render: () => html` + + Ordered List level 1 + + Ordered List level 2 + + Ordered List level 2 + + Ordered List level 3 + Ordered List level 3 + + + + + Ordered List level 1 + Ordered List level 1 + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ isExpressive, native }) => html` + + + Ordered List level 1 + + Ordered List level 2 + + Ordered List level 2 + + Ordered List level 2 + Ordered List level 2 + + + + + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + Ordered List level 1 + +
    + `, +}; + +const meta = { + title: 'Components/Ordered list', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/list/ordered-list.ts b/packages/web-components/src/components/list/ordered-list.ts new file mode 100644 index 000000000000..00f32b9a5276 --- /dev/null +++ b/packages/web-components/src/components/list/ordered-list.ts @@ -0,0 +1,44 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import CDSUnorderedList from './unordered-list'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Ordered list. + */ +@customElement(`${prefix}-ordered-list`) +class CDSOrderedList extends CDSUnorderedList { + /** + * Specify whether the ordered list should use native list styles instead of + * custom counter + */ + @property({ type: Boolean, reflect: true }) + native = false; + + render() { + const classes = classMap({ + [`${prefix}--list--ordered`]: !this.native, + [`${prefix}--list--ordered--native`]: this.native, + [`${prefix}--list--nested`]: this.getAttribute('slot') === 'nested', + [`${prefix}--list--expressive`]: this.isExpressive, + }); + return html` +
      + +
    + `; + } +} + +export default CDSOrderedList; diff --git a/packages/web-components/src/components/list/unordered-list.stories.ts b/packages/web-components/src/components/list/unordered-list.stories.ts new file mode 100644 index 000000000000..21d42b8ea365 --- /dev/null +++ b/packages/web-components/src/components/list/unordered-list.stories.ts @@ -0,0 +1,87 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import storyDocs from './list.mdx'; +import './index'; + +const defaultArgs = { + isExpressive: false, +}; + +const controls = { + isExpressive: { + control: 'boolean', + description: 'Specify whether this ordered list expressive or not.', + }, +}; + +export const Default = { + render: () => html` + Unordered List level 1 + Unordered List level 1 + Unordered List level 1 + `, +}; + +export const Nested = { + render: () => html` + + Unordered List level 1 + + Unordered List level 2 + + Unordered List level 2 + + Unordered List level 3 + Unordered List level 3 + + + + + Unordered List level 1 + Unordered List level 1 + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + + render: ({ isExpressive }) => html` + + + Unordered List level 1 + + Unordered List level 2 + + Unordered List level 2 + + Unordered List level 2 + Unordered List level 2 + + + + + Unordered List level 1 + Unordered List level 1 + + `, +}; + +const meta = { + title: 'Components/Unordered list', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/list/unordered-list.ts b/packages/web-components/src/components/list/unordered-list.ts new file mode 100644 index 000000000000..bac0469cf6a9 --- /dev/null +++ b/packages/web-components/src/components/list/unordered-list.ts @@ -0,0 +1,65 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './list.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Ordered list. + */ +@customElement(`${prefix}-unordered-list`) +class CDSUnorderedList extends LitElement { + /** + * `true` if expressive theme enabled. + */ + @property({ type: Boolean, reflect: true }) + isExpressive = false; + + connectedCallback() { + // Uses attribute for lookup from child + if ( + this.closest( + (this.constructor as typeof CDSUnorderedList).selectorListItem + ) + ) { + this.setAttribute('slot', 'nested'); + } else { + this.removeAttribute('slot'); + } + super.connectedCallback(); + } + + render() { + const classes = classMap({ + [`${prefix}--list--unordered`]: true, + [`${prefix}--list--nested`]: this.getAttribute('slot') === 'nested', + [`${prefix}--list--expressive`]: this.isExpressive, + }); + return html` +
      + +
    + `; + } + + /** + * A selector that will return list item. + */ + static get selectorListItem() { + return `${prefix}-list-item`; + } + + static styles = styles; +} + +export default CDSUnorderedList; diff --git a/packages/web-components/src/components/loading/defs.ts b/packages/web-components/src/components/loading/defs.ts new file mode 100644 index 000000000000..27fcbcfdb4bf --- /dev/null +++ b/packages/web-components/src/components/loading/defs.ts @@ -0,0 +1,23 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Spinner types. + */ +export enum LOADING_TYPE { + /** + * Regular spinner. + */ + REGULAR = 'regular', + + /** + * Small spinner. + */ + SMALL = 'small', +} diff --git a/packages/web-components/src/components/loading/docs/overview.mdx b/packages/web-components/src/components/loading/docs/overview.mdx new file mode 100644 index 000000000000..384715615190 --- /dev/null +++ b/packages/web-components/src/components/loading/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/loading/index.ts b/packages/web-components/src/components/loading/index.ts new file mode 100644 index 000000000000..81860947390c --- /dev/null +++ b/packages/web-components/src/components/loading/index.ts @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './loading'; +import './loading-icon'; diff --git a/packages/web-components/src/components/loading/loading-icon.ts b/packages/web-components/src/components/loading/loading-icon.ts new file mode 100644 index 000000000000..5e95a4118ee5 --- /dev/null +++ b/packages/web-components/src/components/loading/loading-icon.ts @@ -0,0 +1,44 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { prefix } from '../../globals/settings'; +import LOADING_TYPE from './types'; + +/** + * @param Object options The options. + * @param [Object.assistiveText] The assistive text for the spinner icon. + * @param [Object.type] The spinner type. + * @returns The spinner icon. + */ +export default ({ + assistiveText, + type, +}: { + assistiveText?: string; + type?: string; +}) => { + const radius = type === LOADING_TYPE.SMALL ? '42' : '44'; + return html` + + ${!assistiveText ? undefined : html` ${assistiveText} `} + + + + `; +}; diff --git a/packages/web-components/src/components/loading/loading.mdx b/packages/web-components/src/components/loading/loading.mdx new file mode 100644 index 000000000000..d03b8f7bb7b7 --- /dev/null +++ b/packages/web-components/src/components/loading/loading.mdx @@ -0,0 +1,48 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as LoadingStories from './loading.stories'; + + + +# Loading + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/loading) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/loading) + +Loading spinners are used when retrieving data or performing slow computations, +and help to notify users that loading is underway. The waiting experience is a +crucial design opportunity. Although it may not be obvious what is occurring on +the back-end, we can communicate clearly to reassure the user that progress is +happening. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/loading/index.js'; +``` + +{`${cdnJs({ components: ['loading'] })}`} +{`${cdnCss()}`} + +### HTML + +```html +
    + +
    +``` + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `inactive` attribute). + + diff --git a/packages/web-components/src/components/loading/loading.scss b/packages/web-components/src/components/loading/loading.scss new file mode 100644 index 000000000000..4f1a28ff4f77 --- /dev/null +++ b/packages/web-components/src/components/loading/loading.scss @@ -0,0 +1,39 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/type'; +@use '@carbon/styles/scss/components/loading'; + +:host(#{$prefix}-loading) { + @extend .#{$prefix}--loading; + + display: block; +} + +:host(#{$prefix}-loading[overlay]) { + @extend .#{$prefix}--loading-overlay; + + // Avoids duplicate animation of the host and the `.#{$prefix}--loading` in the shadow DOM + animation: none; +} + +:host(#{$prefix}-loading[type='small']) { + @extend .#{$prefix}--loading--small; +} + +:host(#{$prefix}-loading[inactive]) { + @extend .#{$prefix}--loading--stop; +} + +.#{$prefix}--loading__background[hidden] { + // Conditional rendering of `circle.#{$prefix}--loading__background` does not seem to render the `` well + // even though the DOM seems right + display: none; +} diff --git a/packages/web-components/src/components/loading/loading.stories.ts b/packages/web-components/src/components/loading/loading.stories.ts new file mode 100644 index 000000000000..25e63b2c5865 --- /dev/null +++ b/packages/web-components/src/components/loading/loading.stories.ts @@ -0,0 +1,67 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { LOADING_TYPE } from './loading'; + +const types = { + [`Regular (${LOADING_TYPE.REGULAR})`]: null, + [`Small (${LOADING_TYPE.SMALL})`]: LOADING_TYPE.SMALL, +}; + +const defaultArgs = { + inactive: false, + assistiveText: 'Loading', + type: null, + withOverlay: false, +}; + +const controls = { + inactive: { + control: 'boolean', + description: `Specify whether the component should be inactive, or not.`, + }, + assistiveText: { + control: 'text', + description: `Specify a description that would be used to best describe the loading state.`, + }, + type: { + control: 'radio', + options: types, + description: `Specify the spinner type.`, + }, + withOverlay: { + control: 'boolean', + description: `Specify whether the loading should be an overlay.`, + }, +}; + +export const Default = { + render: () => html` `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ inactive, assistiveText, type, withOverlay }) => + html` + + `, +}; + +const meta = { + title: 'Components/Loading', +}; + +export default meta; diff --git a/packages/web-components/src/components/loading/loading.ts b/packages/web-components/src/components/loading/loading.ts new file mode 100644 index 000000000000..7b44cf3d0cf1 --- /dev/null +++ b/packages/web-components/src/components/loading/loading.ts @@ -0,0 +1,66 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { LOADING_TYPE } from './defs'; +import getLoadingIcon from './loading-icon'; +import styles from './loading.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Spinner indicating loading state. + * + * @element cds-loading + */ +@customElement(`${prefix}-loading`) +class CDSLoading extends LitElement { + /** + * The assistive text for the spinner icon. + */ + @property({ attribute: 'assistive-text' }) + assistiveText = 'Loading'; + + /** + * Spinner type. + */ + @property() + type = LOADING_TYPE.REGULAR; + + /** + * `true` if overlay should be applied. + */ + @property({ type: Boolean, reflect: true }) + overlay = false; + + /** + * `true` if spinner should stop. + */ + @property({ type: Boolean, reflect: true }) + inactive = false; + + render() { + const { inactive, assistiveText, type, overlay } = this; + const innerClasses = classMap({ + [`${prefix}--loading`]: true, + [`${prefix}--loading--stop`]: inactive, + [`${prefix}--loading--small`]: type === LOADING_TYPE.SMALL, + }); + const icon = getLoadingIcon({ assistiveText, type }); + return overlay ? html`
    ${icon}
    ` : icon; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export { LOADING_TYPE }; + +export default CDSLoading; diff --git a/packages/web-components/src/components/loading/types.ts b/packages/web-components/src/components/loading/types.ts new file mode 100644 index 000000000000..eebb15db9837 --- /dev/null +++ b/packages/web-components/src/components/loading/types.ts @@ -0,0 +1,15 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LOADING_TYPE } from './defs'; + +/** + * @deprecated Use `defs.ts` + */ +export default LOADING_TYPE; diff --git a/packages/web-components/src/components/modal/defs.ts b/packages/web-components/src/components/modal/defs.ts new file mode 100644 index 000000000000..cbfa1c055557 --- /dev/null +++ b/packages/web-components/src/components/modal/defs.ts @@ -0,0 +1,33 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Modal size. + */ +export enum MODAL_SIZE { + /** + * Extra small size. + */ + EXTRA_SMALL = 'xs', + + /** + * Small size. + */ + SMALL = 'sm', + + /** + * Medium size. + */ + MEDIUM = 'md', + + /** + * Large size. + */ + LARGE = 'lg', +} diff --git a/packages/web-components/src/components/modal/docs/overview.mdx b/packages/web-components/src/components/modal/docs/overview.mdx new file mode 100644 index 000000000000..20a31dcedf95 --- /dev/null +++ b/packages/web-components/src/components/modal/docs/overview.mdx @@ -0,0 +1,20 @@ +## Live demo + + diff --git a/packages/web-components/src/components/modal/index.ts b/packages/web-components/src/components/modal/index.ts new file mode 100644 index 000000000000..efbc87754dae --- /dev/null +++ b/packages/web-components/src/components/modal/index.ts @@ -0,0 +1,18 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './modal'; +import './modal-body'; +import './modal-body-content'; +import './modal-close-button'; +import './modal-footer'; +import './modal-footer-button'; +import './modal-header'; +import './modal-heading'; +import './modal-label'; diff --git a/packages/web-components/src/components/modal/modal-body-content.ts b/packages/web-components/src/components/modal/modal-body-content.ts new file mode 100644 index 000000000000..b4b2103920dd --- /dev/null +++ b/packages/web-components/src/components/modal/modal-body-content.ts @@ -0,0 +1,29 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './modal.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Modal body content + * + * @element cds-modal-body-content + */ +@customElement(`${prefix}-modal-body-content`) +class CDSModalBodyContent extends LitElement { + render() { + return html``; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSModalBodyContent; diff --git a/packages/web-components/src/components/modal/modal-body.ts b/packages/web-components/src/components/modal/modal-body.ts new file mode 100644 index 000000000000..dee8b517b1be --- /dev/null +++ b/packages/web-components/src/components/modal/modal-body.ts @@ -0,0 +1,29 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './modal.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Modal body. + * + * @element cds-modal-body + */ +@customElement(`${prefix}-modal-body`) +class CDSModalBody extends LitElement { + render() { + return html` `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSModalBody; diff --git a/packages/web-components/src/components/modal/modal-close-button.ts b/packages/web-components/src/components/modal/modal-close-button.ts new file mode 100644 index 000000000000..612d4945d7ae --- /dev/null +++ b/packages/web-components/src/components/modal/modal-close-button.ts @@ -0,0 +1,61 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import Close20 from '@carbon/icons/lib/close/20'; +import { prefix } from '../../globals/settings'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import FocusMixin from '../../globals/mixins/focus'; +import styles from './modal.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Modal close button. + * + * @element cds-modal-close-button + * @csspart button The button. + * @csspart close-icon The close icon. + */ +@customElement(`${prefix}-modal-close-button`) +class CDSModalCloseButton extends FocusMixin(LitElement) { + /** + * Specify a label for the close button of the modal; defaults to close + */ + @property({ attribute: 'close-button-label' }) + closeButtonLabel = 'Close'; + + updated() { + this.parentElement?.setAttribute('close-button', ''); + } + + render() { + const { closeButtonLabel } = this; + return html` + + `; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom WebPack loader +} + +export default CDSModalCloseButton; diff --git a/packages/web-components/src/components/modal/modal-footer-button.ts b/packages/web-components/src/components/modal/modal-footer-button.ts new file mode 100644 index 000000000000..b49c38426622 --- /dev/null +++ b/packages/web-components/src/components/modal/modal-footer-button.ts @@ -0,0 +1,26 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { prefix } from '../../globals/settings'; +import CDSButton from '../button/button'; +import buttonStyles from '../button/button.scss?lit'; +import styles from './modal.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Modal footer button. + * + * @element cds-modal-footer-button + */ +@customElement(`${prefix}-modal-footer-button`) +class CDSModalFooterButton extends CDSButton { + static styles = [buttonStyles, styles]; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSModalFooterButton; diff --git a/packages/web-components/src/components/modal/modal-footer.ts b/packages/web-components/src/components/modal/modal-footer.ts new file mode 100644 index 000000000000..fbbdbc69a43e --- /dev/null +++ b/packages/web-components/src/components/modal/modal-footer.ts @@ -0,0 +1,59 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './modal.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Modal footer. + * + * @element cds-modal-footer + */ +@customElement(`${prefix}-modal-footer`) +class CDSModalFooter extends LitElement { + /** + * `true` if this modal footer has more than two buttons. + */ + @property({ type: Boolean, reflect: true, attribute: 'has-three-buttons' }) + hasThreeButtons = false; + + /** + * Handles `slotchange` event. + */ + private _handleSlotChange(event: Event) { + const { selectorButtons } = this.constructor as typeof CDSModalFooter; + this.hasThreeButtons = + (event.target as HTMLSlotElement) + .assignedNodes() + .filter( + (node) => + node.nodeType === Node.ELEMENT_NODE && + (node as Element).matches(selectorButtons) + ).length > 2; + this.requestUpdate(); + } + + render() { + return html` `; + } + + /** + * A selector that selects the child buttons. + */ + static get selectorButtons() { + return `${prefix}-button,${prefix}-modal-footer-button`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSModalFooter; diff --git a/packages/web-components/src/components/modal/modal-header.ts b/packages/web-components/src/components/modal/modal-header.ts new file mode 100644 index 000000000000..d1a42139e63c --- /dev/null +++ b/packages/web-components/src/components/modal/modal-header.ts @@ -0,0 +1,70 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './modal.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Modal header. + * + * @element cds-modal-header + */ +@customElement(`${prefix}-modal-header`) +class CDSModalHeader extends LitElement { + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + /** + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSModalHeader).slugItem + ) + : false + ); + if (hasContent.length > 0) { + this._hasSlug = Boolean(hasContent); + (hasContent[0] as HTMLElement).setAttribute('size', 'lg'); + } + this.requestUpdate(); + } + + updated() { + if (this._hasSlug) { + this.parentElement?.setAttribute('slug', ''); + } else { + this.parentElement?.removeAttribute('slug'); + } + } + + render() { + return html` + `; + } + + /** + * A selector that will return the slug item. + */ + static get slugItem() { + return `${prefix}-slug`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom WebPack loader +} + +export default CDSModalHeader; diff --git a/packages/web-components/src/components/modal/modal-heading.ts b/packages/web-components/src/components/modal/modal-heading.ts new file mode 100644 index 000000000000..586a730b82c1 --- /dev/null +++ b/packages/web-components/src/components/modal/modal-heading.ts @@ -0,0 +1,29 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './modal.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Modal heading. + * + * @element cds-modal-heading + */ +@customElement(`${prefix}-modal-heading`) +class CDSModalHeading extends LitElement { + render() { + return html` `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSModalHeading; diff --git a/packages/web-components/src/components/modal/modal-label.ts b/packages/web-components/src/components/modal/modal-label.ts new file mode 100644 index 000000000000..d18a0aa201b6 --- /dev/null +++ b/packages/web-components/src/components/modal/modal-label.ts @@ -0,0 +1,29 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './modal.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Modal label. + * + * @element cds-modal-label + */ +@customElement(`${prefix}-modal-label`) +class CDSModalLabel extends LitElement { + render() { + return html` `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSModalLabel; diff --git a/packages/web-components/src/components/modal/modal.mdx b/packages/web-components/src/components/modal/modal.mdx new file mode 100644 index 000000000000..f2fbea5c0a84 --- /dev/null +++ b/packages/web-components/src/components/modal/modal.mdx @@ -0,0 +1,199 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; + +import * as ModalStories from './modal.stories'; + + + +# Modal + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/modal) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/modal) + +Modals interrupt user workflow by design. They are most effective when a task +must be completed before a user can continue. While effective when used +correctly, modals should be used sparingly to limit disruption to a user +experience. + +- [Modal](#modal) + - [Getting started](#getting-started) + - [Component API](#component-api) + - [Modal sizes](#modal-sizes) + - [Overflow content](#overflow-content) + - [Modal button variants](#modal-button-variants) + - [Using modal title as message](#using-modal-title-as-message) + - [Focus management](#focus-management) + - [References](#references) + - [Feedback](#feedback) + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/modal/index.js'; +import '@carbon/web-components/es/components/button/index.js'; +``` + +{`${cdnJs({ components: ['modal', 'button'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + Open Modal + + + + + Label (Optional) + Modal Title + +

    Modal text description

    + + Cancel + Save + +
    + + +``` + +## Component API + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `open` attribute). + + + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the +attribute (e.g. `` without `disabled` attribute). + + + +## Opening/closing modal + +For both modal variants, you can open/close the modal by changing the open prop. +For example, you can implement a button that launches the modal upon click. + +```html + +``` + +## Modal sizes + +There are four responsive modal sizes: extra-small (sm), small (sm), +default/medium (md), and large (lg). You can set it via the size prop. + +```html + + + + Label (Optional) + Modal Title + + + Modal text description + + + Cancel + Save + + +``` + +## Overflow content + +In cases where even the largest modal size does not fit all of the modal +content, Carbon design specifies having a "visual fade" at the end of the modal +body area to indicate there is additional content out of view. You can set +hasScrollingContent prop to the component as such: + +```html + + + + Label (Optional) + Modal Title + + + Modal text description +

    Some very large contents...

    +
    + + Cancel + Save + +
    +``` + +## Modal button variants + +With the modal component you can use up to three buttons. One has to be primary, +and the others secondary. Only the primary button can be a danger button. + +## Using modal title as message + +For short, direct messages the title can include the whole message to add visual +clarity to an otherwise repetitive title and body message. + +```html + + + + You have been successfully signed out + + + +``` + +## Focus management + +`` puts focus on one of the following elements (in priority order) +once it gets open: + +1. An programmatic-focusable element with `data-modal-primary-focus` attribute +2. The primary button in modal footer +3. The first sequential-focusable child element + +`` enables "focus-wrapping" behavior after then. It means that +hitting tab key at the last sequential-focusable element in `` puts +focus on the first sequential-focusable element, and hitting Shift-tab key at +the first sequential-focusable element in `` puts focus on the last +sequential-focusable element. + +Once `` gets closed, it puts focus on the last focused element before +it got open, typically the launcher button. + +## References + +Check out the +[usage guidelines](https://www.carbondesignsystem.com/components/modal/usage/) +on the Carbon Design System website. + +## Feedback + +Help us improve this component by providing feedback through, asking questions +on Slack,or updating this file on +[GitHub](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/edit/main/packages/carbon-web-components/src/components/modal/modal-story.mdx). diff --git a/packages/web-components/src/components/modal/modal.scss b/packages/web-components/src/components/modal/modal.scss new file mode 100644 index 000000000000..4e60bd706d81 --- /dev/null +++ b/packages/web-components/src/components/modal/modal.scss @@ -0,0 +1,197 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/motion' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/breakpoint' as *; +@use '@carbon/styles/scss/layer' as *; +@use '@carbon/styles/scss/type' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/utilities/ai-gradient' as *; +@use '@carbon/styles/scss/components/modal' as *; +@use '@carbon/styles/scss/components/button' as *; + +:host(#{$prefix}-modal[open]) { + @extend .#{$prefix}--modal; + + opacity: 1; + transition: opacity $duration-moderate-02 motion(entrance, expressive), + visibility 0ms linear; + visibility: inherit; + + .#{$prefix}--modal-container { + transform: translate3d(0, 0, 0); + transition: transform $duration-moderate-02 motion(entrance, expressive); + } + + @media screen and (prefers-reduced-motion: reduce) { + transition: none; + } +} + +:host(#{$prefix}-modal) { + @extend .#{$prefix}--modal; +} + +:host(#{$prefix}-modal[full-width]) { + ::slotted(#{$prefix}-modal-body) { + padding: 0; + margin: 0; + } +} + +:host(#{$prefix}-modal[has-scrolling-content]) + ::slotted(#{$prefix}-modal-body) { + @extend .#{$prefix}--modal-scroll-content; +} + +:host(#{$prefix}-modal-header) { + @extend .#{$prefix}--modal-header; +} + +:host(#{$prefix}-modal-close-button) { + @extend .#{$prefix}--modal-close-button; + + outline: none; +} + +:host(#{$prefix}-modal-heading), +:host(#{$prefix}-modal-label) { + display: block; +} + +:host(#{$prefix}-modal-heading) { + @extend .#{$prefix}--modal-header__heading; +} + +:host(#{$prefix}-modal-label) { + @extend .#{$prefix}--modal-header__label; +} + +:host(#{$prefix}-modal-body) { + @extend .#{$prefix}--modal-content; + @extend .#{$prefix}--layer-two; + + ::slotted(#{$prefix}-form-item) { + margin-block-end: $spacing-05; + } + + ::slotted(#{$prefix}-select:last-of-type) { + padding-block-end: 0; + } + + ::slotted(*:last-child) { + padding-block-end: $spacing-07; + } +} + +:host(#{$prefix}-modal-body-content) { + @include type-style('body-01'); + + display: block; + padding-inline-end: calc(20% - #{$spacing-07}); +} + +:host(#{$prefix}-modal-body-content[description]) { + margin-block-end: $spacing-05; +} + +:host(#{$prefix}-modal-footer) { + @extend .#{$prefix}--modal-footer; +} + +:host(#{$prefix}-modal-footer[has-three-buttons]) { + @extend .#{$prefix}--modal-footer--three-button; + + ::slotted(#{$prefix}-modal-footer-button) { + flex: 0 1 25%; + } +} + +:host(#{$prefix}-modal-footer-button:first-of-type) .#{$prefix}--btn { + box-shadow: inherit; +} + +:host(#{$prefix}-modal-footer-button) { + .#{$prefix}--btn { + block-size: 100%; + box-shadow: rem(-1px) 0 0 0 $button-separator; + inline-size: 100%; + max-inline-size: none; + + padding-block: $spacing-05 $spacing-07; + + &:focus { + box-shadow: inset 0 0 0 $button-outline-width $focus, + inset 0 0 0 $button-border-width $background; + } + } +} + +:host(#{$prefix}-modal-footer) ::slotted(#{$prefix}-button), +:host(#{$prefix}-modal-footer-button) { + flex: 0 1 50%; + margin: 0; + block-size: $spacing-10; + inline-size: 50%; + max-inline-size: none; +} + +// Slug + +:host(#{$prefix}-modal[slug]) { + background-color: $ai-overlay; +} + +:host(#{$prefix}-modal[slug]) .#{$prefix}--modal-container { + @include ai-popover-gradient('default', 0, 'layer'); + + border: 1px solid transparent; + background-color: $layer; + box-shadow: inset 0 -80px 70px -65px $ai-inner-shadow, + 0 24px 40px -24px $ai-drop-shadow; +} + +:host(#{$prefix}-modal[slug][has-footer]) .#{$prefix}--modal-container { + @include ai-popover-gradient('default', 64px, 'layer'); + + box-shadow: inset 0 -80px 0 -16px $layer, + inset 0 -160px 70px -65px $ai-inner-shadow, + 0 24px 40px -24px $ai-drop-shadow; +} + +:host(#{$prefix}-modal[slug][has-scrolling-content]) { + ::slotted(#{$prefix}-modal-body) { + mask-image: linear-gradient( + to bottom, + $layer calc(100% - 80px), + transparent calc(100% - 48px), + transparent 100% + ), + linear-gradient(to left, $layer 0, 16px, transparent 16px), + linear-gradient(to right, $layer 0, 2px, transparent 2px), + linear-gradient(to top, $layer 0, 2px, transparent 2px); + } +} + +:host(#{$prefix}-modal[slug]) + .#{$prefix}--modal-content--overflow-indicator::before, +:host(#{$prefix}-modal[slug]) .#{$prefix}--modal-content--overflow-indicator { + display: none; +} + +:host(#{$prefix}-modal-header) ::slotted(#{$prefix}-slug) { + position: absolute; + inset-block-start: 0; + inset-inline-end: 0; +} + +:host(#{$prefix}-modal-header[close-button]) ::slotted(#{$prefix}-slug) { + inset-inline-end: $spacing-09; +} diff --git a/packages/web-components/src/components/modal/modal.stories.ts b/packages/web-components/src/components/modal/modal.stories.ts new file mode 100644 index 000000000000..6647c7257a92 --- /dev/null +++ b/packages/web-components/src/components/modal/modal.stories.ts @@ -0,0 +1,439 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import '../structured-list'; +import { MODAL_SIZE } from './modal'; +import './index'; + +const toggleButton = () => { + document.querySelector('cds-modal')?.toggleAttribute('open'); +}; + +const sizes = { + [`Extra small size (${MODAL_SIZE.EXTRA_SMALL})`]: MODAL_SIZE.EXTRA_SMALL, + [`Small size (${MODAL_SIZE.SMALL})`]: MODAL_SIZE.SMALL, + [`Medium size (${MODAL_SIZE.MEDIUM})`]: MODAL_SIZE.MEDIUM, + [`Large size (${MODAL_SIZE.LARGE})`]: MODAL_SIZE.LARGE, +}; + +const buttons = { + 'One (1)': 1, + 'Two (2)': 2, + 'Three (3)': 3, +}; + +const defaultArgs = { + alert: false, + ariaLabel: '', + closeButtonLabel: 'Close', + danger: false, + fullWidth: false, + hasScrollingContent: false, + modalHeading: 'Add a custom domain', + modalLabel: '', + numberOfButtons: 2, + open: true, + passiveModal: false, + preventCloseOnClickOutside: false, + primaryButtonDisabled: false, + size: null, +}; + +const controls = { + alert: { + control: 'boolean', + description: + 'Specify whether the Modal is displaying an alert, error or warning Should go hand in hand with the danger prop.', + }, + ariaLabel: { + control: 'text', + description: 'Required props for the accessibility label of the header.', + }, + closeButtonLabel: { + control: 'text', + description: 'Required props for the accessibility label of the header.', + }, + danger: { + control: 'boolean', + description: 'Specify whether the Modal is for dangerous actions.', + }, + fullWidth: { + control: 'boolean', + description: + 'Specify whether or not the Modal content should have any inner padding.', + }, + hasScrollingContent: { + control: 'boolean', + description: 'Specify whether the modal contains scrolling content.', + }, + modalHeading: { + control: 'text', + description: 'Specify the content of the modal header title.', + }, + modalLabel: { + control: 'text', + description: 'Specify the content of the modal header label.', + }, + numberOfButtons: { + control: 'radio', + description: 'Count of Footer Buttons', + options: buttons, + }, + open: { + control: 'boolean', + description: 'Specify whether the modal is currently open.', + }, + passiveModal: { + control: 'boolean', + description: 'Specify whether the Modal should be passive, or not.', + }, + preventCloseOnClickOutside: { + control: 'boolean', + description: 'Prevent close on click outside.', + }, + primaryButtonDisabled: { + control: 'boolean', + description: 'Primary button disabled.', + }, + size: { + control: 'select', + description: 'Modal size.', + options: sizes, + }, +}; + +export const Default = { + render: () => html` + + + + Account resources + Add a custom domain + + + + Custom domains direct requests for your apps in this Cloud Foundry + organization to a URL that you own. A custom domain can be a shared + domain, a shared subdomain, or a shared domain and host. + + + + + + + + + US South + US East + + + + + One + Two + + + + Option 1 + Option 2 + + + + Cancel + Add + + + `, +}; + +export const DangerModal = { + render: () => html` + + + + Account resources + Are you sure you want to delete this custom + domain? + + + Cancel + Delete + + + `, +}; + +export const FullWidth = { + render: () => html` + + + + An example of a modal with no padding + Full Width Modal + + + + + + Column A + Column B + Column C + + + + + Row 1 + Row 1 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc + dui magna, finibus id tortor sed, aliquet bibendum augue. Aenean + posuere sem vel euismod dignissim. Nulla ut cursus dolor. + Pellentesque vulputate nisl a porttitor interdum. + + + + Row 2 + Row 2 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc + dui magna, finibus id tortor sed, aliquet bibendum augue. Aenean + posuere sem vel euismod dignissim. Nulla ut cursus dolor. + Pellentesque vulputate nisl a porttitor interdum. + + + + Row 3 + Row 3 + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc + dui magna, finibus id tortor sed, aliquet bibendum augue. Aenean + posuere sem vel euismod dignissim. Nulla ut cursus dolor. + Pellentesque vulputate nisl a porttitor interdum. + + + + + + + Cancel + Add + + + `, +}; + +export const PassiveModal = { + render: () => html` + + + + You have been successfully signed out + + + + `, +}; + +export const WithStateManager = { + render: () => html` + + + + Account resources + Add a custom domain + + + + Custom domains direct requests for your apps in this Cloud Foundry + organization to a URL that you own. A custom domain can be a shared + domain, a shared subdomain, or a shared domain and host. + + + + + + + Option 1 + Option 2 + + + + Cancel + Add + + + Launch modal + `, +}; + +export const Playground = { + args: defaultArgs, + argTypes: controls, + render: ({ + alert, + ariaLabel, + danger, + open, + closeButtonLabel, + hasScrollingContent, + fullWidth, + modalHeading, + modalLabel, + numberOfButtons, + passiveModal, + preventCloseOnClickOutside, + primaryButtonDisabled, + size, + }) => + html` + + + + ${modalLabel} + ${modalHeading} + + + + Custom domains direct requests for your apps in this Cloud Foundry + organization to a URL that you own. A custom domain can be a shared + domain, a shared subdomain, or a shared domain and host. + + + + + + + Option 1 + Option 2 + + + ${hasScrollingContent + ? html` + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Aenean id accumsan augue. Phasellus consequat augue vitae + tellus tincidunt posuere. Curabitur justo urna, consectetur + vel elit iaculis, ultrices condimentum risus. Nulla facilisi. + Etiam venenatis molestie tellus. Quisque consectetur non risus + eu rutrum. + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Aenean id accumsan augue. Phasellus consequat augue vitae + tellus tincidunt posuere. Curabitur justo urna, consectetur + vel elit iaculis, ultrices condimentum risus. Nulla facilisi. + Etiam venenatis molestie tellus. Quisque consectetur non risus + eu rutrum. + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Aenean id accumsan augue. Phasellus consequat augue vitae + tellus tincidunt posuere. Curabitur justo urna, consectetur + vel elit iaculis, ultrices condimentum risus. Nulla facilisi. + Etiam venenatis molestie tellus. Quisque consectetur non risus + eu rutrum. + +

    Lorem ipsum

    + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Aenean id accumsan augue. Phasellus consequat augue vitae + tellus tincidunt posuere. Curabitur justo urna, consectetur + vel elit iaculis, ultrices condimentum risus. Nulla facilisi. + Etiam venenatis molestie tellus. Quisque consectetur non risus + eu rutrum. + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Aenean id accumsan augue. Phasellus consequat augue vitae + tellus tincidunt posuere. Curabitur justo urna, consectetur + vel elit iaculis, ultrices condimentum risus. Nulla facilisi. + Etiam venenatis molestie tellus. Quisque consectetur non risus + eu rutrum. + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Aenean id accumsan augue. Phasellus consequat augue vitae + tellus tincidunt posuere. Curabitur justo urna, consectetur + vel elit iaculis, ultrices condimentum risus. Nulla facilisi. + Etiam venenatis molestie tellus. Quisque consectetur non risus + eu rutrum. + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Aenean id accumsan augue. Phasellus consequat augue vitae + tellus tincidunt posuere. Curabitur justo urna, consectetur + vel elit iaculis, ultrices condimentum risus. Nulla facilisi. + Etiam venenatis molestie tellus. Quisque consectetur non risus + eu rutrum. + ` + : ``} +
    + + ${passiveModal + ? `` + : html` + ${numberOfButtons > 2 + ? html` Keep both` + : ``} + ${numberOfButtons >= 2 + ? html` ${numberOfButtons === 2 + ? html`Cancel` + : 'Rename'}` + : ``} + + Add + `} +
    + `, +}; + +const meta = { + title: 'Components/Modal', +}; + +export default meta; diff --git a/packages/web-components/src/components/modal/modal.ts b/packages/web-components/src/components/modal/modal.ts new file mode 100644 index 000000000000..6bf576992179 --- /dev/null +++ b/packages/web-components/src/components/modal/modal.ts @@ -0,0 +1,425 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import { MODAL_SIZE } from './defs'; +import styles from './modal.scss?lit'; +import { selectorTabbable } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { MODAL_SIZE }; + +// eslint-disable-next-line no-bitwise +const PRECEDING = + Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINS; +// eslint-disable-next-line no-bitwise +const FOLLOWING = + Node.DOCUMENT_POSITION_FOLLOWING | Node.DOCUMENT_POSITION_CONTAINED_BY; + +/** + * Tries to focus on the given elements and bails out if one of them is successful. + * + * @param elems The elements. + * @param reverse `true` to go through the list in reverse order. + * @returns `true` if one of the attempts is successful, `false` otherwise. + */ +function tryFocusElems(elems: NodeListOf, reverse = false) { + if (!reverse) { + for (let i = 0; i < elems.length; ++i) { + const elem = elems[i]; + elem.focus(); + if (elem.ownerDocument!.activeElement === elem) { + return true; + } + } + } else { + for (let i = elems.length - 1; i >= 0; --i) { + const elem = elems[i]; + elem.focus(); + if (elem.ownerDocument!.activeElement === elem) { + return true; + } + } + } + return false; +} + +/** + * Modal. + * + * @element cds-modal + * @csspart dialog The dialog. + * @fires cds-modal-beingclosed + * The custom event fired before this modal is being closed upon a user gesture. + * Cancellation of this event stops the user-initiated action of closing this modal. + * @fires cds-modal-closed - The custom event fired after this modal is closed upon a user gesture. + */ +@customElement(`${prefix}-modal`) +class CDSModal extends HostListenerMixin(LitElement) { + /** + * The element that had focus before this modal gets open. + */ + private _launcher: Element | null = null; + + /** + * Node to track focus going outside of modal content. + */ + @query('#start-sentinel') + private _startSentinelNode!: HTMLAnchorElement; + + /** + * Node to track focus going outside of modal content. + */ + @query('#end-sentinel') + private _endSentinelNode!: HTMLAnchorElement; + + /** + * Handles `click` event on this element. + * + * @param event The event. + */ + @HostListener('click') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleClick = (event: MouseEvent) => { + if ( + event.composedPath().indexOf(this.shadowRoot!) < 0 && + !this.preventCloseOnClickOutside + ) { + this._handleUserInitiatedClose(event.target); + } + }; + + /** + * Handles `blur` event on this element. + * + * @param event The event. + * @param event.target The event target. + * @param event.relatedTarget The event relatedTarget. + */ + @HostListener('shadowRoot:focusout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleBlur = async ({ target, relatedTarget }: FocusEvent) => { + const { + open, + _startSentinelNode: startSentinelNode, + _endSentinelNode: endSentinelNode, + } = this; + const oldContains = target !== this && this.contains(target as Node); + const currentContains = + relatedTarget !== this && + (this.contains(relatedTarget as Node) || + (this.shadowRoot?.contains(relatedTarget as Node) && + relatedTarget !== (endSentinelNode as Node))); + + // Performs focus wrapping if _all_ of the following is met: + // * This modal is open + // * The viewport still has focus + // * Modal body used to have focus but no longer has focus + const { selectorTabbable: selectorTabbableForModal } = this + .constructor as typeof CDSModal; + if (open && relatedTarget && oldContains && !currentContains) { + const comparisonResult = (target as Node).compareDocumentPosition( + relatedTarget as Node + ); + // eslint-disable-next-line no-bitwise + if (relatedTarget === startSentinelNode || comparisonResult & PRECEDING) { + await (this.constructor as typeof CDSModal)._delay(); + if ( + !tryFocusElems( + this.querySelectorAll(selectorTabbableForModal), + true + ) && + relatedTarget !== this + ) { + this.focus(); + } + } + // eslint-disable-next-line no-bitwise + else if ( + relatedTarget === endSentinelNode || + comparisonResult & FOLLOWING + ) { + await (this.constructor as typeof CDSModal)._delay(); + if (!tryFocusElems(this.querySelectorAll(selectorTabbableForModal))) { + this.focus(); + } + } + } + }; + + @HostListener('document:keydown') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleKeydown = ({ key, target }: KeyboardEvent) => { + if (key === 'Esc' || key === 'Escape') { + this._handleUserInitiatedClose(target); + } + }; + + /** + * Handles `click` event on the modal container. + * + * @param event The event. + */ + private _handleClickContainer(event: MouseEvent) { + if ( + (event.target as Element).matches( + (this.constructor as typeof CDSModal).selectorCloseButton + ) && + !this.preventClose + ) { + this._handleUserInitiatedClose(event.target); + } + } + + /** + * Handles user-initiated close request of this modal. + * + * @param triggeredBy The element that triggered this close request. + */ + private _handleUserInitiatedClose(triggeredBy: EventTarget | null) { + if (this.open) { + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + triggeredBy, + }, + }; + if ( + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSModal).eventBeforeClose, + init + ) + ) + ) { + this.open = false; + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSModal).eventClose, + init + ) + ); + } + } + } + + /** + * Handles `slotchange` event. + */ + private _handleSlotChange() { + this.querySelector(`${prefix}-modal-footer`) + ? this.setAttribute('has-footer', '') + : this.removeAttribute('has-footer'); + } + + /** + * Specify whether the Modal is displaying an alert, error or warning. + * Should go hand in hand with the danger prop. + */ + @property({ type: Boolean, reflect: true }) + alert = false; + + /** + * Specify text for the accessibility label of the header + */ + @property({ attribute: 'aria-label' }) + ariaLabel = ''; + + /** + * The additional CSS class names for the container
    of the element. + */ + @property({ attribute: 'container-class' }) + containerClass = ''; + + /** + * Specify whether or not the Modal content should have any inner padding. + */ + @property({ type: Boolean, reflect: true, attribute: 'full-width' }) + fullWidth = false; + + /** + * Specify whether the modal contains scrolling content + */ + @property({ + type: Boolean, + reflect: true, + attribute: 'has-scrolling-content', + }) + hasScrollingContent = false; + + /** + * `true` if the modal should be open. + */ + @property({ type: Boolean, reflect: true }) + open = false; + + /** + * Modal size. + */ + @property({ reflect: true }) + size = MODAL_SIZE.MEDIUM; + + /** + * Prevent closing on click outside of modal + */ + @property({ type: Boolean, attribute: 'prevent-close-on-click-outside' }) + preventCloseOnClickOutside = false; + + /** + * Prevent the modal from closing after clicking the close button + */ + @property({ type: Boolean, attribute: 'prevent-close' }) + preventClose = false; + + firstUpdated() { + const body = this.querySelector( + (this.constructor as typeof CDSModal).selectorModalBody + ); + + if (!body) { + const bodyElement = document.createElement( + (this.constructor as typeof CDSModal).selectorModalBody + ); + this.appendChild(bodyElement); + } + } + + render() { + const { alert, ariaLabel, size, hasScrollingContent } = this; + const containerClass = this.containerClass + .split(' ') + .filter(Boolean) + .reduce((acc, item) => ({ ...acc, [item]: true }), {}); + const containerClasses = classMap({ + [`${prefix}--modal-container`]: true, + [`${prefix}--modal-container--${size}`]: size, + ...containerClass, + }); + return html` + +
    + + ${hasScrollingContent + ? html`
    ` + : ``} +
    + + `; + } + + async updated(changedProperties) { + if (changedProperties.has('open')) { + if (this.open) { + this._launcher = this.ownerDocument!.activeElement; + const primaryFocusNode = this.querySelector( + (this.constructor as typeof CDSModal).selectorPrimaryFocus + ); + await (this.constructor as typeof CDSModal)._delay(); + if (primaryFocusNode) { + // For cases where a `carbon-web-components` component (e.g. ``) being `primaryFocusNode`, + // where its first update/render cycle that makes it focusable happens after ``'s first update/render cycle + (primaryFocusNode as HTMLElement).focus(); + } else if ( + !tryFocusElems( + this.querySelectorAll( + (this.constructor as typeof CDSModal).selectorTabbable + ), + true + ) + ) { + this.focus(); + } + } else if ( + this._launcher && + typeof (this._launcher as HTMLElement).focus === 'function' + ) { + (this._launcher as HTMLElement).focus(); + this._launcher = null; + } + } + } + + /** + * @param ms The number of milliseconds. + * @returns A promise that is resolves after the given milliseconds. + */ + private static _delay(ms = 0) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + } + + /** + * A selector selecting buttons that should close this modal. + */ + static get selectorCloseButton() { + return `[data-modal-close],${prefix}-modal-close-button`; + } + + /** + * A selector selecting tabbable nodes. + */ + static get selectorTabbable() { + return selectorTabbable; + } + + /** + * A selector selecting the nodes that should be focused when modal gets open. + */ + static get selectorPrimaryFocus() { + return `[data-modal-primary-focus],${prefix}-modal-footer ${prefix}-button[kind="primary"]`; + } + + /** + * A selector selecting the modal body component + */ + static get selectorModalBody() { + return `${prefix}-modal-body`; + } + + /** + * The name of the custom event fired before this modal is being closed upon a user gesture. + * Cancellation of this event stops the user-initiated action of closing this modal. + */ + static get eventBeforeClose() { + return `${prefix}-modal-beingclosed`; + } + + /** + * The name of the custom event fired after this modal is closed upon a user gesture. + */ + static get eventClose() { + return `${prefix}-modal-closed`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSModal; diff --git a/packages/web-components/src/components/multi-select/defs.ts b/packages/web-components/src/components/multi-select/defs.ts new file mode 100644 index 000000000000..059a4a2174d5 --- /dev/null +++ b/packages/web-components/src/components/multi-select/defs.ts @@ -0,0 +1,28 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Multi-select selection feedback options. + */ +export enum SELECTION_FEEDBACK_OPTION { + /** + * selected item stays at it's position + */ + FIXED = 'fixed', + + /** + * selected item jumps to top + */ + TOP = 'top', + + /** + * selected item jump to top after reopen dropdown + */ + TOP_AFTER_REOPEN = 'top-after-reopen', +} diff --git a/packages/web-components/src/components/multi-select/docs/overview.mdx b/packages/web-components/src/components/multi-select/docs/overview.mdx new file mode 100644 index 000000000000..4d8d41b62745 --- /dev/null +++ b/packages/web-components/src/components/multi-select/docs/overview.mdx @@ -0,0 +1,16 @@ +## Live demo + + diff --git a/packages/web-components/src/components/multi-select/index.ts b/packages/web-components/src/components/multi-select/index.ts new file mode 100644 index 000000000000..efcdcac802f7 --- /dev/null +++ b/packages/web-components/src/components/multi-select/index.ts @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './multi-select'; +import './multi-select-item'; diff --git a/packages/web-components/src/components/multi-select/multi-select-item.ts b/packages/web-components/src/components/multi-select/multi-select-item.ts new file mode 100644 index 000000000000..a666010c5b1e --- /dev/null +++ b/packages/web-components/src/components/multi-select/multi-select-item.ts @@ -0,0 +1,65 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { prefix } from '../../globals/settings'; +import CDSDropdownItem from '../dropdown/dropdown-item'; +import styles from './multi-select.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Multi select item. + * + * @element cds-multi-select-item + */ +@customElement(`${prefix}-multi-select-item`) +class CDSMultiSelectItem extends CDSDropdownItem { + /** + * The property to hide when item is filtered from input + */ + @property({ type: Boolean }) + filtered; + + /** + * The `name` attribute for the `` for selection. + */ + @property({ attribute: 'selection-name' }) + selectionName = ''; + + render() { + const { disabled, selected, selectionName, value } = this; + return html` +
    +
    + +
    +
    + `; + } + + /** + * A selector that will return multi select. + */ + static get selectorList() { + return `${prefix}-multi-select`; + } + + static styles = styles; +} + +export default CDSMultiSelectItem; diff --git a/packages/web-components/src/components/multi-select/multi-select.mdx b/packages/web-components/src/components/multi-select/multi-select.mdx new file mode 100644 index 000000000000..f98043cc2376 --- /dev/null +++ b/packages/web-components/src/components/multi-select/multi-select.mdx @@ -0,0 +1,117 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as MultiSelectStories from './multi-select.stories'; + + + +# Multi select + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/multi-select) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/multi-select) + +Multi select is used when user needs to select multiple options from a dropdown. + +The label remains persistent within the dropdown. Once the user chooses an +option from the list, a number badge will appear to the left of the label +containing the total number of selected items. Selected options float to the top +of the list in alphanumeric order. + +To clear all selected items from a list, hover over the number badge and click +the “x” icon next to the value. To help with clarity, a browser tooltip appears +when the user hovers over the “x” (or close) icon to indicate the click action +results. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/multi-select/index.js'; +``` + +{`${cdnJs({ components: ['multi-select'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + Foo + Bar + Baz + +``` + +## Filter mode + +If you'd like to have a search bar to filter through the dropdown options, you +can add the `filterable` boolean to the `` component. + +```html + + Foo + Bar + Baz + +``` + +Often you want to render the multi select items from your data. Below is an +example of [`lit-html`](https://lit-html.polymer-project.org), but similar +stories apply to React, Angular, Vue, Backbone, Knockout and many others: + +```javascript +html` + + ${items.map( + (item) => + html` + ${item.title} + ` + )} + +`; +``` + +## Selection + +When user attempts to change selection in multi select item, +`cds-multi-select-beingselected` event fires on ``, which has +the following properties in the event details: + +| Property | Description | +| -------- | --------------------------------------------------------------- | +| `item` | The `` whose selection is being changed. | + +`cds-multi-select-beingselected` bubbles and is cancelable. Canceling this event +means canceling change in selection. + +## Note on keyboard navigation + +Similar to native `` for filtering. + */ + @query('input') + private _filterInputNode!: HTMLInputElement; + + /** + * The trigger button. + */ + @query(`.${prefix}--list-box__field`) + private _triggerNode!: HTMLElement; + + protected _selectionShouldChange(itemToSelect?: CDSMultiSelectItem) { + // If we are selecting an item, assumes we always toggle + return Boolean(this.value || itemToSelect); + } + + protected _selectionDidChange(itemToSelect?: CDSMultiSelectItem) { + if (itemToSelect) { + itemToSelect.selected = !itemToSelect.selected; + } else { + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSMultiSelect).selectorItemSelected + ), + (item) => { + (item as CDSMultiSelectItem).selected = false; + } + ); + this._handleUserInitiatedToggle(false); + } + // Change in `.selected` hasn't been reflected to the corresponding attribute yet + this.value = filter( + this.querySelectorAll( + (this.constructor as typeof CDSMultiSelect).selectorItem + ), + (item) => (item as CDSMultiSelectItem).selected + ) + .map((item) => (item as CDSMultiSelectItem).value) + .join(','); + } + + protected _handleClickInner(event: MouseEvent) { + if ( + this._selectionButtonNode?.contains(event.target as Node) && + !this.readOnly + ) { + this._handleUserInitiatedSelectItem(); + if (this.filterable) { + this._filterInputNode.focus(); + } else { + this._triggerNode.focus(); + } + } else if (this._clearButtonNode?.contains(event.target as Node)) { + this._handleUserInitiatedClearInput(); + } else if ( + !(event.target as HTMLElement)?.matches( + (this.constructor as typeof CDSMultiSelect).slugItem + ) + ) { + super._handleClickInner(event); + if (this.filterable) { + this._filterInputNode.focus(); + } + } + } + + /** + * Handler for the `keypress` event, ensures filter still works upon entering space + */ + protected _handleKeypressInner(event: KeyboardEvent) { + const { key } = event; + const action = (this.constructor as typeof CDSDropdown).getAction(key); + const { TRIGGERING } = DROPDOWN_KEYBOARD_ACTION; + + if ( + this._clearButtonNode?.contains(event.target as Node) && + // Space key should be handled by `` unless "clear selection" button has focus + (action === TRIGGERING || key === ' ') + ) { + this._handleUserInitiatedClearInput(); + } else if (this._selectionButtonNode?.contains(event.target as Node)) { + this._handleUserInitiatedSelectItem(); + this.open = true; + if (this.filterable) { + this._filterInputNode.focus(); + } else { + this._triggerNode.focus(); + } + } else if (this.filterable) { + this._handleKeypressInnerFlterable(event); + } else { + super._handleKeypressInner(event); + } + } + + /** + * Special andler for the `keypress` event, ensures space selection for filterable + * variation is disabled + */ + + protected _handleKeypressInnerFlterable(event: KeyboardEvent) { + const { key } = event; + const action = (this.constructor as typeof CDSDropdown).getAction(key); + if (!this.open) { + switch (action) { + case DROPDOWN_KEYBOARD_ACTION.TRIGGERING: + this._handleUserInitiatedToggle(true); + break; + default: + break; + } + } else { + switch (key) { + case 'Enter': + { + const constructor = this.constructor as typeof CDSDropdown; + const highlightedItem = this.querySelector( + constructor.selectorItemHighlighted + ) as CDSMultiSelectItem; + if (highlightedItem) { + this._handleUserInitiatedSelectItem(highlightedItem); + } else { + this._handleUserInitiatedToggle(false); + } + } + break; + default: + break; + } + } + } + + protected _renderTitleLabel() { + const { + clearSelectionDescription, + clearSelectionText, + disabled, + hideLabel, + titleText, + _selectedItemsCount: selectedItemsCount, + _slotTitleTextNode: slotTitleTextNode, + _handleSlotchangeLabelText: handleSlotchangeLabelText, + } = this; + + const labelClasses = classMap({ + [`${prefix}--label`]: true, + [`${prefix}--label--disabled`]: disabled, + [`${prefix}--visually-hidden`]: hideLabel, + }); + + const hasTitleText = + titleText || + (slotTitleTextNode && slotTitleTextNode.assignedNodes().length > 0); + + return html` + + `; + } + + protected _renderPrecedingLabel() { + const { + disabled, + readOnly, + clearSelectionLabel, + _selectedItemsCount: selectedItemsCount, + } = this; + + const selectionButtonClasses = classMap({ + [`${prefix}--list-box__selection`]: true, + [`${prefix}--list-box__selection--multi`]: true, + [`${prefix}--tag`]: true, + [`${prefix}--tag--filter`]: true, + [`${prefix}--tag--high-contrast`]: true, + [`${prefix}--tag--disabled`]: disabled, + }); + return selectedItemsCount === 0 + ? undefined + : html` +
    + ${selectedItemsCount} + ${Close16({ + 'aria-label': clearSelectionLabel, + class: `${prefix}--tag__close-icon`, + })} +
    + `; + } + + /** + @returns The main content of the trigger button. + */ + protected _renderLabel(): TemplateResult { + const { label, value, _selectedItemContent: selectedItemContent } = this; + + const inputClasses = classMap({ + [`${prefix}--text-input`]: true, + [`${prefix}--text-input--empty`]: !value, + }); + + return !this.filterable + ? html` + ${selectedItemContent || label} + ` + : html` + + `; + } + + protected _renderFollowingLabel(): TemplateResult | void { + const { clearSelectionLabel, _filterInputNode: filterInputNode } = this; + return filterInputNode && + filterInputNode.value.length > 0 && + this.filterable + ? html` +
    + ${Close16({ 'aria-label': clearSelectionLabel })} +
    + ` + : undefined; + } + + /** + * Handles `input` event on the `` for filtering. + */ + protected _handleInput() { + const items = this.querySelectorAll( + (this.constructor as typeof CDSMultiSelect).selectorItem + ); + const inputValue = this._filterInputNode.value.toLocaleLowerCase(); + + if (!this.open) { + this.open = true; + } + + forEach(items, (item) => { + const itemValue = (item as HTMLElement).innerText.toLocaleLowerCase(); + + if (!itemValue.includes(inputValue)) { + (item as CDSMultiSelectItem).setAttribute('filtered', ''); + (item as CDSMultiSelectItem).removeAttribute('highlighted'); + } else { + (item as CDSMultiSelectItem).removeAttribute('filtered'); + } + }); + + this.requestUpdate(); + } + + /** + * Navigate through dropdown items. + * + * @param direction `-1` to navigate backward, `1` to navigate forward. + */ + protected _navigate(direction: number) { + if (!this.filterable) { + super._navigate(direction); + } else { + // only navigate through remaining item + const constructor = this.constructor as typeof CDSMultiSelect; + const items = this.querySelectorAll(constructor.selectorItemResults); + const highlightedItem = this.querySelector( + constructor.selectorItemHighlighted + ); + const highlightedIndex = indexOf(items, highlightedItem!); + + let nextIndex = highlightedIndex + direction; + if (nextIndex < 0) { + nextIndex = items.length - 1; + } + if (nextIndex >= items.length) { + nextIndex = 0; + } + forEach(items, (item, i) => { + (item as CDSMultiSelectItem).highlighted = i === nextIndex; + }); + } + } + + /** + * Handles user-initiated clearing the `` for filtering. + */ + protected _handleUserInitiatedClearInput() { + const constructor = this.constructor as typeof CDSMultiSelect; + const items = this.querySelectorAll(constructor.selectorItemFiltered); + this._filterInputNode.value = ''; + this.open = true; + this._filterInputNode.focus(); + forEach(items, (item) => { + (item as CDSMultiSelectItem).removeAttribute('filtered'); + }); + } + + /** + * The `aria-label` attribute for the icon to clear selection. + */ + @property({ attribute: 'clear-selection-label' }) + clearSelectionLabel = ''; + + /** + * Specify the text that should be read for screen readers that describes total items selected + */ + @property({ attribute: 'clear-selection-description' }) + clearSelectionDescription = 'Total items selected: '; + + /** + * Specify the text that should be read for screen readers to clear selection. + */ + @property({ attribute: 'clear-selection-text' }) + clearSelectionText = 'To clear selection, press Delete or Backspace.'; + + /** + * Specify the locale of the control. Used for the default compareItems used for sorting the list of items in the control. + */ + @property() + locale = 'en'; + + /** + * Specify feedback (mode) of the selection. + * `top`: selected item jumps to top + * `fixed`: selected item stays at it's position + * `top-after-reopen`: selected item jump to top after reopen dropdown + */ + @property({ attribute: 'selection-feedback' }) + selectionFeedback = SELECTION_FEEDBACK_OPTION.TOP_AFTER_REOPEN; + + /** + * The CSS class list for multi-select listbox + */ + protected get _classes() { + const { + disabled, + size, + type, + invalid, + readOnly, + open, + warn, + _selectedItemsCount: selectedItemsCount, + } = this; + const inline = type === DROPDOWN_TYPE.INLINE; + + return classMap({ + [`${prefix}--multi-select`]: true, + [`${prefix}--list-box`]: true, + [`${prefix}--list-box--disabled`]: disabled, + [`${prefix}--list-box--inline`]: inline, + [`${prefix}--list-box--expanded`]: open, + [`${prefix}--list-box--${size}`]: size, + [`${prefix}--multi-select--invalid`]: invalid, + [`${prefix}--multi-select--warn`]: warn, + [`${prefix}--multi-select--inline`]: inline, + [`${prefix}--multi-select--readonly`]: readOnly, + [`${prefix}--multi-select--selected`]: selectedItemsCount > 0, + }); + } + + protected compareItems = (itemA, itemB, { locale }) => { + itemA.localeCompare(itemB, locale, { numeric: true }); + }; + + protected sortItems = ( + menuItems: NodeList, + { values, compareItems, locale = 'en' } + ) => { + const menuItemsArray = Array.from(menuItems); + + const sortedArray = menuItemsArray.sort((itemA, itemB) => { + const hasItemA = values.includes((itemA as HTMLInputElement).value); + const hasItemB = values.includes((itemB as HTMLInputElement).value); + + // Prefer whichever item is in the `value` array first + if (hasItemA && !hasItemB) { + return -1; + } + + if (hasItemB && !hasItemA) { + return 1; + } + + return compareItems( + (itemA as HTMLInputElement).value, + (itemB as HTMLInputElement).value, + { + locale, + } + ); + }); + + return sortedArray; + }; + + shouldUpdate(changedProperties) { + const { selectorItem, slugItem } = this + .constructor as typeof CDSMultiSelect; + const slug = this.querySelector(slugItem); + const items = this.querySelectorAll(selectorItem); + + const { value, locale } = this; + const values = !value ? [] : value.split(','); + + if (changedProperties.has('size')) { + forEach(this.querySelectorAll(selectorItem), (elem) => { + (elem as CDSMultiSelectItem).size = this.size; + }); + } + if (changedProperties.has('value')) { + // Updates selection beforehand because our rendering logic for `` looks for selected items via `qSA()` + forEach(items, (elem) => { + (elem as CDSMultiSelectItem).selected = + values.indexOf((elem as CDSMultiSelectItem).value) >= 0; + }); + this._selectedItemsCount = filter( + items, + (elem) => values.indexOf((elem as CDSMultiSelectItem).value) >= 0 + ).length; + + if (this.selectionFeedback === SELECTION_FEEDBACK_OPTION.TOP) { + const sortedMenuItems = this.sortItems(items, { + values, + compareItems: this.compareItems, + locale, + }); + + slug ? sortedMenuItems.unshift(slug as Node) : ''; + // @todo remove typecast once we've updated to Typescript. + (this as any).replaceChildren(...sortedMenuItems); + } + } + if (changedProperties.has('open')) { + if ( + this.selectionFeedback === SELECTION_FEEDBACK_OPTION.TOP_AFTER_REOPEN + ) { + const sortedMenuItems = this.sortItems(items, { + values, + compareItems: this.compareItems, + locale, + }); + + slug ? sortedMenuItems.unshift(slug as Node) : ''; + // @todo remove typecast once we've updated to Typescript. + (this as any).replaceChildren(...sortedMenuItems); + } + } + return true; + } + + updated(changedProperties) { + super.updated(changedProperties); + if (changedProperties.has('open') && this.open && !this.filterable) { + // move focus to menu body when open for non-filterable mulit-select + this._menuBodyNode.focus(); + } + } + + connectedCallback() { + super.connectedCallback(); + /** + * Detect if multi-select already has initially selected items + */ + this.value = filter( + this.querySelectorAll( + (this.constructor as typeof CDSMultiSelect).selectorItem + ), + (item) => (item as CDSMultiSelectItem).selected + ) + .map((item) => (item as CDSMultiSelectItem).value) + .join(','); + } + + /** + * A selector that will return menu body. + */ + static get selectorMenuBody() { + return `div[part="menu-body"]`; + } + + /** + * A selector that will return highlighted items. + */ + static get selectorItemHighlighted() { + return `${prefix}-multi-select-item[highlighted]`; + } + + /** + * A selector that will return multi select items. + * We use a separate property from `.itemTagName` due to the nature in difference of tag name vs. selector. + */ + static get selectorItem() { + return `${prefix}-multi-select-item`; + } + + /** + * A selector that will return remaining items after a filter. + */ + static get selectorItemFiltered() { + return `${prefix}-multi-select-item[filtered]`; + } + + /** + * A selector that will return remaining items after a filter. + */ + static get selectorItemResults() { + return `${prefix}-multi-select-item:not([filtered])`; + } + + /** + * A selector that will return selected items. + */ + static get selectorItemSelected() { + return `${prefix}-multi-select-item[selected]`; + } + + /** + * The name of the custom event fired before this multi select item is being toggled upon a user gesture. + * Cancellation of this event stops the user-initiated action of toggling this multi select item. + */ + static get eventBeforeToggle() { + return `${prefix}-multi-select-beingtoggled`; + } + + /** + * The name of the custom event fired after this multi select item is toggled upon a user gesture. + */ + static get eventToggle() { + return `${prefix}-multi-select-toggled`; + } + + /** + * The name of the custom event fired before a multi select item is selected upon a user gesture. + * Cancellation of this event stops changing the user-initiated selection. + */ + static get eventBeforeSelect() { + return `${prefix}-multi-select-beingselected`; + } + + /** + * The name of the custom event fired after a a multi select item is selected upon a user gesture. + */ + static get eventSelect() { + return `${prefix}-multi-select-selected`; + } + + static styles = styles; +} + +export default CDSMultiSelect; diff --git a/packages/web-components/src/components/notification/actionable-notification-button.ts b/packages/web-components/src/components/notification/actionable-notification-button.ts new file mode 100644 index 000000000000..e9d867a8f0df --- /dev/null +++ b/packages/web-components/src/components/notification/actionable-notification-button.ts @@ -0,0 +1,34 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { prefix } from '../../globals/settings'; +import CDSButton from '../button/button'; +import styles from './actionable-notification.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Actionable notification action button. + * + * @element cds-actionable-notification-button + */ +@customElement(`${prefix}-actionable-notification-button`) +class CDSActionableNotificationButton extends CDSButton { + update(changedProperties) { + super.update(changedProperties); + this.shadowRoot!.getElementById('button')?.classList.add( + `${prefix}--actionable-notification__action-button` + ); + + this.setAttribute('size', 'sm'); + } + + static styles = styles; +} + +export default CDSActionableNotificationButton; diff --git a/packages/web-components/src/components/notification/actionable-notification.scss b/packages/web-components/src/components/notification/actionable-notification.scss new file mode 100644 index 000000000000..bddb75907e94 --- /dev/null +++ b/packages/web-components/src/components/notification/actionable-notification.scss @@ -0,0 +1,217 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/colors' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/components/notification/index' as *; +@use '@carbon/styles/scss/components/notification/mixins' as *; +@use '@carbon/styles/scss/components/button'; +@use '@carbon/styles/scss/components/button/mixins' as button-mixins; +@use '@carbon/styles/scss/components/button/vars' as button-vars; +@use '@carbon/styles/scss/layout' as *; + +@include actionable-notification; + +:host(#{$prefix}-actionable-notification) { + @extend .#{$prefix}--actionable-notification; + @include emit-layout-tokens(); + + display: none; + outline: none; +} + +:host( + #{$prefix}-actionable-notification-button:not( + [low-contrast] + )[kind='tertiary'] + ) + button { + @include button-mixins.button-theme( + transparent, + $notification-action-tertiary-inverse, + $notification-action-tertiary-inverse, + $notification-action-tertiary-inverse-hover, + currentColor, + $notification-action-tertiary-inverse-active + ); + + &:focus { + border-color: $focus-inverse; + background-color: $notification-action-tertiary-inverse; + box-shadow: inset 0 0 0 button-vars.$button-outline-width $focus-inverse, + inset 0 0 0 button-vars.$button-border-width $background-inverse; + color: $notification-action-tertiary-inverse-text; + } + + &:hover { + color: $notification-action-tertiary-inverse-text; + } + + &:active { + border-color: transparent; + background-color: $notification-action-tertiary-inverse-active; + color: $notification-action-tertiary-inverse-text; + } +} + +:host(#{$prefix}-actionable-notification-button[low-contrast][kind='ghost']) + button { + &:hover, + &:active { + background-color: $notification-action-hover; + } + + &:focus { + outline-color: $focus; + } +} + +:host( + #{$prefix}-actionable-notification-button:not([low-contrast])[kind='ghost'] + ) + button { + color: $link-inverse; +} + +:host( + #{$prefix}-actionable-notification-button[hide-close-button][kind='ghost'] + ) + button { + margin-inline-end: $spacing-03; +} + +:host(#{$prefix}-actionable-notification:not([inline])) { + @extend .#{$prefix}--actionable-notification--toast; +} + +:host(#{$prefix}-actionable-notification[inline][low-contrast])::before { + position: absolute; + box-sizing: border-box; + border-width: 1px 1px 1px 0; + border-style: solid; + block-size: 100%; + content: ''; + filter: opacity(0.4); + inline-size: 100%; + inset-block-start: 0; + inset-inline-start: 0; + pointer-events: none; +} + +:host(#{$prefix}-actionable-notification[open]) { + display: flex; +} + +:host(#{$prefix}-actionable-notification[hide-close-button]) + .#{$prefix}--actionable-notification__close-button { + display: none; +} + +:host(#{$prefix}-actionable-notification[kind='success']) { + @extend .#{$prefix}--actionable-notification--success; +} + +:host(#{$prefix}-actionable-notification[kind='success'][low-contrast]) { + @extend .#{$prefix}--actionable-notification--low-contrast, + .#{$prefix}--actionable-notification--success; + + @include notification--experimental( + $support-success, + $notification-background-success + ); + + &::before { + border-color: $support-success; + } +} + +:host(#{$prefix}-actionable-notification[kind='info']) { + @extend .#{$prefix}--actionable-notification--info; +} + +:host(#{$prefix}-actionable-notification[kind='info-square']) { + @extend .#{$prefix}--actionable-notification--info-square; +} + +:host(#{$prefix}-actionable-notification[kind='info'][low-contrast]), +:host(#{$prefix}-actionable-notification[kind='info-square'][low-contrast]) { + @extend .#{$prefix}--actionable-notification--low-contrast, + .#{$prefix}--actionable-notification--info; + + @include notification--experimental( + $support-info, + $notification-background-info + ); + + &::before { + border-color: $support-info; + } +} + +:host(#{$prefix}-actionable-notification[kind='warning']) { + @extend .#{$prefix}--actionable-notification--warning; + + /* TODO: Remove this once the following issue with icon fill is resolved: + ** https://github.com/carbon-design-system/carbon/issues/13616 + */ + .#{$prefix}--inline-notification__icon path[data-icon-path='inner-path'] { + fill: $black-100; + opacity: 1; + } +} + +:host(#{$prefix}-actionable-notification[kind='warning-alt']) { + @extend .#{$prefix}--actionable-notification--warning-alt; + + /* TODO: Remove this once the following issue with icon fill is resolved: + ** https://github.com/carbon-design-system/carbon/issues/13616 + */ + .#{$prefix}--inline-notification__icon, + .#{$prefix}--toast-notification__icon { + path[data-icon-path='inner-path'] { + fill: $black-100; + opacity: 1; + } + } +} + +:host(#{$prefix}-actionable-notification[kind='warning'][low-contrast]), +:host(#{$prefix}-actionable-notification[kind='warning-alt'][low-contrast]) { + @extend .#{$prefix}--actionable-notification--low-contrast, + .#{$prefix}--actionable-notification--warning; + + @include notification--experimental( + $support-warning, + $notification-background-warning + ); + + &::before { + border-color: $support-warning; + } +} + +:host(#{$prefix}-actionable-notification[kind='error']) { + @extend .#{$prefix}--actionable-notification--error; +} + +:host(#{$prefix}-actionable-notification[kind='error'][low-contrast]) { + @extend .#{$prefix}--actionable-notification--low-contrast, + .#{$prefix}--actionable-notification--error; + + @include notification--experimental( + $support-error, + $notification-background-error + ); + + &::before { + border-color: $support-error; + } +} diff --git a/packages/web-components/src/components/notification/actionable-notification.stories.ts b/packages/web-components/src/components/notification/actionable-notification.stories.ts new file mode 100644 index 000000000000..202bf2a8fd0d --- /dev/null +++ b/packages/web-components/src/components/notification/actionable-notification.stories.ts @@ -0,0 +1,167 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { NOTIFICATION_KIND } from './inline-notification'; +import './actionable-notification'; +import './actionable-notification-button'; +import storyDocs from './notification.mdx'; +import { prefix } from '../../globals/settings'; +import kinds from './stories/helper'; +import '../button/button'; + +const noop = () => {}; + +const args = { + actionButtonLabel: 'Action', + closeOnEscape: true, + hasFocus: false, + hideCloseButton: false, + inline: false, + kind: NOTIFICATION_KIND.ERROR, + lowContrast: false, + role: 'alertdialog', + subtitle: 'Subtitle text goes here', + statusIconDescription: 'notification', + title: 'Notification title', +}; + +const argTypes = { + actionButtonLabel: { + control: 'text', + description: + 'Pass in the action button label that will be rendered within the ActionableNotification.', + }, + closeOnEscape: { + control: 'boolean', + description: + 'Specify if pressing the escape key should close notifications.', + }, + hasFocus: { + control: 'boolean', + description: + 'Specify if focus should be moved to the component when the notification contains actions.', + }, + hideCloseButton: { + control: 'boolean', + description: 'Specify the close button should be disabled, or not.', + }, + inline: { + control: 'boolean', + }, + kind: { + control: 'select', + description: 'Specify what state the notification represents.', + options: kinds, + }, + lowContrast: { + control: 'boolean', + description: + 'Specify whether you are using the low contrast variant of the ActionableNotification.', + }, + role: { + control: 'text', + description: + 'By default, this value is "alertdialog". You can also provide an alternate role if it makes sense from from an accessibility perspective.', + }, + subtitle: { + control: 'text', + description: 'Specify the subtitle.', + }, + statusIconDescription: { + control: 'text', + description: + 'Provide a description for "status" icon that can be read by screen readers.', + }, + title: { + control: 'text', + description: 'Specify the title.', + }, + onBeforeClose: { + action: `${prefix}-notification-beingclosed`, + }, + onClose: { + action: `${prefix}-notification-closed`, + }, +}; + +export const Default = { + render: () => { + return html` + + Action + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + actionButtonLabel, + closeOnEscape, + hasFocus, + kind, + title, + subtitle, + hideCloseButton, + lowContrast, + role, + inline, + statusIconDescription, + disableClose, + onBeforeClose = noop, + onClose = noop, + } = args ?? {}; + const handleBeforeClose = (event: CustomEvent) => { + onBeforeClose(event); + if (disableClose) { + event.preventDefault(); + } + }; + return html` + + ${actionButtonLabel} + + `; + }, +}; + +const meta = { + title: 'Components/Notifications/Actionable', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/notification/actionable-notification.ts b/packages/web-components/src/components/notification/actionable-notification.ts new file mode 100644 index 000000000000..265571082bef --- /dev/null +++ b/packages/web-components/src/components/notification/actionable-notification.ts @@ -0,0 +1,185 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ +import CheckmarkFilled20 from '@carbon/icons/lib/checkmark--filled/20'; +import ErrorFilled20 from '@carbon/icons/lib/error--filled/20'; +import InformationFilled20 from '@carbon/icons/lib/information--filled/20'; +import InformationSquareFilled20 from '@carbon/icons/lib/information--square--filled/20'; +import WarningFilled20 from '@carbon/icons/lib/warning--filled/20'; +import WarningAltFilled20 from '@carbon/icons/lib/warning--alt--filled/20'; +import { html, svg } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { NOTIFICATION_TYPE, NOTIFICATION_KIND } from './defs'; +import CDSInlineNotification from './inline-notification'; +import styles from './actionable-notification.scss?lit'; +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; + +/** + * The default icons, keyed by notification kind. + */ +const iconsForKinds = { + [NOTIFICATION_KIND.SUCCESS]: CheckmarkFilled20, + [NOTIFICATION_KIND.INFO]: InformationFilled20, + [NOTIFICATION_KIND.INFO_SQUARE]: InformationSquareFilled20, + [NOTIFICATION_KIND.WARNING]: WarningFilled20, + [NOTIFICATION_KIND.WARNING_ALT]: WarningAltFilled20, + [NOTIFICATION_KIND.ERROR]: ErrorFilled20, +}; + +/** + * Actionable notification. + * + * @element cds-actionable-notification + * @slot subtitle - The subtitle. + * @slot title - The title. + * @fires cds-notification-beingclosed + * The custom event fired before this notification is being closed upon a user gesture. + * Cancellation of this event stops the user-initiated action of closing this notification. + * @fires cds-notification-closed - The custom event fired after this notification is closed upon a user gesture. + */ +@customElement(`${prefix}-actionable-notification`) +class CDSActionableNotification extends HostListenerMixin( + CDSInlineNotification +) { + protected _type = NOTIFICATION_TYPE.ACTIONABLE; + + /** + * Inline notification type. + */ + @property({ type: Boolean, reflect: true }) + inline = false; + + /** + * Pass in the action button label that will be rendered within the ActionableNotification. + */ + @property({ type: String, reflect: true, attribute: 'action-button-label' }) + actionButtonLabel = ''; + + /** + * Specify if pressing the escape key should close notifications + */ + @property({ type: Boolean, reflect: true, attribute: 'close-on-escape' }) + closeOnEscape = true; + + /** + * Specify if focus should be moved to the component when the notification contains actions + */ + @property({ type: Boolean, reflect: true, attribute: 'has-focus' }) + hasFocus = true; + + /** + * Handles `keydown` event on this event. + * Escape will close the notification if `closeOnEscape` is true + */ + @HostListener('keydown') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleKeyDown = async (event: KeyboardEvent) => { + const { key } = event; + if (this.closeOnEscape && key === 'Escape') { + this.open = false; + } + }; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'alertdialog'); + } + super.connectedCallback(); + } + + protected _renderIcon() { + const { statusIconDescription, kind, inline } = this; + const { [kind]: icon } = iconsForKinds; + return !icon + ? undefined + : icon({ + class: `${prefix}--${inline ? 'inline' : 'toast'}-notification__icon`, + children: !statusIconDescription + ? undefined + : svg`${statusIconDescription}`, + }); + } + + protected _renderText() { + const { subtitle, title, _type: type } = this; + return html` +
    +
    +
    + ${title} +
    +
    + ${subtitle} +
    + +
    +
    + `; + } + + /** + * The caption. + */ + @property() + caption = ''; + + updated(changedProperties) { + super.updated(changedProperties); + const button = this.querySelector( + (this.constructor as typeof CDSActionableNotification) + .selectorActionButton + ); + if (changedProperties.has('inline')) { + button?.setAttribute('kind', this.inline ? 'ghost' : 'tertiary'); + } + if (changedProperties.has('lowContrast')) { + if (this.lowContrast) { + button?.setAttribute('low-contrast', 'true'); + } else { + button?.removeAttribute('low-contrast'); + } + } + if (changedProperties.has('hideCloseButton')) { + if (this.hideCloseButton) { + button?.setAttribute('hide-close-button', 'true'); + } else { + button?.removeAttribute('hide-close-button'); + } + } + if (changedProperties.has('hasFocus')) { + if (this.hasFocus) { + this.focus(); + } + } + } + + render() { + const { _type: type } = this; + return html` +
    + ${this._renderIcon()} ${this._renderText()} +
    + + ${this._renderButton()} + `; + } + + /** + * A selector that will return the action button element + */ + static get selectorActionButton() { + return `${prefix}-actionable-notification-button`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSActionableNotification; diff --git a/packages/web-components/src/components/notification/defs.ts b/packages/web-components/src/components/notification/defs.ts new file mode 100644 index 000000000000..99dd052da03a --- /dev/null +++ b/packages/web-components/src/components/notification/defs.ts @@ -0,0 +1,69 @@ +/** + * @license + * + * Copyright IBM Corp. 2020 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Notification kinds. + */ +export enum NOTIFICATION_KIND { + /** + * Notification to represent success state. + */ + SUCCESS = 'success', + + /** + * Informational notification. + */ + INFO = 'info', + + /** + * Informational square icon notification. + */ + INFO_SQUARE = 'info-square', + + /** + * Warning notification. + */ + WARNING = 'warning', + + /** + * Warning Alt notification. + */ + WARNING_ALT = 'warning-alt', + + /** + * Error notification. + */ + ERROR = 'error', +} + +/** + * Notification types. + */ +export enum NOTIFICATION_TYPE { + /** + * Inline notification, which show up in task flows, to notify users of the status of an action. + * They usually appear at the top of the primary content area. + */ + INLINE = 'inline', + + /** + * Toast notification, which is a non-modal, time-based window elements used to display short messages. + * They usually appear at the bottom of the screen and disappear after a few seconds. + */ + TOAST = 'toast', + + /** + * Actionable notifications allow for interactive elements within a notification styled like an inline + * or toast notification. Actionable notifications, since they require user interaction, take focus when + * triggered and can be highly disruptive to screen readers and keyboard users. With actionable notifications, + * only one action is allowed per notification. This action frequently takes users to a flow or page related + * to the message, where they can resolve the notification. + */ + ACTIONABLE = 'actionable', +} diff --git a/packages/web-components/src/components/notification/docs/overview.mdx b/packages/web-components/src/components/notification/docs/overview.mdx new file mode 100644 index 000000000000..82245ba95712 --- /dev/null +++ b/packages/web-components/src/components/notification/docs/overview.mdx @@ -0,0 +1,16 @@ +## Live demo + + diff --git a/packages/web-components/src/components/notification/index.ts b/packages/web-components/src/components/notification/index.ts new file mode 100644 index 000000000000..899b14e76237 --- /dev/null +++ b/packages/web-components/src/components/notification/index.ts @@ -0,0 +1,13 @@ +/** + * @license + * + * Copyright IBM Corp. 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './inline-notification'; +import './toast-notification'; +import './actionable-notification'; +import './actionable-notification-button'; diff --git a/packages/web-components/src/components/notification/inline-notification.scss b/packages/web-components/src/components/notification/inline-notification.scss new file mode 100644 index 000000000000..b114dca19d1f --- /dev/null +++ b/packages/web-components/src/components/notification/inline-notification.scss @@ -0,0 +1,153 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/colors' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities/focus-outline' as *; +@use '@carbon/styles/scss/components/notification/index' as *; +@use '@carbon/styles/scss/components/notification/mixins' as *; +@use '@carbon/styles/scss/components/button'; +@use '@carbon/styles/scss/layout' as *; + +// https://github.com/carbon-design-system/carbon/issues/11408 +@include inline-notification; + +:host(#{$prefix}-inline-notification) { + @extend .#{$prefix}--inline-notification; + @include emit-layout-tokens(); + + display: none; + outline: none; + + .#{$prefix}--inline-notification__close-button:focus { + @include focus-outline('outline'); + } + + .#{$prefix}--inline-notification__title { + margin-block: 0 0; + } +} + +:host(#{$prefix}-inline-notification[low-contrast])::before { + position: absolute; + box-sizing: border-box; + border-width: 1px 1px 1px 0; + border-style: solid; + block-size: 100%; + content: ''; + filter: opacity(0.4); + inline-size: 100%; + inset-block-start: 0; + inset-inline-start: 0; + pointer-events: none; +} + +:host(#{$prefix}-inline-notification[open]) { + display: flex; +} + +:host(#{$prefix}-inline-notification[hide-close-button]) + .#{$prefix}--inline-notification__close-button { + display: none; +} + +:host(#{$prefix}-inline-notification[kind='success']) { + @extend .#{$prefix}--inline-notification--success; +} + +:host(#{$prefix}-inline-notification[kind='success'][low-contrast]) { + @extend .#{$prefix}--inline-notification--low-contrast, + .#{$prefix}--inline-notification--success; + + @include notification--experimental( + $support-success, + $notification-background-success + ); + + &::before { + border-color: $support-success; + } +} + +:host(#{$prefix}-inline-notification[kind='info']) { + @extend .#{$prefix}--inline-notification--info; +} + +:host(#{$prefix}-inline-notification[kind='info-square']) { + @extend .#{$prefix}--inline-notification--info-square; +} + +:host(#{$prefix}-inline-notification[kind='info'][low-contrast]), +:host(#{$prefix}-inline-notification[kind='info-square'][low-contrast]) { + @extend .#{$prefix}--inline-notification--low-contrast, + .#{$prefix}--inline-notification--info; + + @include notification--experimental( + $support-info, + $notification-background-info + ); + + &::before { + border-color: $support-info; + } +} + +:host(#{$prefix}-inline-notification[kind='warning']) { + @extend .#{$prefix}--inline-notification--warning; +} + +:host(#{$prefix}-inline-notification[kind='warning-alt']) { + @extend .#{$prefix}--inline-notification--warning-alt; + + &[low-contrast] { + @extend .#{$prefix}--inline-notification--low-contrast, + .#{$prefix}--inline-notification--warning-alt; + } + + /* TODO: Remove this once the following issue with icon fill is resolved: + ** https://github.com/carbon-design-system/carbon/issues/13616 + */ + .#{$prefix}--inline-notification__icon path[data-icon-path='inner-path'] { + fill: $black-100; + } +} + +:host(#{$prefix}-inline-notification[kind='warning'][low-contrast]), +:host(#{$prefix}-inline-notification[kind='warning-alt'][low-contrast]) { + @extend .#{$prefix}--inline-notification--low-contrast, + .#{$prefix}--inline-notification--warning; + + @include notification--experimental( + $support-warning, + $notification-background-warning + ); + + &::before { + border-color: $support-warning; + } +} + +:host(#{$prefix}-inline-notification[kind='error']) { + @extend .#{$prefix}--inline-notification--error; +} + +:host(#{$prefix}-inline-notification[kind='error'][low-contrast]) { + @extend .#{$prefix}--inline-notification--low-contrast, + .#{$prefix}--inline-notification--error; + + @include notification--experimental( + $support-error, + $notification-background-error + ); + + &::before { + border-color: $support-error; + } +} diff --git a/packages/web-components/src/components/notification/inline-notification.stories.ts b/packages/web-components/src/components/notification/inline-notification.stories.ts new file mode 100644 index 000000000000..a1620eabd960 --- /dev/null +++ b/packages/web-components/src/components/notification/inline-notification.stories.ts @@ -0,0 +1,132 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import storyDocs from './notification.mdx'; +import { NOTIFICATION_KIND } from './inline-notification'; +import { prefix } from '../../globals/settings'; +import kinds from './stories/helper'; + +const noop = () => {}; + +const args = { + hideCloseButton: false, + kind: NOTIFICATION_KIND.INFO, + lowContrast: false, + role: 'status', + statusIconDescription: 'notification', + subtitle: 'Subtitle text goes here', + title: 'Notification title', +}; + +const argTypes = { + hideCloseButton: { + control: 'boolean', + description: 'Specify the close button should be disabled, or not.', + }, + kind: { + control: 'select', + description: 'Specify what state the notification represents.', + options: kinds, + }, + lowContrast: { + control: 'boolean', + description: + 'Specify whether you are using the low contrast variant of the InlineNotification.', + }, + role: { + control: 'select', + description: + 'By default, this value is "status". You can also provide an alternate role if it makes sense from the accessibility-side.', + options: { alert: 'alert', log: 'log', status: 'status' }, + }, + statusIconDescription: { + control: 'text', + description: + 'Provide a description for "status" icon that can be read by screen readers.', + }, + subtitle: { + control: 'text', + description: 'Specify the subtitle.', + }, + title: { + control: 'text', + description: 'Specify the title.', + }, + onBeforeClose: { + action: `${prefix}-notification-beingclosed`, + }, + onClose: { + action: `${prefix}-notification-closed`, + }, +}; + +export const Default = { + render: () => { + return html` + + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + kind, + title, + subtitle, + hideCloseButton, + lowContrast, + role, + statusIconDescription, + timeout, + disableClose, + onBeforeClose = noop, + onClose = noop, + } = args ?? {}; + const handleBeforeClose = (event: CustomEvent) => { + onBeforeClose(event); + if (disableClose) { + event.preventDefault(); + } + }; + return html` + + + `; + }, +}; + +const meta = { + title: 'Components/Notifications/Inline', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/notification/inline-notification.ts b/packages/web-components/src/components/notification/inline-notification.ts new file mode 100644 index 000000000000..ea2c285bbc49 --- /dev/null +++ b/packages/web-components/src/components/notification/inline-notification.ts @@ -0,0 +1,291 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import CheckmarkFilled20 from '@carbon/icons/lib/checkmark--filled/20'; +import Close16 from '@carbon/icons/lib/close/16'; +import ErrorFilled20 from '@carbon/icons/lib/error--filled/20'; +import InformationFilled20 from '@carbon/icons/lib/information--filled/20'; +import InformationSquareFilled20 from '@carbon/icons/lib/information--square--filled/20'; +import WarningFilled20 from '@carbon/icons/lib/warning--filled/20'; +import WarningAltFilled20 from '@carbon/icons/lib/warning--alt--filled/20'; +import { LitElement, html, svg } from 'lit'; +import { property } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import FocusMixin from '../../globals/mixins/focus'; +import { NOTIFICATION_KIND, NOTIFICATION_TYPE } from './defs'; +import styles from './inline-notification.scss?lit'; + +export { NOTIFICATION_KIND, NOTIFICATION_TYPE }; + +/** + * The default icons, keyed by notification kind. + */ +const iconsForKinds = { + [NOTIFICATION_KIND.SUCCESS]: CheckmarkFilled20, + [NOTIFICATION_KIND.INFO]: InformationFilled20, + [NOTIFICATION_KIND.INFO_SQUARE]: InformationSquareFilled20, + [NOTIFICATION_KIND.WARNING]: WarningFilled20, + [NOTIFICATION_KIND.WARNING_ALT]: WarningAltFilled20, + [NOTIFICATION_KIND.ERROR]: ErrorFilled20, +}; + +/** + * Inline notification. + * + * @element cds-inline-notification + * @slot subtitle - The subtitle. + * @slot title - The title. + * @fires cds-notification-beingclosed + * The custom event fired before this notification is being closed upon a user gesture. + * Cancellation of this event stops the user-initiated action of closing this notification. + * @fires cds-notification-closed - The custom event fired after this notification is closed upon a user gesture. + */ +@customElement(`${prefix}-inline-notification`) +class CDSInlineNotification extends FocusMixin(LitElement) { + /** + * Current timeout identifier + */ + protected _timeoutID: number | null = null; + + /** + * Notification type. + */ + protected _type = NOTIFICATION_TYPE.INLINE; + + /** + * Cancels the current timeout configured for the notification + * + * @param timeoutID current timeout's identifier + */ + protected _cancelTimeout(timeoutID: number) { + clearTimeout(timeoutID); + this._timeoutID = null; + } + + /** + * Overrides (if exists) the timeout to close the notification + * + * @param timeout the time in ms + */ + protected _initializeTimeout(timeout: number) { + if (this._timeoutID) { + this._cancelTimeout(this._timeoutID); + } + this._timeoutID = setTimeout( + this._handleUserOrTimerInitiatedClose.bind(this, null), + timeout + ) as unknown as number; + } + + /** + * Handles `click` event on the close button. + * + * @param event The event. + * @param event.target The event target. + */ + protected _handleClickCloseButton({ target }: MouseEvent) { + this._handleUserOrTimerInitiatedClose(target); + } + + /** + * Handles user-initiated or through timer close request of this modal. + * + * @param triggeredBy The element that triggered this close request, if there is one. + */ + protected _handleUserOrTimerInitiatedClose(triggeredBy: EventTarget | null) { + if (this.open) { + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + triggeredBy, + }, + }; + if ( + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSInlineNotification).eventBeforeClose, + init + ) + ) + ) { + this.open = false; + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSInlineNotification).eventClose, + init + ) + ); + } + } + } + + /** + * @returns The template part for the close button. + */ + protected _renderButton() { + const { + ariaLabel, + _type: type, + _handleClickCloseButton: handleClickCloseButton, + } = this; + return html` + + `; + } + + /** + * @returns The template part for the text contents. + */ + protected _renderText() { + const { subtitle, title, _type: type } = this; + return html` +
    +

    + ${title} +

    +
    + ${subtitle} +
    + +
    + `; + } + + /** + * @returns The template part for the icon. + */ + protected _renderIcon() { + const { statusIconDescription, kind, _type: type } = this; + const { [kind]: icon } = iconsForKinds; + return !icon + ? undefined + : icon({ + class: `${prefix}--${type}-notification__icon`, + children: !statusIconDescription + ? undefined + : svg`${statusIconDescription}`, + }); + } + + /** + * Provide a description for "close" icon button that can be read by screen readers + */ + @property({ attribute: 'aria-label' }) + ariaLabel!: string; + + /** + * `true` to hide the close button. + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-close-button' }) + hideCloseButton = false; + + /** + * Provide a description for "status" icon that can be read by screen readers + */ + @property({ attribute: 'status-icon-description' }) + statusIconDescription!: string; + + /** + * Notification kind. + */ + @property({ reflect: true }) + kind = NOTIFICATION_KIND.SUCCESS; + + /** + * Low contrast mode + */ + @property({ type: Boolean, reflect: true, attribute: 'low-contrast' }) + lowContrast = false; + + /** + * `true` if the notification should be open. + */ + @property({ type: Boolean, reflect: true }) + open = true; + + /** + * Specify an optional duration the notification should be closed in + */ + @property({ type: Number, reflect: true }) + timeout: number | null = null; + + /** + * The subtitle. + */ + @property() + subtitle = ''; + + /** + * The title. + */ + @property() + title = ''; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'alert'); + } + super.connectedCallback(); + } + + updated(changedProperties) { + const openChanged = changedProperties.has('open'); + const timeoutChanged = changedProperties.has('timeout'); + + if (openChanged || timeoutChanged) { + if (this.open && this.timeout) { + this._initializeTimeout(this.timeout); + } else if (!this.open && this._timeoutID) { + this._cancelTimeout(this._timeoutID); + } + } + } + + render() { + const { _type: type } = this; + return html` +
    + ${this._renderIcon()}${this._renderText()} +
    + ${this._renderButton()} + `; + } + + /** + * The name of the custom event fired before this notification is being closed upon a user gesture. + * Cancellation of this event stops the user-initiated action of closing this notification. + */ + static get eventBeforeClose() { + return `${prefix}-notification-beingclosed`; + } + + /** + * The name of the custom event fired after this notification is closed upon a user gesture. + */ + static get eventClose() { + return `${prefix}-notification-closed`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSInlineNotification; diff --git a/packages/web-components/src/components/notification/notification.mdx b/packages/web-components/src/components/notification/notification.mdx new file mode 100644 index 000000000000..bf311e59a153 --- /dev/null +++ b/packages/web-components/src/components/notification/notification.mdx @@ -0,0 +1,113 @@ +import { ArgTypes, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; + +# Notification + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/notification) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/notification) + +Notifications are messages that communicate information to the user. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/notification/index.js'; +``` + +### SCSS (must include with JS import) + +```css +@use '@carbon/styles/scss/components/notification'; +``` + +{`${cdnJs({ components: ['notification'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + +``` + +## Actionable notification + +Actionable notifications allow for interactive elements within a notification +styled like an inline or toast notification. Actionable notifications, since +they require user interaction, take focus when triggered and can be highly +disruptive to screen readers and keyboard users. With actionable notifications, +only one action is allowed per notification. This action frequently takes users +to a flow or page related to the message, where they can resolve the +notification. + +```html + + Action + +``` + +## Inline notification + +Inline notifications show up in task flows, to notify users of the status of an +action. They usually appear at the top of the primary content area. + +```html + + +``` + +## Toast notification + +Toasts are a non-modal, time-based window elements used to display short +messages; they usually appear at the bottom of the screen and disappear after a +few seconds. + +```html + + +``` + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the +attribute (e.g. `` without `open` attribute). + + + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `open` attribute). + + + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `open` attribute). + + diff --git a/packages/web-components/src/components/notification/stories/helper.ts b/packages/web-components/src/components/notification/stories/helper.ts new file mode 100644 index 000000000000..a6813a882aa9 --- /dev/null +++ b/packages/web-components/src/components/notification/stories/helper.ts @@ -0,0 +1,22 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { NOTIFICATION_KIND } from '../inline-notification'; + +const kinds = { + [`Error (${NOTIFICATION_KIND.ERROR})`]: NOTIFICATION_KIND.ERROR, + [`Info (${NOTIFICATION_KIND.INFO})`]: NOTIFICATION_KIND.INFO, + [`Info (${NOTIFICATION_KIND.INFO_SQUARE})`]: NOTIFICATION_KIND.INFO_SQUARE, + [`Success (${NOTIFICATION_KIND.SUCCESS})`]: NOTIFICATION_KIND.SUCCESS, + [`Warning (${NOTIFICATION_KIND.WARNING})`]: NOTIFICATION_KIND.WARNING, + [`Warning Alt (${NOTIFICATION_KIND.WARNING_ALT})`]: + NOTIFICATION_KIND.WARNING_ALT, +}; + +export default kinds; diff --git a/packages/web-components/src/components/notification/toast-notification.scss b/packages/web-components/src/components/notification/toast-notification.scss new file mode 100644 index 000000000000..4dc0086d986e --- /dev/null +++ b/packages/web-components/src/components/notification/toast-notification.scss @@ -0,0 +1,109 @@ +// +// Copyright IBM Corp. 2019, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/colors' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/components/notification/mixins' as *; +@use '@carbon/styles/scss/components/notification/index' as *; +@use '@carbon/styles/scss/components/button'; +@use '@carbon/styles/scss/layout' as *; + +// https://github.com/carbon-design-system/carbon/issues/11408 +@include toast-notification; + +:host(#{$prefix}-toast-notification) { + @extend .#{$prefix}--toast-notification; + @include emit-layout-tokens(); + + display: none; + outline: none; +} + +:host(#{$prefix}-toast-notification[open]) { + display: flex; +} + +:host(#{$prefix}-toast-notification[hide-close-button]) + .#{$prefix}--toast-notification__close-button { + display: none; +} + +:host(#{$prefix}-toast-notification[kind='success']) { + @extend .#{$prefix}--toast-notification--success; +} + +:host(#{$prefix}-toast-notification[kind='success'][low-contrast]) { + @extend .#{$prefix}--toast-notification--low-contrast, + .#{$prefix}--toast-notification--success; + + @include notification--experimental( + $support-success, + $notification-background-success + ); +} + +:host(#{$prefix}-toast-notification[kind='info']) { + @extend .#{$prefix}--toast-notification--info; +} + +:host(#{$prefix}-toast-notification[kind='info-square']) { + @extend .#{$prefix}--toast-notification--info-square; +} + +:host(#{$prefix}-toast-notification[kind='info'][low-contrast]), +:host(#{$prefix}-toast-notification[kind='info-square'][low-contrast]) { + @extend .#{$prefix}--toast-notification--low-contrast, + .#{$prefix}--toast-notification--info; + + @include notification--experimental( + $support-info, + $notification-background-info + ); +} + +:host(#{$prefix}-toast-notification[kind='warning']) { + @extend .#{$prefix}--toast-notification--warning; +} + +:host(#{$prefix}-toast-notification[kind='warning-alt']) { + @extend .#{$prefix}--toast-notification--warning-alt; + + /* TODO: Remove this once the following issue with icon fill is resolved: + ** https://github.com/carbon-design-system/carbon/issues/13616 + */ + .#{$prefix}--toast-notification__icon path[data-icon-path='inner-path'] { + fill: $black-100; + } +} + +:host(#{$prefix}-toast-notification[kind='warning'][low-contrast]), +:host(#{$prefix}-toast-notification[kind='warning-alt'][low-contrast]) { + @extend .#{$prefix}--toast-notification--low-contrast, + .#{$prefix}--toast-notification--warning; + + @include notification--experimental( + $support-warning, + $notification-background-warning + ); +} + +:host(#{$prefix}-toast-notification[kind='error']) { + @extend .#{$prefix}--toast-notification--error; +} + +:host(#{$prefix}-toast-notification[kind='error'][low-contrast]) { + @extend .#{$prefix}--toast-notification--low-contrast, + .#{$prefix}--toast-notification--error; + + @include notification--experimental( + $support-error, + $notification-background-error + ); +} diff --git a/packages/web-components/src/components/notification/toast-notification.stories.ts b/packages/web-components/src/components/notification/toast-notification.stories.ts new file mode 100644 index 000000000000..7af4034643b7 --- /dev/null +++ b/packages/web-components/src/components/notification/toast-notification.stories.ts @@ -0,0 +1,149 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { NOTIFICATION_KIND } from './inline-notification'; +import './toast-notification'; +import storyDocs from './notification.mdx'; +import { prefix } from '../../globals/settings'; +import kinds from './stories/helper'; + +const noop = () => {}; + +const args = { + caption: '00:00:00 AM', + hideCloseButton: false, + kind: NOTIFICATION_KIND.INFO, + lowContrast: false, + role: 'status', + statusIconDescription: 'notification', + subtitle: 'Subtitle text goes here', + timeout: '0', + title: 'Notification title', +}; + +const argTypes = { + caption: { + control: 'text', + description: 'Specify the caption.', + }, + hideCloseButton: { + control: 'boolean', + description: 'Specify the close button should be disabled, or not.', + }, + kind: { + control: 'select', + description: 'Specify what state the notification represents.', + options: kinds, + }, + lowContrast: { + control: 'boolean', + description: + 'Specify whether you are using the low contrast variant of the Toast Notification.', + }, + role: { + control: 'select', + description: + 'By default, this value is "status". You can also provide an alternate role if it makes sense from the accessibility-side.', + options: { alert: 'alert', log: 'log', status: 'status' }, + }, + statusIconDescription: { + control: 'text', + description: + 'Provide a description for "status" icon that can be read by screen readers.', + }, + subtitle: { + control: 'text', + description: 'Specify the subtitle.', + }, + timeout: { + control: 'text', + description: + 'Specify an optional duration the notification should be closed in.', + }, + title: { + control: 'text', + description: 'Specify the title.', + }, + onBeforeClose: { + action: `${prefix}-notification-beingclosed`, + }, + onClose: { + action: `${prefix}-notification-closed`, + }, +}; + +export const Default = { + render: () => { + return html` + + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + kind, + title, + subtitle, + caption, + hideCloseButton, + statusIconDescription, + lowContrast, + timeout, + role, + disableClose, + onBeforeClose = noop, + onClose = noop, + } = args ?? {}; + const handleBeforeClose = (event: CustomEvent) => { + onBeforeClose(event); + if (disableClose) { + event.preventDefault(); + } + }; + return html` + + + `; + }, +}; + +const meta = { + title: 'Components/Notifications/Toast', + parameters: { + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/notification/toast-notification.ts b/packages/web-components/src/components/notification/toast-notification.ts new file mode 100644 index 000000000000..35e7f8d6d545 --- /dev/null +++ b/packages/web-components/src/components/notification/toast-notification.ts @@ -0,0 +1,71 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { NOTIFICATION_TYPE } from './defs'; +import CDSInlineNotification from './inline-notification'; +import styles from './toast-notification.scss?lit'; + +/** + * Toast notification. + * + * @element cds-toast-notification + * @slot subtitle - The subtitle. + * @slot title - The title. + * @fires cds-notification-beingclosed + * The custom event fired before this notification is being closed upon a user gesture. + * Cancellation of this event stops the user-initiated action of closing this notification. + * @fires cds-notification-closed - The custom event fired after this notification is closed upon a user gesture. + */ +@customElement(`${prefix}-toast-notification`) +class CDSToastNotification extends CDSInlineNotification { + protected _type = NOTIFICATION_TYPE.TOAST; + + protected _renderText() { + const { caption, subtitle, title, _type: type } = this; + return html` +
    +
    + ${title} +
    +
    + ${subtitle} +
    +
    + ${caption} +
    + +
    + `; + } + + /** + * Specify the caption + */ + @property() + caption = ''; + + render() { + const { _type: type } = this; + return html` + ${this._renderIcon()} +
    + ${this._renderText()} +
    + ${this._renderButton()} + `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSToastNotification; diff --git a/packages/web-components/src/components/number-input/defs.ts b/packages/web-components/src/components/number-input/defs.ts new file mode 100644 index 000000000000..eee7821c9946 --- /dev/null +++ b/packages/web-components/src/components/number-input/defs.ts @@ -0,0 +1,18 @@ +/** + * @license + * + * Copyright IBM Corp. 2020 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +export { FORM_ELEMENT_COLOR_SCHEME as NUMBER_INPUT_COLOR_SCHEME } from '../../globals/shared-enums'; + +/** + * Works in conjunction with VALIDATION_STATUS + */ +export enum NUMBER_INPUT_VALIDATION_STATUS { + EXCEEDED_MAXIMUM = 'exceeded_maximum', + EXCEEDED_MINIMUM = 'exceeded_minimum', +} diff --git a/packages/web-components/src/components/number-input/docs/overview.mdx b/packages/web-components/src/components/number-input/docs/overview.mdx new file mode 100644 index 000000000000..1c56ba5a5b39 --- /dev/null +++ b/packages/web-components/src/components/number-input/docs/overview.mdx @@ -0,0 +1,20 @@ +## Live demo + + diff --git a/packages/web-components/src/components/number-input/index.ts b/packages/web-components/src/components/number-input/index.ts new file mode 100644 index 000000000000..5d4ce515bf57 --- /dev/null +++ b/packages/web-components/src/components/number-input/index.ts @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './number-input'; +import './number-input-skeleton'; diff --git a/packages/web-components/src/components/number-input/number-input-skeleton.ts b/packages/web-components/src/components/number-input/number-input-skeleton.ts new file mode 100644 index 000000000000..4c94f0f3c224 --- /dev/null +++ b/packages/web-components/src/components/number-input/number-input-skeleton.ts @@ -0,0 +1,39 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './number-input.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Skeleton of number input. + */ +@customElement(`${prefix}-number-input-skeleton`) +class CDSNumberInputSkeleton extends LitElement { + /** + * `true` if the label should be hidden. Corresponds to the attribute with the same name. + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-label' }) + hideLabel = false; + + render() { + const { hideLabel } = this; + return html` + ${!hideLabel && + html` `} +
    + `; + } + + static styles = styles; +} + +export default CDSNumberInputSkeleton; diff --git a/packages/web-components/src/components/number-input/number-input.mdx b/packages/web-components/src/components/number-input/number-input.mdx new file mode 100644 index 000000000000..f9eeb8d82cb7 --- /dev/null +++ b/packages/web-components/src/components/number-input/number-input.mdx @@ -0,0 +1,78 @@ +import { ArgTypes, Meta, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as NumberInputStories from './number-input.stories'; + + + +# Number input + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/number-input) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/number-input) + +Number inputs are similar to text inputs, but contain controls used to increase +or decrease an incremental value. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/number-input/index.js'; +``` + +{`${cdnJs({ components: ['number-input'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + +``` + +## Form item + +If the input is part of a form, make sure to import and wrap the input with +`` + +```javascript +import '@carbon/web-components/es/components/form/index.js'; +``` + +```html + + + + +``` + +## Skeleton + +For the skeleton variation, utilize ``. + +```html + +``` + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `invalid` attribute). + + diff --git a/packages/web-components/src/components/number-input/number-input.scss b/packages/web-components/src/components/number-input/number-input.scss new file mode 100644 index 000000000000..8cafafcf3bfa --- /dev/null +++ b/packages/web-components/src/components/number-input/number-input.scss @@ -0,0 +1,63 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/utilities'; +@use '@carbon/styles/scss/components/form'; +@use '@carbon/styles/scss/components/number-input/index'; + +:host(#{$prefix}-number-input), +:host(#{$prefix}-number-input-skeleton) { + // the base text-input class has a 100% so we need to propagate it up to the host element + inline-size: 100%; + outline: none; + + .#{$prefix}--form-requirement[hidden] { + display: none; + } +} + +.#{$prefix}--number__invalid + ~ .#{$prefix}--number__controls + .#{$prefix}--number__rule-divider:first-of-type, +.#{$prefix}--number + .#{$prefix}--number__invalid + ~ input[type='number']:disabled + + .#{$prefix}--number__controls + .#{$prefix}--number__rule-divider:first-of-type { + background-color: $border-subtle; +} + +.#{$prefix}--number--readonly { + .#{$prefix}--number__controls { + .#{$prefix}--number__control-btn { + border-block-end: 0; + } + } +} + +:host(#{$prefix}-number-input) { + ::slotted(#{$prefix}-slug) { + position: absolute; + inset-block-start: 50%; + inset-inline-end: 5.5rem; + } + ::slotted(#{$prefix}-slug:not([revert-active])) { + transform: translateY(-50%); + } +} +:host(#{$prefix}-number-input) .#{$prefix}--number[data-invalid], +:host(#{$prefix}-number-input[warn]), +:host(#{$prefix}-number-input[invalid]) { + ::slotted(#{$prefix}-slug) { + inset-inline-end: to-rem(120px); + } +} diff --git a/packages/web-components/src/components/number-input/number-input.stories.ts b/packages/web-components/src/components/number-input/number-input.stories.ts new file mode 100644 index 000000000000..c1a8f116f3ce --- /dev/null +++ b/packages/web-components/src/components/number-input/number-input.stories.ts @@ -0,0 +1,216 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { INPUT_SIZE } from '../text-input/text-input'; +import './number-input'; +import './number-input-skeleton'; +import '../form/form-item'; + +const sizes = { + [`Small size (${INPUT_SIZE.SMALL})`]: INPUT_SIZE.SMALL, + [`Medium size (${INPUT_SIZE.MEDIUM})`]: INPUT_SIZE.MEDIUM, + [`Large size (${INPUT_SIZE.LARGE})`]: INPUT_SIZE.LARGE, +}; + +const args = { + allowEmpty: false, + decrementButtonDescription: 'decrease number input', + incrementButtonDescription: 'increase number input', + disabled: false, + helperText: 'Optional helper text', + hideLabel: false, + hideSteppers: false, + invalid: false, + invalidText: 'Number is not valid', + label: 'number-input label', + readOnly: false, + value: 50, + warn: false, + warnText: 'Warning text', + min: 0, + max: 100, + step: 1, + size: INPUT_SIZE.MEDIUM, +}; + +const argTypes = { + allowEmpty: { + control: 'boolean', + description: 'true to allow empty string.', + }, + decrementButtonDescription: { + control: 'text', + description: + 'Decrement button assistive description (decrement-button-assistive-text)', + }, + incrementButtonDescription: { + control: 'text', + description: + 'Increment button assistive description (increment-button-assistive-text)', + }, + disabled: { + control: 'boolean', + description: 'Specify if the control should be disabled, or not.', + }, + helperText: { + control: 'text', + description: + 'Provide text that is used alongside the control label for additional help.', + }, + hideLabel: { + control: 'boolean', + description: + 'Specify whether you want the underlying label to be visually hidden.', + }, + hideSteppers: { + control: 'boolean', + description: 'Specify whether you want the steppers to be hidden.', + }, + invalid: { + control: 'boolean', + description: 'Specify if the currently value is invalid.', + }, + invalidText: { + control: 'text', + description: 'Message which is displayed if the value is invalid.', + }, + label: { + control: 'text', + description: + 'Generic label that will be used as the textual representation of what this field is for.', + }, + readOnly: { + control: 'boolean', + description: 'Specify if the component should be read-only.', + }, + value: { + control: 'number', + description: 'Specify the value of the input.', + }, + warn: { + control: 'boolean', + description: 'Specify whether the control is currently in warning state.', + }, + warnText: { + control: 'text', + description: + 'Provide the text that is displayed when the control is in warning state.', + }, + min: { + control: 'number', + description: 'The minimum value.', + }, + max: { + control: 'number', + description: 'The maximum value.', + }, + step: { + control: 'number', + description: + 'Specify how much the values should increase/decrease upon clicking on up/down button.', + }, + size: { + control: 'select', + description: 'Specify the size of the Number Input.', + options: sizes, + }, + onInput: { + action: 'input', + }, +}; + +export const Default = { + render: () => { + return html` + + + + + `; + }, +}; + +export const Skeleton = { + parameters: { + percy: { + skip: true, + }, + }, + render: () => html` `, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + allowEmpty, + decrementButtonDescription, + incrementButtonDescription, + disabled, + helperText, + hideLabel, + hideSteppers, + invalid, + invalidText, + label, + readOnly, + warn, + warnText, + value, + min, + max, + size, + step, + onInput, + } = args ?? {}; + return html` + + + + + `; + }, +}; + +export default { + title: 'Components/Number Input', +}; diff --git a/packages/web-components/src/components/number-input/number-input.ts b/packages/web-components/src/components/number-input/number-input.ts new file mode 100644 index 000000000000..cef3909bc0ad --- /dev/null +++ b/packages/web-components/src/components/number-input/number-input.ts @@ -0,0 +1,361 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import { prefix } from '../../globals/settings'; +import WarningFilled16 from '@carbon/icons/lib/warning--filled/16'; +import WarningAltFilled16 from '@carbon/icons/lib/warning--alt--filled/16'; +import Add16 from '@carbon/icons/lib/add/16'; +import Subtract16 from '@carbon/icons/lib/subtract/16'; +import ifNonEmpty from '../../globals/directives/if-non-empty'; +import { NUMBER_INPUT_VALIDATION_STATUS } from './defs'; +import styles from './number-input.scss?lit'; +import CDSTextInput, { INPUT_SIZE } from '../text-input/text-input'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { NUMBER_INPUT_VALIDATION_STATUS }; + +/** + * Number input. + * + * @element cds-number-input + * @fires cds-number-input + * The name of the custom event fired after the value is changed upon a user gesture. + * @slot helper-text - The helper text. + * @slot label-text - The label text. + * @slot validity-message - The validity message. If present and non-empty, this input shows the UI of its invalid state. + */ +@customElement(`${prefix}-number-input`) +class CDSNumberInput extends CDSTextInput { + /** + * Handles `input` event on the `` in the shadow DOM. + */ + protected _handleInput(event: Event) { + const { target } = event; + const { value } = target as HTMLInputElement; + this.dispatchEvent( + new CustomEvent((this.constructor as typeof CDSNumberInput).eventInput, { + bubbles: true, + composed: true, + cancelable: false, + detail: { + value, + }, + }) + ); + super._handleInput(event); + } + + /** + * Handles `click` event on the up button in the shadow DOM. + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected _handleUserInitiatedStepDown(_: Event) { + const { _input: input } = this; + this.stepDown(); + this.dispatchEvent( + new CustomEvent((this.constructor as typeof CDSNumberInput).eventInput, { + bubbles: true, + composed: true, + cancelable: false, + detail: { + value: input.value, + }, + }) + ); + } + + /** + * Handles `click` event on the down button in the shadow DOM. + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected _handleUserInitiatedStepUp(_: Event) { + const { _input: input } = this; + this.stepUp(); + this.dispatchEvent( + new CustomEvent((this.constructor as typeof CDSNumberInput).eventInput, { + bubbles: true, + composed: true, + cancelable: false, + detail: { + value: input.value, + }, + }) + ); + } + + /** + * The underlying input element + */ + @query('input') + protected _input!: HTMLInputElement; + + _getInputValidity() { + if (this.invalid) { + return false; + } + if ( + this._input?.valueAsNumber > Number(this.max) || + this._input?.valueAsNumber < Number(this.min) + ) { + return false; + } + if (this.value === '') { + return this.allowEmpty; + } + return true; + } + + protected _min = ''; + + protected _max = ''; + + protected _step = '1'; + + /** + * The minimum value allowed in the input + */ + @property({ reflect: true }) + get min() { + return this._min.toString(); + } + + set min(value) { + const oldValue = this.min; + this._min = value; + this.requestUpdate('min', oldValue); + } + + /** + * The maximum value allowed in the input + */ + @property({ reflect: true }) + get max() { + return this._max.toString(); + } + + set max(value) { + const oldValue = this.max; + this._max = value; + this.requestUpdate('max', oldValue); + } + + /** + * The amount the value should increase or decrease by + */ + @property({ reflect: true }) + get step() { + return this._step.toString(); + } + + set step(value) { + const oldValue = this.step; + this._step = value; + this.requestUpdate('step', oldValue); + } + + /** + * Aria text for the button that increments the value + */ + @property({ attribute: 'increment-button-assistive-text' }) + incrementButtonAssistiveText = 'increase number input'; + + /** + * Aria text for the button that decrements the value + */ + @property({ attribute: 'decrement-button-assistive-text' }) + decrementButtonAssistiveText = 'decrease number input'; + + /** + * Specify whether you want the steppers to be hidden + */ + @property({ type: Boolean, attribute: 'hide-steppers', reflect: true }) + hideSteppers = false; + + /** + * `true` to allow empty string. + */ + @property({ type: Boolean, attribute: 'allow-empty', reflect: true }) + allowEmpty = false; + + /** + * The input box size. + */ + @property({ reflect: true }) + size = INPUT_SIZE.MEDIUM; + + /** + * Handles incrementing the value in the input + */ + stepUp() { + this._input.stepUp(); + } + + /** + * Handles decrementing the value in the input + */ + stepDown() { + this._input.stepDown(); + } + + render() { + const { + _handleInput: handleInput, + _handleUserInitiatedStepDown: handleUserInitiatedStepDown, + _handleUserInitiatedStepUp: handleUserInitiatedStepUp, + } = this; + + const isValid = this._getInputValidity(); + + const invalidIcon = WarningFilled16({ + class: `${prefix}--number__invalid`, + }); + + const warnIcon = WarningAltFilled16({ + class: `${prefix}--number__invalid ${prefix}--number__invalid--warning`, + }); + + const normalizedProps = { + disabled: !this.readonly && this.disabled, + invalid: !this.readonly && !isValid, + warn: !this.readonly && isValid && this.warn, + 'slot-name': '', + 'slot-text': '', + icon: null, + }; + + const wrapperClasses = classMap({ + [`${prefix}--number`]: true, + [`${prefix}--number--${this.size}`]: this.size, + [`${prefix}--number--nosteppers`]: this.hideSteppers, + [`${prefix}--number--readonly`]: this.readonly, + }); + + const inputWrapperClasses = classMap({ + [`${prefix}--number__input-wrapper`]: true, + [`${prefix}--number__input-wrapper--warning`]: normalizedProps.warn, + [`${prefix}--number__input-wrapper--slug`]: this._hasSlug, + }); + + const labelClasses = classMap({ + [`${prefix}--label`]: true, + [`${prefix}--label--disabled`]: normalizedProps.disabled, + [`${prefix}--visually-hidden`]: this.hideLabel, + }); + + const helperTextClasses = classMap({ + [`${prefix}--form__helper-text`]: true, + [`${prefix}--form__helper-text--disabled`]: normalizedProps.disabled, + }); + + const incrementButton = html` + +
    + `; + const decrementButton = html` + +
    + `; + + const input = html` + + `; + + if (normalizedProps.invalid) { + normalizedProps.icon = invalidIcon; + normalizedProps['slot-name'] = 'invalid-text'; + normalizedProps['slot-text'] = this.invalidText; + } else if (normalizedProps.warn) { + normalizedProps.icon = warnIcon; + normalizedProps['slot-name'] = 'warn-text'; + normalizedProps['slot-text'] = this.warnText; + } + + return html` +
    + +
    + ${normalizedProps.icon} ${input} + +
    + ${!this.hideSteppers + ? html`${decrementButton} ${incrementButton}` + : null} +
    +
    +
    + ${this.helperText} +
    +
    + + ${normalizedProps['slot-text']} + +
    +
    + `; + } + + /** + * The name of the custom event fired after the value is changed upon a user gesture. + */ + static get eventInput() { + return `${prefix}-number-input`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSNumberInput; diff --git a/packages/web-components/src/components/overflow-menu/defs.ts b/packages/web-components/src/components/overflow-menu/defs.ts new file mode 100644 index 000000000000..433495a9b601 --- /dev/null +++ b/packages/web-components/src/components/overflow-menu/defs.ts @@ -0,0 +1,33 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Overflow menu size. + */ +export enum OVERFLOW_MENU_SIZE { + /** + * Small size. + */ + SMALL = 'sm', + + /** + * Medium size. + */ + MEDIUM = 'md', + + /** + * Large size. + */ + LARGE = 'lg', +} + +export const NAVIGATION_DIRECTION = { + ArrowDown: 1, + ArrowUp: -1, +}; diff --git a/packages/web-components/src/components/overflow-menu/docs/overview.mdx b/packages/web-components/src/components/overflow-menu/docs/overview.mdx new file mode 100644 index 000000000000..b57db26e0560 --- /dev/null +++ b/packages/web-components/src/components/overflow-menu/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/overflow-menu/index.ts b/packages/web-components/src/components/overflow-menu/index.ts new file mode 100644 index 000000000000..e46d3a56e6b4 --- /dev/null +++ b/packages/web-components/src/components/overflow-menu/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * + * Copyright IBM Corp. 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './overflow-menu'; +import './overflow-menu-body'; +import './overflow-menu-item'; diff --git a/packages/web-components/src/components/overflow-menu/overflow-menu-body.ts b/packages/web-components/src/components/overflow-menu/overflow-menu-body.ts new file mode 100644 index 000000000000..0ba8ded7b23e --- /dev/null +++ b/packages/web-components/src/components/overflow-menu/overflow-menu-body.ts @@ -0,0 +1,170 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import CDSFloatingMenu, { + FLOATING_MENU_DIRECTION, +} from '../floating-menu/floating-menu'; +import { NAVIGATION_DIRECTION, OVERFLOW_MENU_SIZE } from './defs'; +import CDSOverflowMenuItem from './overflow-menu-item'; +import HostListener from '../../globals/decorators/host-listener'; +import { indexOf } from '../../globals/internal/collection-helpers'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import styles from './overflow-menu.scss?lit'; + +/** + * @param index The index + * @param length The length of the array. + * @returns The new index, adjusting overflow/underflow. + */ +const capIndex = (index: number, length: number) => { + if (index < 0) { + return length - 1; + } + if (index >= length) { + return 0; + } + return index; +}; + +/** + * Overflow menu body. + * + * @element cds-overflow-menu-body + */ +@customElement(`${prefix}-overflow-menu-body`) +class CDSOverflowMenuBody extends CDSFloatingMenu { + /** + * The menu direction. + */ + @property() + direction = FLOATING_MENU_DIRECTION.BOTTOM; + + /** + * How the menu is aligned to the trigger button. + */ + @property({ type: Boolean, reflect: true }) + flipped = false; + + /** + * `true` if the menu should be open. + * + * @private + */ + @property({ type: Boolean, reflect: true }) + open = false; + + selected: CDSOverflowMenuItem | null = null; + + /** + * The overflow menu size. + */ + @property({ reflect: true }) + size = OVERFLOW_MENU_SIZE.MEDIUM; + + /** + * @param currentItem The currently selected item. + * @param direction The navigation direction. + * @returns The item to be selected. + */ + protected _getNextItem(currentItem: CDSOverflowMenuItem, direction: number) { + const { selectorItemEnabled } = this + .constructor as typeof CDSOverflowMenuBody; + const menuItems = this.querySelectorAll(selectorItemEnabled); + const currentIndex = indexOf(menuItems, currentItem); + const nextIndex = capIndex(currentIndex + direction, menuItems.length); + return nextIndex === currentIndex ? null : menuItems[nextIndex]; + } + + /** + * Navigates through overflow menu items. + * + * @param direction `-1` to navigate backward, `1` to navigate forward. + */ + protected _navigate(direction: number) { + if (this.selected) { + const nextItem = this._getNextItem(this.selected, direction); + (nextItem as HTMLElement)?.focus(); + } + } + + /** + * Handles `keydown` event on the menu body. + */ + @HostListener('keydown') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + protected _handleKeydown = async (event: KeyboardEvent) => { + const { key } = event; + if (this.open) { + /** + * sets this.selected to focused menu item. the menu item is focused + * automatically due to FocusMixin + */ + if (this.contains(document.activeElement)) { + this.selected = document.activeElement as CDSOverflowMenuItem; + } + + if (key in NAVIGATION_DIRECTION) { + this._navigate(NAVIGATION_DIRECTION[key]); + } + + if (key === 'Escape') { + this.open = false; + } + } + }; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'menu'); + } + if (!this.hasAttribute('tabindex')) { + // TODO: Should we use a property? + this.setAttribute('tabindex', '-1'); + } + super.connectedCallback(); + } + + updated(changedProperties) { + if (changedProperties.has('size')) { + const { selectorMenuItem } = this + .constructor as typeof CDSOverflowMenuBody; + const menuItems = this.querySelectorAll(selectorMenuItem); + menuItems.forEach((item) => { + item.setAttribute('size', this.size); + }); + } + + super.updated(changedProperties); + } + + render() { + return html` `; + } + + /** + * A selector that will return menu items. + */ + static get selectorMenuItem() { + return `${prefix}-overflow-menu-item`; + } + + /** + * A selector that will return enabled menu items. + */ + static get selectorItemEnabled() { + return `${prefix}-overflow-menu-item:not([disabled])`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSOverflowMenuBody; diff --git a/packages/web-components/src/components/overflow-menu/overflow-menu-item.ts b/packages/web-components/src/components/overflow-menu/overflow-menu-item.ts new file mode 100644 index 000000000000..58d8474897ea --- /dev/null +++ b/packages/web-components/src/components/overflow-menu/overflow-menu-item.ts @@ -0,0 +1,94 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import FocusMixin from '../../globals/mixins/focus'; +import { OVERFLOW_MENU_SIZE } from './defs'; +import styles from './overflow-menu.scss?lit'; + +/** + * Overflow menu item. + * + * @element cds-overflow-menu-item + */ +@customElement(`${prefix}-overflow-menu-item`) +class CDSOverflowMenuItem extends FocusMixin(LitElement) { + /** + * `true` if the action is danger. + */ + @property({ type: Boolean, reflect: true }) + danger = false; + + /** + * `true` if the overflow menu item should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * `true` if the item has a divider + */ + @property({ type: Boolean, reflect: true }) + divider = false; + + /** + * The link href of the overflow menu item. + */ + @property() + href = ''; + + /** + * The size of the overflow menu item. + */ + @property({ reflect: true }) + size = OVERFLOW_MENU_SIZE.MEDIUM; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'menuitem'); + } + super.connectedCallback(); + } + + render() { + return this.href + ? html` + +
    + +
    +
    + ` + : html` + + `; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSOverflowMenuItem; diff --git a/packages/web-components/src/components/overflow-menu/overflow-menu.mdx b/packages/web-components/src/components/overflow-menu/overflow-menu.mdx new file mode 100644 index 000000000000..550eda73c004 --- /dev/null +++ b/packages/web-components/src/components/overflow-menu/overflow-menu.mdx @@ -0,0 +1,68 @@ +import { ArgTypes, Meta, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as OverflowMenuStories from './overflow-menu.stories'; + + + +# Overflow menu + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/overflow-menu) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/overflow-menu) + +Overflow menu is used when additional options are available to the user and +there is a space constraint. Create overflow menu item components for each +option on the menu. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/overflow-menu/index.js'; +import OverflowMenuVertical16 from '@carbon/icons/lib/overflow-menu--vertical/16'; +``` + +{`${cdnJs({ components: ['overflow-menu'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + ${OverflowMenuVertical16({ class: `${prefix}--overflow-menu__icon`, slot: + 'icon', })} + Options + + Option 1 + Option 2 + Option 3 + Option 4 + Option 5 + + +``` + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `open` attribute). + + + +## `` attributes and properties + + + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `disabled` attribute). + + diff --git a/packages/web-components/src/components/overflow-menu/overflow-menu.scss b/packages/web-components/src/components/overflow-menu/overflow-menu.scss new file mode 100644 index 000000000000..ff206e994292 --- /dev/null +++ b/packages/web-components/src/components/overflow-menu/overflow-menu.scss @@ -0,0 +1,112 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/components/overflow-menu/overflow-menu' as *; + +// https://github.com/carbon-design-system/carbon/issues/11408 +@include overflow-menu; + +:host(#{$prefix}-overflow-menu), +:host(#{$prefix}-breadcrumb-overflow-menu) { + @extend .#{$prefix}--overflow-menu; + + ::slotted(.#{$prefix}--overflow-menu__icon) { + @extend .#{$prefix}--overflow-menu__icon; + } +} + +:host(#{$prefix}-overflow-menu[size='sm']), +:host(#{$prefix}-breadcrumb-overflow-menu[size='sm']) { + @extend .#{$prefix}--overflow-menu--sm; +} + +:host(#{$prefix}-overflow-menu[size='lg']), +:host(#{$prefix}-breadcrumb-overflow-menu[size='lg']) { + @extend .#{$prefix}--overflow-menu--lg; +} + +:host(#{$prefix}-overflow-menu[disabled]), +:host(#{$prefix}-breadcrumb-overflow-menu[disabled]) { + cursor: not-allowed; + + svg { + cursor: not-allowed; + fill: $icon-disabled; + } +} + +:host(#{$prefix}-overflow-menu[disabled]:hover), +:host(#{$prefix}-breadcrumb-overflow-menu[disabled]:hover) { + background-color: transparent; +} + +:host(#{$prefix}-overflow-menu[open]), +:host(#{$prefix}-breadcrumb-overflow-menu[open]) { + background-color: $layer-01; + box-shadow: 0 $spacing-01 6px 0 rgba(0, 0, 0, 0.3); + transition: none; + + :hover { + background-color: $layer; + } +} + +:host(#{$prefix}-overflow-menu-body) { + @extend .#{$prefix}--overflow-menu-options; +} + +:host(#{$prefix}-overflow-menu-body[direction='top']) { + margin-block: 0 $spacing-02; +} + +:host(#{$prefix}-overflow-menu-body[open]) { + @extend .#{$prefix}--overflow-menu-options--open; +} + +:host(#{$prefix}-overflow-menu-body[size='sm']) { + @extend .#{$prefix}--overflow-menu-options--sm; +} + +:host(#{$prefix}-overflow-menu-body[size='lg']) { + @extend .#{$prefix}--overflow-menu-options--lg; +} + +:host(#{$prefix}-overflow-menu-item) { + @extend .#{$prefix}--overflow-menu-options__option; + + outline: none; + + button:hover { + background-color: $layer-hover; + } +} + +:host(#{$prefix}-overflow-menu-item[size='sm']) { + block-size: $spacing-07; +} + +:host(#{$prefix}-overflow-menu-item[size='lg']) { + block-size: $spacing-09; +} + +:host(#{$prefix}-overflow-menu-item[danger]) { + @extend .#{$prefix}--overflow-menu-options__option--danger; +} + +:host(#{$prefix}-overflow-menu-item[disabled]) { + @extend .#{$prefix}--overflow-menu-options__option--disabled; +} + +:host(#{$prefix}-overflow-menu-item[divider]) { + @extend .#{$prefix}--overflow-menu--divider; +} diff --git a/packages/web-components/src/components/overflow-menu/overflow-menu.stories.ts b/packages/web-components/src/components/overflow-menu/overflow-menu.stories.ts new file mode 100644 index 000000000000..46f60fd2155e --- /dev/null +++ b/packages/web-components/src/components/overflow-menu/overflow-menu.stories.ts @@ -0,0 +1,140 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { OVERFLOW_MENU_SIZE } from './overflow-menu'; +import './overflow-menu-body'; +import './overflow-menu-item'; +import { prefix } from '../../globals/settings'; +import OverflowMenuVertical16 from '@carbon/icons/lib/overflow-menu--vertical/16'; +import Filter16 from '@carbon/icons/lib/filter/16'; + +const sizes = { + [`Small size (${OVERFLOW_MENU_SIZE.SMALL})`]: OVERFLOW_MENU_SIZE.SMALL, + [`Medium size (default) (${OVERFLOW_MENU_SIZE.MEDIUM})`]: + OVERFLOW_MENU_SIZE.MEDIUM, + [`Lg size (${OVERFLOW_MENU_SIZE.LARGE})`]: OVERFLOW_MENU_SIZE.LARGE, +}; + +const args = { + flipped: false, + iconDescription: 'Options', + open: false, + index: 1, + size: OVERFLOW_MENU_SIZE.MEDIUM, +}; + +const argTypes = { + flipped: { + control: 'boolean', + description: 'true if the menu alignment should be flipped.', + }, + iconDescription: { + control: 'text', + description: 'The icon description.', + }, + open: { + control: 'boolean', + description: 'true if the menu should be open.\n', + }, + index: { + control: 'number', + description: 'The index for the item which should be focused in the menu.', + }, + size: { + control: 'select', + description: + 'Specify the size of the OverflowMenu. Currently supports either sm, md (default) or lg
    as an option.', + options: sizes, + }, +}; + +export const Default = { + render: () => { + return html` + + ${OverflowMenuVertical16({ + class: `${prefix}--overflow-menu__icon`, + slot: 'icon', + })} + Options + + Stop app + Restart app + Rename app + Clone and move app + Edit routes and access + Delete app + + + `; + }, +}; + +export const RenderCustomIcon = { + render: () => { + return html` + + ${Filter16({ + class: `${prefix}--overflow-menu__icon`, + slot: 'icon', + })} + Options + + Filter A + Filter B + + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { flipped, iconDescription, open, index, size } = args ?? {}; + return html` + + ${OverflowMenuVertical16({ + class: `${prefix}--overflow-menu__icon`, + slot: 'icon', + })} + ${iconDescription} + + Stop app + Restart app + Rename app + Clone and move app + Edit routes and access + Delete app + + + `; + }, +}; + +const meta = { + title: 'Components/Overflow Menu', +}; + +export default meta; diff --git a/packages/web-components/src/components/overflow-menu/overflow-menu.ts b/packages/web-components/src/components/overflow-menu/overflow-menu.ts new file mode 100644 index 000000000000..fca55a2ef531 --- /dev/null +++ b/packages/web-components/src/components/overflow-menu/overflow-menu.ts @@ -0,0 +1,207 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import HostListener from '../../globals/decorators/host-listener'; +import FocusMixin from '../../globals/mixins/focus'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import { find } from '../../globals/internal/collection-helpers'; +import CDSFloatingMenuTrigger from '../floating-menu/floating-menu-trigger'; +import { OVERFLOW_MENU_SIZE } from './defs'; +import CDSOverflowMenuBody from './overflow-menu-body'; +import styles from './overflow-menu.scss?lit'; +import CDSIconButton from '../icon-button/icon-button'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { OVERFLOW_MENU_SIZE }; + +/** + * Overflow menu. + * + * @element cds-overflow-menu + * @slot icon - The icon for the trigger button. + */ +@customElement(`${prefix}-overflow-menu`) +class CDSOverflowMenu + extends HostListenerMixin(FocusMixin(CDSIconButton)) + implements CDSFloatingMenuTrigger +{ + /** + * The menu body. + */ + private _menuBody: CDSOverflowMenuBody | null = null; + + /** + * Handles user-initiated toggling of the menu. + */ + private async _handleUserInitiatedToggle() { + this.open = !this.open; + const { index, open, updateComplete } = this; + if (open) { + await updateComplete; + const { _menuBody: menuBody } = this; + const menuItem = menuBody?.querySelector( + `${prefix}-overflow-menu-item:nth-of-type(${index})` + ) as HTMLElement; + menuItem?.focus(); + } + } + + /** + * Handles `click` event on the trigger button. + */ + @HostListener('click') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleClickTrigger = async () => { + this._handleUserInitiatedToggle(); + }; + + /** + * Handles `keydown` event on the trigger button. + */ + @HostListener('keydown') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleKeydownTrigger = async (event) => { + if (event.key === ' ' || event.key === 'Enter') { + this._handleUserInitiatedToggle(); + event.preventDefault(); + } + }; + + /** + * `true` if this tooltip is in a data table row + */ + @property({ type: Boolean, reflect: true, attribute: 'data-table' }) + dataTable = false; + + /** + * `true` if this overflow menu should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * `true` if this overflow menu body should be flipped. + */ + @property({ type: Boolean, reflect: true }) + flipped = false; + + /** + * `true` if the dropdown should be open. + */ + @property({ type: Boolean, reflect: true }) + open = false; + + /** + * Index (starting at 1) of overflow menu item to focus on open. + */ + @property() + index = 1; + + /** + * Overflow menu size. + */ + @property({ reflect: true }) + size = OVERFLOW_MENU_SIZE.MEDIUM; + + /** + * `true` if this menu is a toolbar action + */ + @property({ type: Boolean, attribute: 'toolbar-action', reflect: true }) + toolbarAction = false; + + /** + * @returns The position of the trigger button in the viewport. + */ + get triggerPosition() { + return this.getBoundingClientRect(); + } + + connectedCallback() { + if (!this.hasAttribute('aria-haspopup')) { + this.setAttribute('aria-haspopup', 'true'); + } + if (!this.shadowRoot) { + this.attachShadow({ mode: 'open' }); + } + super.connectedCallback(); + } + + updated(changedProperties) { + const button = this.shadowRoot + ?.querySelector(`${prefix}-tooltip`) + ?.querySelector('button'); + button?.classList.add( + `${prefix}--btn--icon-only`, + `${prefix}--overflow-menu` + ); + + if (changedProperties.has('open')) { + const { open } = this; + if (open && !this._menuBody) { + this._menuBody = find( + this.childNodes, + (elem) => + (elem.constructor as typeof CDSOverflowMenuBody).FLOATING_MENU + ); + } + const { _menuBody: menuBody } = this; + if (menuBody) { + menuBody.open = open; + + const tooltipContent = this.querySelector( + '[slot=tooltip-content]' + )?.textContent; + button?.setAttribute('aria-expanded', String(Boolean(open))); + button?.setAttribute('aria-label', String(tooltipContent)); + } + } + + if (changedProperties.has('dataTable')) { + const tooltip = this.shadowRoot?.querySelector(`${prefix}-tooltip`); + tooltip?.setAttribute('data-table', ''); + } + + if (changedProperties.has('size')) { + const { size } = this; + const { _menuBody: menuBody } = this; + if (menuBody) { + menuBody.size = size; + } + + button?.classList.forEach((item) => { + if (item.startsWith(`${prefix}--overflow-menu--`)) { + button?.classList.remove(item); + } + }); + button?.classList.add(`${prefix}--overflow-menu--${this.size}`); + + const tooltip = this.shadowRoot?.querySelector(`${prefix}-tooltip`); + tooltip?.setAttribute('size', this.size); + } + + if (changedProperties.has('toolbarAction') && this.toolbarAction) { + this.shadowRoot + ?.querySelector(`${prefix}-tooltip`) + ?.setAttribute('toolbar-action', ''); + } + + super.updated(changedProperties); + } + + render() { + return html` ${super.render()} `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSOverflowMenu; diff --git a/packages/web-components/src/components/pagination/defs.ts b/packages/web-components/src/components/pagination/defs.ts new file mode 100644 index 000000000000..afe597c84fe2 --- /dev/null +++ b/packages/web-components/src/components/pagination/defs.ts @@ -0,0 +1,28 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Pagination size. + */ +export enum PAGINATION_SIZE { + /** + * Small size. + */ + SMALL = 'sm', + + /** + * Medium size. + */ + MEDIUM = 'md', + + /** + * Large size. + */ + LARGE = 'lg', +} diff --git a/packages/web-components/src/components/pagination/docs/overview.mdx b/packages/web-components/src/components/pagination/docs/overview.mdx new file mode 100644 index 000000000000..75eed4ba54d3 --- /dev/null +++ b/packages/web-components/src/components/pagination/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/pagination/index.ts b/packages/web-components/src/components/pagination/index.ts new file mode 100644 index 000000000000..6a7a63e0d741 --- /dev/null +++ b/packages/web-components/src/components/pagination/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '../select/select-item'; +import '../select/select'; +import './pagination'; diff --git a/packages/web-components/src/components/pagination/pagination.mdx b/packages/web-components/src/components/pagination/pagination.mdx new file mode 100644 index 000000000000..413d85a88473 --- /dev/null +++ b/packages/web-components/src/components/pagination/pagination.mdx @@ -0,0 +1,58 @@ +import { ArgTypes, Meta, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as PaginationStories from './pagination.stories'; + + + +# Pagination + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/pagination) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/pagination) + +The pagination component is used to switch through multiple pages of items, when +only a maximum number of items can be displayed per page. Can be used in +combination with other components like data table. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/pagination/index.js'; +``` + +{`${cdnJs({ components: ['pagination'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + 10 + 20 + 30 + 40 + 50 + +``` + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `at-last-page` attribute). + + + +## `` attributes, properties and events + + + +## `` attributes, properties and events + + diff --git a/packages/web-components/src/components/pagination/pagination.scss b/packages/web-components/src/components/pagination/pagination.scss new file mode 100644 index 000000000000..530670b443c5 --- /dev/null +++ b/packages/web-components/src/components/pagination/pagination.scss @@ -0,0 +1,45 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/type' as *; +@use '@carbon/styles/scss/breakpoint' as *; +@use '@carbon/styles/scss/components/pagination' as *; +@use '@carbon/styles/scss/utilities/visually-hidden' as *; + +:host(#{$prefix}-pagination) { + @extend .#{$prefix}--pagination; + + position: relative; + outline: none; + + .#{$prefix}-ce--pagination__divider { + background-color: $layer-accent-01; + block-size: 100%; + inline-size: to-rem(1px); + } + + .#{$prefix}--pagination__control-buttons { + block-size: 100%; + } + + .#{$prefix}--pagination__button svg { + transform: rotate(0) #{'/*rtl:rotate(180deg)*/'}; + } +} + +:host(#{$prefix}-pagination[size='sm']) { + @extend .#{$prefix}--pagination--sm; +} + +:host(#{$prefix}-pagination[size='lg']) { + @extend .#{$prefix}--pagination--lg; +} diff --git a/packages/web-components/src/components/pagination/pagination.stories.ts b/packages/web-components/src/components/pagination/pagination.stories.ts new file mode 100644 index 000000000000..b51513ede1eb --- /dev/null +++ b/packages/web-components/src/components/pagination/pagination.stories.ts @@ -0,0 +1,199 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './index'; +import '../select/index'; +import { prefix } from '../../globals/settings'; +import { PAGINATION_SIZE } from './defs'; + +const sizes = { + [`Small size (${PAGINATION_SIZE.SMALL})`]: PAGINATION_SIZE.SMALL, + [`Medium size (${PAGINATION_SIZE.MEDIUM})`]: PAGINATION_SIZE.MEDIUM, + [`Large size (${PAGINATION_SIZE.LARGE})`]: PAGINATION_SIZE.LARGE, +}; + +const args = { + backwardText: 'Previous page', + disabled: false, + forwardText: 'Next page', + isLastPage: false, + itemsPerPageText: 'Items per page:', + page: 1, + pageSize: 10, + pageInputDisabled: false, + pageSizeInputDisabled: false, + pagesUnknown: false, + size: PAGINATION_SIZE.MEDIUM, + totalItems: 103, +}; + +const argTypes = { + backwardText: { + control: 'text', + description: 'The description for the backward icon.', + }, + disabled: { + control: 'boolean', + description: + 'true if the backward/forward buttons, as well as the page select elements, should be disabled.', + }, + forwardText: { + control: 'text', + description: 'The description for the forward icon.', + }, + isLastPage: { + control: 'boolean', + description: + 'true if the current page should be the last page.', + }, + itemsPerPageText: { + control: 'text', + description: 'The text indicating the number of items per page.', + }, + page: { + control: 'number', + description: 'The current page.', + }, + pageSize: { + control: 'number', + description: 'The number dictating how many items a page contains.', + }, + pageInputDisabled: { + control: 'boolean', + description: + 'true if the select box to change the page should be disabled.', + }, + pageSizeInputDisabled: { + control: 'boolean', + description: + 'true if the select box to change the items per page should be disabled.', + }, + pagesUnknown: { + control: 'boolean', + description: 'true if the total number of items is unknown.', + }, + size: { + control: 'select', + description: 'Specify the size of the Pagination.', + options: sizes, + }, + totalItems: { + control: 'number', + description: 'The total number of items.', + }, + onChangedCurrent: { + action: `${prefix}-pagination-changed-current`, + }, + onChangedPageSizesSelect: { + action: `${prefix}-page-sizes-select-changed`, + }, +}; + +export const Default = { + render: () => { + return html` + + 10 + 20 + 30 + 40 + 50 + + `; + }, +}; + +export const MultiplePaginationComponents = { + render: () => { + return html` + + 10 + 20 + 30 + 40 + 50 + + + 10 + 20 + 30 + 40 + 50 + + `; + }, +}; + +export const PaginationWithCustomPageSizesLabel = { + render: () => { + return html` + + Ten + Twenty + Thirty + Forty + Fifty + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + backwardText, + onChangedCurrent, + onChangedPageSizesSelect, + disabled, + forwardText, + isLastPage, + itemsPerPageText, + page, + pageInputDisabled, + pageSize, + pageSizeInputDisabled, + pagesUnknown, + size, + totalItems, + } = args ?? {}; + return html` + + 10 + 20 + 30 + 40 + 50 + + `; + }, +}; + +const meta = { + title: 'Components/Pagination', + decorators: [(story) => html`
    ${story()}
    `], +}; + +export default meta; diff --git a/packages/web-components/src/components/pagination/pagination.ts b/packages/web-components/src/components/pagination/pagination.ts new file mode 100644 index 000000000000..403bef7a02ec --- /dev/null +++ b/packages/web-components/src/components/pagination/pagination.ts @@ -0,0 +1,477 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import CaretLeft16 from '@carbon/icons/lib/caret--left/16'; +import CaretRight16 from '@carbon/icons/lib/caret--right/16'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import HostListener from '../../globals/decorators/host-listener'; +import styles from './pagination.scss?lit'; +import { PAGINATION_SIZE } from './defs'; +import CDSSelect from '../select/select'; +import '../button/index'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Pagination UI. + * + * @element cds-pagination + * @slot page-sizes-select - Where to put in the ``. + * @fires cds-pages-select-changed - The custom event fired after the current page is changed from ``. + * @fires cds-page-sizes-select-changed + * The custom event fired after the number of rows per page is changed from ``. + */ +@customElement(`${prefix}-pagination`) +class CDSPagination extends FocusMixin(HostListenerMixin(LitElement)) { + @query(`${prefix}-select`) + private _pageSizeSelect!: HTMLElement; + + private _handleSlotChange({ target }: Event) { + const content = (target as HTMLSlotElement) + .assignedNodes() + .filter( + (node) => node.nodeType !== Node.TEXT_NODE || node!.textContent!.trim() + ); + + content.forEach((item) => { + this._pageSizeSelect.appendChild(item); + }); + } + + /** + * @returns Page status text. + */ + private _renderStatusText() { + const { + start, + pageSize, + totalItems, + pagesUnknown, + formatStatusWithDeterminateTotal, + formatStatusWithIndeterminateTotal, + } = this; + // * Regular: `1-10 of 100 items` + // * Indeterminate total: `Item 1-10` (`Item 11-` at the last page) + const end = Math.min( + start + pageSize, + totalItems == null ? Infinity : totalItems + ); + const format = + totalItems == null || pagesUnknown + ? formatStatusWithIndeterminateTotal + : formatStatusWithDeterminateTotal; + + // `start`/`end` properties starts with zero, whereas we want to show number starting with 1 + return format({ start: start + 1, end, count: totalItems }); + } + + /** + * Handles user-initiated change in the row number the current page starts with. + * + * @param start The new current row number, index that starts with zero. + */ + private _handleUserInitiatedChangeStart(start: number) { + this.start = start; + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSPagination).eventChangeCurrent, + { + bubbles: true, + composed: true, + detail: { + page: this.page, + pageSize: this.pageSize, + }, + } + ) + ); + } + + /** + * Handles `click` event on the previous button. + */ + private _handleClickPrevButton() { + const { start: oldStart, pageSize } = this; + this.page--; + const newStart = Math.max(oldStart - pageSize, 0); + if (newStart !== oldStart) { + this._handleUserInitiatedChangeStart(newStart); + } + } + + /** + * Handles `click` event on the next button. + */ + private _handleClickNextButton() { + const { start: oldStart, pageSize, totalItems } = this; + this.page++; + const newStart = oldStart + pageSize; + if (newStart < (totalItems == null ? Infinity : totalItems)) { + this._handleUserInitiatedChangeStart(newStart); + } + } + + /** + * Handles user-initiated change in number of rows per page. + * + * @param event The event. + */ + @HostListener('eventChangeSelect') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleChangeSelector(event) { + const { value } = event.detail; + const { totalItems, pageSize } = this; + + if (event.composedPath()[0] === this._pageSizeSelect) { + this.pageSize = parseInt(value); + // Default pageSize to effectively be 1 when we have a value of 0 to avoid + // division by 0. + this.totalPages = + pageSize > 0 ? Math.ceil(totalItems / pageSize) : totalItems; + this.page = 1; + this.start = 0; + } else { + this.page = value; + this._handleUserInitiatedChangeStart((value - 1) * pageSize); + } + } + + /** + * The assistive text for the button to go to previous page. + */ + @property({ attribute: 'backward-text' }) + backwardText = 'Previous page'; + + /** + * The current page + */ + @property({ type: Number, reflect: true }) + page = 1; + + /** + * The formatter for the assistive text for screen readers to announce. + * Should be changed upon the locale the UI is rendered with. + */ + @property({ attribute: false }) + formatLabelText = ({ count }) => + `Page number, of ${count} page${count <= 1 ? '' : 's'}`; + + /** + * The formatter, used with determinate the total pages. Should be changed upon the locale the UI is rendered with. + */ + @property({ attribute: false }) + formatStatusWithDeterminateTotal = ({ start, end, count }) => + `${start}–${end} of ${count} item${count <= 1 ? '' : 's'}`; + + /** + * The formatter, used with indeterminate the total pages. Should be changed upon the locale the UI is rendered with. + */ + @property({ attribute: false }) + formatStatusWithIndeterminateTotal = ({ start, end, count }) => + end == null + ? `Item ${start}–` + : `${start}–${end} item${count <= 1 ? '' : 's'}`; + + /** + * The formatter for the text next to the select box. Should be changed upon the locale the UI is rendered with. + */ + @property({ attribute: false }) + formatSupplementalText = ({ count }) => + this.pagesUnknown || !this.totalItems + ? `page` + : `of ${count} page${count <= 1 ? '' : 's'}`; + /** + * `true` to explicitly state that user is at the last page. + */ + @property({ type: Boolean, attribute: 'is-last-page' }) + isLastPage!: boolean; + + /** + * The translatable text indicating the number of items per page. + */ + @property({ attribute: 'items-per-page-text' }) + itemsPerPageText = 'Items per page:'; + + /** + * `true` if the pagination UI should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * The assistive text for the button to go to next page. + */ + @property({ attribute: 'forward-text' }) + forwardText = 'Next page'; + + /** + * true if the select box to change the page should be disabled. + */ + @property({ type: Boolean, attribute: 'page-input-disabled' }) + pageInputDisabled = false; + + /** + * Number of items per page. + */ + @property({ type: Number, attribute: 'page-size', reflect: true }) + pageSize = 10; + + /** + * true if the select box to change the items per page should be disabled. + */ + @property({ type: Boolean, attribute: 'page-size-input-disabled' }) + pageSizeInputDisabled; + + /** + * The label text for the UI to select page size. + */ + @property({ attribute: 'page-size-label-text' }) + pageSizeLabelText!: string; + + /** + * true if the total number of items is unknown. + */ + @property({ type: Boolean, reflect: true, attribute: 'pages-unknown' }) + pagesUnknown = false; + + /** + * Specify the size of the Pagination. + */ + @property({ reflect: true }) + size = PAGINATION_SIZE.MEDIUM; + + /** + * The row number where current page start with, index that starts with zero. + */ + @property({ type: Number }) + start = 0; + + /** + * The number of total items. + */ + @property({ type: Number, attribute: 'total-items' }) + totalItems!: number; + + /** + * The number of total pages. + */ + @property({ type: Number }) + totalPages = 1; + + updated(changedProperties) { + const { page, pageSize, totalItems } = this; + const { selectorPageSizesSelect, selectorPagesSelect } = this + .constructor as typeof CDSPagination; + + if (changedProperties.has('pageSize')) { + (this.shadowRoot!.querySelector(selectorPageSizesSelect) as any).value = + pageSize; + } + if (changedProperties.has('pageSize') || changedProperties.has('start')) { + // Default pageSize to effectively be 1 when we have a value of 0 to avoid + // division by 0. + this.totalPages = + pageSize > 0 ? Math.ceil(totalItems / pageSize) : totalItems; + (this.shadowRoot!.querySelector(selectorPagesSelect) as CDSSelect).value = + this.page.toString(); + } + + if (changedProperties.has('page')) { + this._handleUserInitiatedChangeStart((page - 1) * pageSize); + } + } + + render() { + const { + page, + disabled, + forwardText, + backwardText, + itemsPerPageText, + pageInputDisabled, + pageSize, + pageSizeInputDisabled, + pagesUnknown, + size, + start, + totalItems, + totalPages, + _handleClickPrevButton: handleClickPrevButton, + _handleClickNextButton: handleClickNextButton, + _handleSlotChange: handleSlotChange, + formatLabelText, + formatSupplementalText, + } = this; + + const { isLastPage = start + pageSize >= totalItems } = this; + const prevButtonDisabled = disabled || start === 0; + const nextButtonDisabled = disabled || isLastPage; + + const prevButtonClassMap = { + [`${prefix}--btn`]: true, + [`${prefix}--btn--icon-only`]: true, + [`${prefix}--pagination__button`]: true, + [`${prefix}--pagination__button--backward`]: true, + [`${prefix}--pagination__button--no-index`]: prevButtonDisabled, + [`${prefix}--btn--${size}`]: true, + [`${prefix}--btn--ghost`]: true, + }; + const nextButtonClassMap = { + [`${prefix}--btn`]: true, + [`${prefix}--btn--icon-only`]: true, + [`${prefix}--pagination__button`]: true, + [`${prefix}--pagination__button--forward`]: true, + [`${prefix}--pagination__button--no-index`]: nextButtonDisabled, + [`${prefix}--btn--${size}`]: true, + [`${prefix}--btn--ghost`]: true, + }; + + const prevButtonClasses = Object.entries(prevButtonClassMap) + .filter(([, value]) => value === true) + .map(([key]) => key) + .join(' '); + const nextButtonClasses = Object.entries(nextButtonClassMap) + .filter(([, value]) => value === true) + .map(([key]) => key) + .join(' '); + + return html` +
    + + + + + ${this._renderStatusText()} +
    +
    + + ${pagesUnknown || !totalItems + ? html` + ${formatSupplementalText({ count: totalPages })} + + + ${Array.from(new Array(totalPages)).map( + (_item, index) => + html` + + ${index + 1} + + ` + )} + + ` + : html` + + ${Array.from(new Array(totalPages)).map( + (_item, index) => + html` + + ${index + 1} + + ` + )} + + ${formatSupplementalText({ count: totalPages })} + `} + +
    + + ${CaretLeft16({ slot: 'icon' })} + + + ${CaretRight16({ slot: 'icon' })} + +
    +
    + `; + } + + /** + * A selector that will return the select box for the current page. + */ + static get selectorPagesSelect() { + return `${prefix}-select#pages-select`; + } + + /** + * A selector that will return the select box for page sizes. + */ + static get selectorPageSizesSelect() { + return `${prefix}-select`; + } + + /** + * The name of the custom event fired after the current row number is changed. + */ + static get eventChangeCurrent() { + return `${prefix}-pagination-changed-current`; + } + + /** + * The name of the custom event fired after the number of rows per page is changed from ``. + */ + static get eventChangeSelect() { + return `${prefix}-select-selected`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSPagination; diff --git a/packages/web-components/src/components/popover/autoalign.mdx b/packages/web-components/src/components/popover/autoalign.mdx new file mode 100644 index 000000000000..bebc1315a9f2 --- /dev/null +++ b/packages/web-components/src/components/popover/autoalign.mdx @@ -0,0 +1,142 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as AutoAlignStories from './autoalign.stories'; + + + +# Auto Align + +> 💡 Check our +> [CodeSandbox](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/autoalign) +> example implementation. + +[![Edit carbon-web-components](https://codesandbox.io/static/img/play-codesandbox.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/autoalign) + +## Table of Contents + +- [Overview](#overview) +- [Popover](#popover) +- [Toggletip](#toggletip) +- [Tooltip](#tooltip) +- [Slug](#slug) + +## Overview + +Auto Align is an experimental feature utilizing the +[@floating-ui/dom](https://floating-ui.com/docs/getting-started) library. With +Auto Align, the tooltip or popover is positioned relative to the viewport and +other elements, avoiding collisions. + +NOTE: The Auto Align feature currently uses the `flip()` utility from +[@floating-ui/dom](https://floating-ui.com/docs/flip) with the +`fallbackAxisSideDirection` enabled. If no placements along the preferred +placement axis fit, it will fallback to a primary axis direction (`top`, `left`, +`right`, or `bottom`). + +Activating the Auto Align feature is simple - just add the `autoalign` property +to the component. + +## Popover + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/popover/index.js'; +import Checkbox16 from '@carbon/icons/lib/checkbox/16'; +``` + +{`${cdnJs({ components: ['popover'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + +
    ${Checkbox16()}
    + +
    +

    Available storage

    +

    + This server has 150 GB of block storage remaining. +

    +
    +
    +
    +``` + +## Toggletip + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/toggle-tip/index.js'; +``` + +{`${cdnJs({ components: ['toogle-tip'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + Toggletip label + +

    toggletip body text

    + Test + Button +
    +``` + +## Tooltip + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/tooltip/index.js'; +import Information16 from '@carbon/icons/lib/information/16'; +``` + +{`${cdnJs({ components: ['tooltip'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + +
    ${Information16()}
    + + Occassionally, services are updated in a specified time window to ensure no + down time for customers. + +
    +``` + +## Slug + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/slug/index.js'; +``` + +{`${cdnJs({ components: ['slug'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + +
    +

    AI Explained

    +

    84%

    +

    Confidence score

    +

    + Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

    +
    +

    Model type

    +

    Foundation model

    +
    +
    +``` diff --git a/packages/web-components/src/components/popover/autoalign.stories.ts b/packages/web-components/src/components/popover/autoalign.stories.ts new file mode 100644 index 000000000000..837214229799 --- /dev/null +++ b/packages/web-components/src/components/popover/autoalign.stories.ts @@ -0,0 +1,312 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './index'; +import '../toggle-tip/index'; +import '../slug/index'; +import '../icon-button/index'; +import '../data-table/index'; +import { POPOVER_ALIGNMENT } from './defs'; +import { SLUG_SIZE } from '../slug/defs'; +import Checkbox16 from '@carbon/icons/lib/checkbox/16'; +import Information16 from '@carbon/icons/lib/information/16'; +import View16 from '@carbon/icons/lib/view/16'; +import FolderOpen16 from '@carbon/icons/lib/folder--open/16'; +import Folders16 from '@carbon/icons/lib/folders/16'; + +import styles from './popover-story.scss?lit'; +import slugStyles from '../slug/slug-story.scss?lit'; +import tooltipStyles from '../tooltip/tooltip-story.scss?lit'; + +const popoverAlignments = { + [`top`]: POPOVER_ALIGNMENT.TOP, + [`top-start`]: POPOVER_ALIGNMENT.TOP_START, + [`top-end`]: POPOVER_ALIGNMENT.TOP_END, + [`bottom`]: POPOVER_ALIGNMENT.BOTTOM, + [`bottom-start`]: POPOVER_ALIGNMENT.BOTTOM_START, + [`bottom-end`]: POPOVER_ALIGNMENT.BOTTOM_END, + [`left`]: POPOVER_ALIGNMENT.LEFT, + [`left-end`]: POPOVER_ALIGNMENT.LEFT_END, + [`left-start`]: POPOVER_ALIGNMENT.LEFT_START, + [`right`]: POPOVER_ALIGNMENT.RIGHT, + [`right-end`]: POPOVER_ALIGNMENT.RIGHT_END, + [`right-start`]: POPOVER_ALIGNMENT.RIGHT_START, +}; + +const sizes = { + [`Mini size (${SLUG_SIZE.MINI})`]: SLUG_SIZE.MINI, + [`2XS size (${SLUG_SIZE.EXTRA_EXTRA_SMALL})`]: SLUG_SIZE.EXTRA_EXTRA_SMALL, + [`XS size (${SLUG_SIZE.EXTRA_SMALL})`]: SLUG_SIZE.EXTRA_SMALL, + [`Small size (${SLUG_SIZE.SMALL})`]: SLUG_SIZE.SMALL, + [`Medium size (${SLUG_SIZE.MEDIUM})`]: SLUG_SIZE.MEDIUM, + [`Large size (${SLUG_SIZE.LARGE})`]: SLUG_SIZE.LARGE, + [`XL size (${SLUG_SIZE.EXTRA_LARGE})`]: SLUG_SIZE.EXTRA_LARGE, +}; + +const content = html` +
    +

    AI Explained

    +

    84%

    +

    Confidence score

    +

    + Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

    +
    +

    Model type

    +

    Foundation model

    +
    +`; + +const actions = html` + + ${View16({ slot: 'icon' })} + View + + + ${FolderOpen16({ slot: 'icon' })} + Open folder + + + ${Folders16({ slot: 'icon' })} + Folders + + View details +`; + +export const Popover = { + args: { + caret: true, + highContrast: false, + align: popoverAlignments.bottom, + dropShadow: true, + }, + argTypes: { + caret: { + control: 'boolean', + description: 'Caret (caret)', + }, + highContrast: { + control: 'boolean', + description: 'High contrast (highContrast)', + }, + align: { + control: 'select', + description: 'Align (align)', + options: popoverAlignments, + }, + dropShadow: { + control: 'boolean', + description: 'Drop shadow (dropShadow)', + }, + }, + render: (args) => { + const { caret, highContrast, align, dropShadow } = args ?? {}; + + const handleClick = (id) => { + const popover = document.querySelector(id); + const open = popover?.hasAttribute('open'); + open + ? popover?.removeAttribute('open') + : popover?.setAttribute('open', ''); + }; + + return html` + + + + +
    +

    Available storage

    +

    + This server has 150 GB of block storage remaining. +

    +
    +
    +
    + `; + }, +}; + +export const Toogletip = { + args: { + alignment: POPOVER_ALIGNMENT.BOTTOM, + bodyText: `Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, + sed do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua.`, + }, + argTypes: { + alignment: { + control: 'select', + description: 'Toggletip alignment to trigger button (alignment)', + options: popoverAlignments, + }, + bodyText: { + control: 'text', + description: 'Toggletip content (bodyText)', + }, + }, + render: (args) => { + const { alignment, bodyText } = args ?? {}; + + return html` + + Toggletip label + +

    ${bodyText}

    + Test + Button +
    + `; + }, +}; + +export const Tooltip = { + args: { + alignment: POPOVER_ALIGNMENT.TOP, + defaultOpen: false, + label: 'Custom label', + enterDelay: 100, + leaveDelay: 300, + closeOnActivation: false, + }, + argTypes: { + alignment: { + control: 'select', + description: 'Tooltip alignment to trigger button (alignment)', + options: popoverAlignments, + }, + defaultOpen: { + control: 'boolean', + description: 'Default open (defaultOpen)', + }, + label: { + control: 'text', + description: 'Label (label)', + }, + enterDelay: { + control: 'number', + description: 'Enter delay in ms', + }, + leaveDelay: { + control: 'number', + description: 'Leave delay in ms', + }, + closeOnActivation: { + control: 'boolean', + description: 'Close on activation (closeOnActivation)', + }, + }, + render: (args) => { + const { + alignment, + defaultOpen, + label, + enterDelay, + leaveDelay, + closeOnActivation, + } = args ?? {}; + + return html` + + + + ${label} + + `; + }, +}; + +export const Slug = { + args: { + alignment: POPOVER_ALIGNMENT.BOTTOM, + size: SLUG_SIZE.EXTRA_SMALL, + kind: 'default', + aiTextLabel: '', + revertActive: false, + }, + argTypes: { + alignment: { + control: 'select', + description: 'Slug alignment to trigger button (alignment)', + options: popoverAlignments, + }, + size: { + control: 'select', + description: 'Slug size (size)', + options: sizes, + }, + kind: { + control: 'select', + description: 'Kind (kind)', + options: ['default', 'inline'], + }, + aiTextLabel: { + control: 'text', + description: 'Ai text label', + }, + revertActive: { + control: 'boolean', + description: 'Revert active', + }, + }, + render: (args) => { + const { alignment, aiTextLabel, size, kind, revertActive } = args ?? {}; + return html` + +
    + + ${content} ${actions} + +
    + `; + }, +}; + +const meta = { + title: 'Experimental/Auto Align', +}; + +export default meta; diff --git a/packages/web-components/src/components/popover/defs.ts b/packages/web-components/src/components/popover/defs.ts new file mode 100644 index 000000000000..e9bb88e1f8d3 --- /dev/null +++ b/packages/web-components/src/components/popover/defs.ts @@ -0,0 +1,128 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ +/** + * The alignment choices of popover. + */ +export enum POPOVER_ALIGNMENT { + /** + * Align the top position for the popover content. + */ + TOP = 'top', + + /** + * Align the top-left position for the popover content. + * + * @deprecated + */ + TOP_LEFT = 'top-left', + + /** + * Align the top right position for the popover content. + * + * @deprecated + */ + TOP_RIGHT = 'top-right', + + /** + * Align the top-start position for the popover content. + */ + TOP_START = 'top-start', + + /** + * Align the top end position for the popover content. + */ + TOP_END = 'top-end', + + /** + * Align the bottom position for the popover content. + */ + BOTTOM = 'bottom', + + /** + * Align the bottom left position for the popover content. + * + * @deprecated + */ + BOTTOM_LEFT = 'bottom-left', + + /** + * Align the bottom right position for the popover content. + * + * @deprecated + */ + BOTTOM_RIGHT = 'bottom-right', + + /** + * Align the bottom start position for the popover content. + */ + BOTTOM_START = 'bottom-start', + + /** + * Align the bottom end position for the popover content. + */ + BOTTOM_END = 'bottom-end', + + /** + * Align the left position for the popover content. + */ + LEFT = 'left', + + /** + * Align the left bottom position for the popover content. + * + * @deprecated + */ + LEFT_BOTTOM = 'left-bottom', + + /** + * Align the left top position for the popover content. + * + * @deprecated + */ + LEFT_TOP = 'left-top', + + /** + * Align the left start position for the popover content. + */ + LEFT_START = 'left-start', + + /** + * Align the left end position for the popover content. + */ + LEFT_END = 'left-end', + + /** + * Align the right position for the popover content. + */ + RIGHT = 'right', + + /** + * Align the right bottom position for the popover content. + * + * @deprecated + */ + RIGHT_BOTTOM = 'right-bottom', + + /** + * Align the right top position for the popover content. + * + * @deprecated + */ + RIGHT_TOP = 'right-top', + + /** + * Align the right start position for the popover content. + */ + RIGHT_START = 'right-start', + + /** + * Align the right end position for the popover content. + */ + RIGHT_END = 'right-end', +} diff --git a/packages/web-components/src/components/popover/index.ts b/packages/web-components/src/components/popover/index.ts new file mode 100644 index 000000000000..d647829a5e34 --- /dev/null +++ b/packages/web-components/src/components/popover/index.ts @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './popover'; +import './popover-content'; diff --git a/packages/web-components/src/components/popover/popover-content.ts b/packages/web-components/src/components/popover/popover-content.ts new file mode 100644 index 000000000000..80218ff78204 --- /dev/null +++ b/packages/web-components/src/components/popover/popover-content.ts @@ -0,0 +1,86 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { prefix } from '../../globals/settings'; +import styles from './popover.scss?lit'; + +/** + * Popover. + * + * @element cds-popover + */ +@customElement(`${prefix}-popover-content`) +class CDSPopoverContent extends LitElement { + /** + * Specify the popover alignment + */ + @property({ reflect: true, type: String }) + align = ''; + + /** + * Specify whether a auto align functionality should be applied + */ + @property({ type: Boolean, reflect: true }) + autoalign = false; + + /** + * Specify whether a caret should be rendered + */ + @property({ type: Boolean, reflect: true }) + caret; + + /** + * Specify whether a dropShadow should be rendered + */ + @property({ type: Boolean, reflect: true }) + dropShadow = true; + + /** + * Specify whether the component is currently open or closed + */ + @property({ type: Boolean, reflect: true }) + open = false; + + /** + * Render the component using the tab tip variant + */ + @property({ type: Boolean, reflect: true }) + tabTip = false; + + /** + * The shadow slot this popover content should be in. + */ + @property({ reflect: true }) + slot = 'content'; + + render() { + if (this.autoalign) { + return html` + + + + + `; + } else { + return html` + + + + + `; + } + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSPopoverContent; diff --git a/packages/web-components/src/components/popover/popover-story.scss b/packages/web-components/src/components/popover/popover-story.scss new file mode 100644 index 000000000000..35a422075d9f --- /dev/null +++ b/packages/web-components/src/components/popover/popover-story.scss @@ -0,0 +1,124 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/type'; + +/// Utilities +.flex { + display: flex; +} + +.flex-column { + flex-direction: column; +} + +.justify-center { + justify-content: center; +} + +.justify-end { + justify-content: flex-end; +} + +.align-center { + align-items: center; +} + +.align-end { + align-items: flex-end; +} + +.justify-items-end { + justify-items: end; +} + +.position-relative { + position: relative; +} + +.display-inline-block { + display: inline-block; +} + +.grid { + display: grid; +} + +.grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.mb-3 { + margin-block-end: $spacing-05; +} + +.mt-9 { + padding-block-start: $spacing-09; +} + +.mt-10 { + padding-block-start: $spacing-10; +} + +.p-3 { + padding: $spacing-05; +} + +#{$prefix}-popover .playground-trigger { + display: flex; + align-items: center; + justify-content: center; + border: 1px solid theme.$border-subtle; + block-size: $spacing-07; + inline-size: $spacing-07; +} + +#{$prefix}-popover .playground-trigger svg { + fill: theme.$background-inverse; +} + +#{$prefix}-popover .popover-title { + @include type.type-style('heading-compact-01'); + + margin-block-end: $spacing-01; +} + +#{$prefix}-popover .popover-details { + @include type.type-style('body-compact-01'); +} + +#{$prefix}-popover .popover-story { + display: flex; + flex-direction: column; + block-size: 100%; + inline-size: 100%; +} + +.popover-tabtip-story .p-3 { + inline-size: 16rem; +} + +.popover-tabtip-story #{$prefix}-popover .#{$prefix}--radio-button-wrapper { + margin-block-end: $spacing-03; +} + +.popover-tabtip-story hr { + border: none; + margin: $spacing-03 0 $spacing-05; + background: theme.$border-subtle; + block-size: 1px; +} + +.popover-tabtip-story #{$prefix}-popover:last-of-type { + margin-inline-start: 15rem; +} diff --git a/packages/web-components/src/components/popover/popover.mdx b/packages/web-components/src/components/popover/popover.mdx new file mode 100644 index 000000000000..ada966141d7f --- /dev/null +++ b/packages/web-components/src/components/popover/popover.mdx @@ -0,0 +1,108 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as PopoverStories from './popover.stories'; + + + +# Popover + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/popover) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/popover) + +Popover is a layer that pops up over all other elements on a page + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/popover/index.js'; +import Checkbox16 from '@carbon/icons/lib/checkbox/16'; +``` + +{`${cdnJs({ components: ['popover'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + +
    ${Checkbox16()}
    + +
    +

    Available storage

    +

    + This server has 150 GB of block storage remaining. +

    +
    +
    +
    +``` + +## HTML (with Tabtip) + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/popover/index.js'; +import '@carbon/web-components/es/components/form/index.js'; +import '@carbon/web-components/es/components/radio-button/index.js'; +import '@carbon/web-components/es/components/checkbox/index.js'; + +import Settings16 from '@carbon/icons/lib/settings/16'; +``` + +```html + + + +
    + + + + + + +
    +
    + Edit columns + + + +
    +
    +
    +
    +``` + +## `` attributes and properties + + + +## `` attributes and properties + + diff --git a/packages/web-components/src/components/popover/popover.scss b/packages/web-components/src/components/popover/popover.scss new file mode 100644 index 000000000000..a5a40f47e889 --- /dev/null +++ b/packages/web-components/src/components/popover/popover.scss @@ -0,0 +1,328 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/utilities/custom-property'; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/breakpoint' as *; +@use '@carbon/styles/scss/components/popover'; + +// The distance between the popover container and the triggering element +// Specify the distance between the popover and the trigger. This value must +// have a unit otherwise the `calc()` expression will not work +// stylelint-disable-next-line length-zero-no-unit +$popover-offset: custom-property.get-var('popover-offset', 0rem); + +// Customize the dimensions of the caret by specifying its width or height. +// These values will be flipped in left or right directions to have the +// correct dimensions +$popover-caret-width: custom-property.get-var('popover-caret-width', rem(12px)); +$popover-caret-height: custom-property.get-var( + 'popover-caret-height', + rem(6px) +); + +:host(#{$prefix}-tooltip), +:host(#{$prefix}-popover) { + ::slotted(.#{$prefix}--popover--tab-tip__button) { + @extend .#{$prefix}--popover--tab-tip__button; + } +} + +:host(#{$prefix}-tooltip[highContrast]), +:host(#{$prefix}-popover[highContrast]) { + ::slotted(#{$prefix}-tooltip-content), + ::slotted(#{$prefix}-popover-content) { + @extend .#{$prefix}--popover; + } +} + +:host(#{$prefix}-popover[tabTip][open]) { + ::slotted(.#{$prefix}--popover--tab-tip__button) { + background: theme.$layer !important; /* stylelint-disable-line declaration-no-important */ + box-shadow: 0 $spacing-01 $spacing-01 rgba(0, 0, 0, 0.2); + } +} + +:host(#{$prefix}-tooltip-content), +:host(#{$prefix}-popover-content) { + @extend .#{$prefix}--popover; +} + +:host(#{$prefix}-tooltip-content[open]), +:host(#{$prefix}-popover-content[open]), +:host(#{$prefix}-toggletip[open]), +:host(#{$prefix}-slug[open]) { + .#{$prefix}--popover-content { + display: block; + } +} + +:host(#{$prefix}-tooltip-content[open][tabTip]), +:host(#{$prefix}-popover-content[open][tabTip]) { + .#{$prefix}--popover-content { + border-radius: 0; + background: theme.$layer; + } +} + +:host(#{$prefix}-tooltip-content[open][caret]), +:host(#{$prefix}-popover-content[open][caret]), +:host(#{$prefix}-toggletip[open]), +:host(#{$prefix}-slug[open]) { + .#{$prefix}--popover-caret { + display: block; + } +} + +:host(#{$prefix}-popover-content[dropShadow]) { + @include custom-property.declaration( + 'popover-drop-shadow', + drop-shadow(0 $spacing-01 $spacing-01 rgba(0, 0, 0, 0.2)) + ); +} + +:host(#{$prefix}-tooltip-content[align^='bottom']:not([autoalign])), +:host(#{$prefix}-popover-content[align^='bottom']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment^='bottom']:not([autoalign])), +:host(#{$prefix}-slug[alignment^='bottom']:not([autoalign])) { + .#{$prefix}--popover-caret { + block-size: $popover-caret-height; + clip-path: polygon(0% 100%, 50% 0%, 100% 100%); + inline-size: $popover-caret-width; + inset-block-end: 0; + inset-inline-start: 50%; + transform: translate(-50%, $popover-offset); + } +} + +:host(#{$prefix}-slug[alignment^='bottom']:not([autoalign])) + .#{$prefix}--popover-caret { + clip-path: none; +} + +:host(#{$prefix}-tooltip-content[align='bottom']:not([autoalign])), +:host(#{$prefix}-popover-content[align='bottom']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='bottom']:not([autoalign])), +:host(#{$prefix}-slug[alignment='bottom']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-end: 0; + inset-inline-start: 50%; + transform: translate(-50%, calc(100% + $popover-offset)); + } +} + +:host(#{$prefix}-tooltip-content[align='bottom-left']:not([autoalign])), +:host(#{$prefix}-popover-content[align='bottom-left']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='bottom-left']:not([autoalign])), +:host(#{$prefix}-slug[alignment='bottom-left']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-end: 0; + inset-inline-start: 0; + transform: translate( + calc(-1 * $popover-offset), + calc(100% + $popover-offset) + ); + } +} + +:host(#{$prefix}-tooltip-content[align='bottom-right']:not([autoalign])), +:host(#{$prefix}-popover-content[align='bottom-right']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='bottom-right']:not([autoalign])), +:host(#{$prefix}-slug[alignment='bottom-right']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-end: 0; + inset-inline-end: 0; + transform: translate($popover-offset, calc(100% + $popover-offset)); + } +} + +:host(#{$prefix}-tooltip-content[align^='left']:not([autoalign])), +:host(#{$prefix}-popover-content[align^='left']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment^='left']:not([autoalign])), +:host(#{$prefix}-slug[alignment^='left']:not([autoalign])) { + .#{$prefix}--popover-caret { + block-size: $popover-caret-width; + clip-path: polygon(0% 0%, 100% 50%, 0% 100%); + inline-size: $popover-caret-height; + inset-block-start: 50%; + inset-inline-end: 100%; + transform: translate(calc(-1 * $popover-offset + 100%), -50%); + } +} + +:host(#{$prefix}-tooltip-content[align='left']:not([autoalign])), +:host(#{$prefix}-popover-content[align='left']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='left']:not([autoalign])), +:host(#{$prefix}-slug[alignment='left']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-start: 50%; + inset-inline-end: 100%; + // Add in 0.1px to prevent rounding errors where the content is + // moved farther than the caret + transform: translate(calc(-1 * $popover-offset + 0.1px), -50%); + } +} + +:host(#{$prefix}-tooltip-content[align='left-bottom']:not([autoalign])), +:host(#{$prefix}-popover-content[align='left-bottom']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='left-bottom']:not([autoalign])), +:host(#{$prefix}-slug[alignment='left-bottom']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-end: 50%; + inset-inline-end: 100%; + // Add in 0.1px to prevent rounding errors where the content is + // moved farther than the caret + transform: translate( + calc(-1 * $popover-offset), + calc(0.5 * $popover-offset + $spacing-05) + ); + } +} + +:host(#{$prefix}-tooltip-content[align='left-top']:not([autoalign])), +:host(#{$prefix}-popover-content[align='left-top']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='left-top']:not([autoalign])), +:host(#{$prefix}-slug[alignment='left-top']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-start: 50%; + inset-inline-end: 100%; + // Add in 0.1px to prevent rounding errors where the content is + // moved farther than the caret + transform: translate( + calc(-1 * $popover-offset), + calc(-1 * 0.5 * $popover-offset - $spacing-05) + ); + } +} + +:host(#{$prefix}-tooltip-content[align^='right']:not([autoalign])), +:host(#{$prefix}-popover-content[align^='right']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment^='right']:not([autoalign])), +:host(#{$prefix}-slug[alignment^='right']:not([autoalign])) { + .#{$prefix}--popover-caret { + block-size: $popover-caret-width; + clip-path: polygon(0% 50%, 100% 0%, 100% 100%); + inline-size: $popover-caret-height; + inset-block-start: 50%; + inset-inline-start: 100%; + transform: translate(calc($popover-offset - 100%), -50%); + } +} + +:host(#{$prefix}-tooltip-content[align='right']:not([autoalign])), +:host(#{$prefix}-popover-content[align='right']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='right']:not([autoalign])), +:host(#{$prefix}-slug[alignment='right']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-start: 50%; + inset-inline-start: 100%; + // Add in 0.1px to prevent rounding errors where the content is + // moved farther than the caret + transform: translate($popover-offset, -50%); + } +} + +:host(#{$prefix}-tooltip-content[align='right-bottom']:not([autoalign])), +:host(#{$prefix}-popover-content[align='right-bottom']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='right-bottom']:not([autoalign])), +:host(#{$prefix}-slug[alignment='right-bottom']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-end: 50%; + inset-inline-start: 100%; + transform: translate($popover-offset, calc(0.5 * $popover-offset + 16px)); + } +} + +:host(#{$prefix}-tooltip-content[align='right-top']:not([autoalign])), +:host(#{$prefix}-popover-content[align='right-top']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='right-top']:not([autoalign])), +:host(#{$prefix}-slug[alignment='right-top']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-start: 50%; + inset-inline-start: 100%; + transform: translate( + $popover-offset, + calc(0.5 * $popover-offset * -1 - 16px) + ); + } +} + +:host(#{$prefix}-tooltip-content[align^='top']:not([autoalign])), +:host(#{$prefix}-popover-content[align^='top']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment^='top']:not([autoalign])), +:host(#{$prefix}-slug[alignment^='top']:not([autoalign])) { + .#{$prefix}--popover-caret { + block-size: $popover-caret-height; + clip-path: polygon(0% 0%, 50% 100%, 100% 0%); + inline-size: $popover-caret-width; + inset-block-start: 0; + inset-inline-start: 50%; + transform: translate(-50%, calc(-1 * $popover-offset)); + } +} + +:host(#{$prefix}-tooltip-content[align='top']:not([autoalign])), +:host(#{$prefix}-popover-content[align='top']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='top']:not([autoalign])), +:host(#{$prefix}-slug[alignment='top']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-start: 0; + inset-inline-start: 50%; + transform: translate(-50%, calc(-100% - $popover-offset)); + } +} + +:host(#{$prefix}-tooltip-content[align='top-left']:not([autoalign])), +:host(#{$prefix}-popover-content[align='top-left']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='top-left']:not([autoalign])), +:host(#{$prefix}-slug[alignment='top-left']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-start: 0; + inset-inline-start: 0; + transform: translate( + calc(-1 * $popover-offset), + calc(-100% - $popover-offset) + ); + } +} + +:host(#{$prefix}-tooltip-content[align='top-right']:not([autoalign])), +:host(#{$prefix}-popover-content[align='top-right']:not([autoalign])), +:host(#{$prefix}-toggletip[alignment='top-right']:not([autoalign])), +:host(#{$prefix}-slug[alignment='top-right']:not([autoalign])) { + .#{$prefix}--popover-content { + inset-block-start: 0; + inset-inline-end: 0; + transform: translate($popover-offset, calc(-100% - $popover-offset)); + } +} + +:host(#{$prefix}-toggletip[autoalign]), +:host(#{$prefix}-tooltip-content[autoalign]), +:host(#{$prefix}-popover-content[autoalign]) { + .#{$prefix}--popover-caret { + block-size: 8px; + inline-size: 8px; + transform: rotate(45deg); + } +} + +:host(#{$prefix}-slug[autoalign]), +:host(#{$prefix}-tooltip[autoalign]), +:host(#{$prefix}-toggletip[autoalign]), +:host(#{$prefix}-popover[autoalign]) { + .#{$prefix}--popover-container { + position: static; + } +} diff --git a/packages/web-components/src/components/popover/popover.stories.ts b/packages/web-components/src/components/popover/popover.stories.ts new file mode 100644 index 000000000000..e92a3275a087 --- /dev/null +++ b/packages/web-components/src/components/popover/popover.stories.ts @@ -0,0 +1,210 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './popover'; +import './popover-content'; +import '../radio-button/index'; +import { POPOVER_ALIGNMENT } from './defs'; +import { prefix } from '../../globals/settings'; +import Checkbox16 from '@carbon/icons/lib/checkbox/16'; +import Settings16 from '@carbon/icons/lib/settings/16'; +import '../checkbox/checkbox'; + +import styles from './popover-story.scss?lit'; +const controls = { + align: { + control: 'select', + options: [ + POPOVER_ALIGNMENT.TOP, + POPOVER_ALIGNMENT.TOP_LEFT, + POPOVER_ALIGNMENT.TOP_RIGHT, + POPOVER_ALIGNMENT.BOTTOM, + POPOVER_ALIGNMENT.BOTTOM_LEFT, + POPOVER_ALIGNMENT.BOTTOM_RIGHT, + POPOVER_ALIGNMENT.LEFT, + POPOVER_ALIGNMENT.LEFT_BOTTOM, + POPOVER_ALIGNMENT.LEFT_TOP, + POPOVER_ALIGNMENT.RIGHT, + POPOVER_ALIGNMENT.RIGHT_BOTTOM, + POPOVER_ALIGNMENT.RIGHT_TOP, + ], + description: `Specify how the popover should align with the trigger element`, + }, + caret: { + control: 'boolean', + description: `Specify whether a caret should be rendered`, + }, + + highContrast: { + control: 'boolean', + description: 'Render the component using the high-contrast variant', + }, + dropShadow: { + control: 'boolean', + description: + 'Specify whether a drop shadow should be rendered on the popover', + }, + open: { + control: 'boolean', + description: 'Specify whether the component is currently open or closed', + }, +}; + +export const TabTip = { + render: () => { + const handleClick = (id) => { + const popover = document.querySelector(id); + const open = popover?.hasAttribute('open'); + open + ? popover?.removeAttribute('open') + : popover?.setAttribute('open', ''); + }; + + return html` + +
    + + + +
    + + + + + + +
    +
    + Edit columns + + + +
    +
    +
    +
    + + + +
    + + + + + + +
    +
    + Edit columns + + + +
    +
    +
    +
    +
    + `; + }, +}; + +export const Playground = { + argTypes: controls, + args: { + caret: true, + highContrast: false, + align: POPOVER_ALIGNMENT.BOTTOM, + dropShadow: true, + open: true, + }, + + decorators: [ + (story) => html`
    ${story()}
    `, + ], + render: (args) => { + return html` + + +
    ${Checkbox16()}
    + +
    +

    Available storage

    +

    + This server has 150 GB of block storage remaining. +

    +
    +
    +
    + `; + }, +}; + +const meta = { + title: 'Components/Popover', +}; + +export default meta; diff --git a/packages/web-components/src/components/popover/popover.ts b/packages/web-components/src/components/popover/popover.ts new file mode 100644 index 000000000000..bd2d1b5281ac --- /dev/null +++ b/packages/web-components/src/components/popover/popover.ts @@ -0,0 +1,202 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { prefix } from '../../globals/settings'; +import styles from './popover.scss?lit'; +import CDSPopoverContent from './popover-content'; +import PopoverController from '../../globals/controllers/popover-controller'; + +/** + * Popover. + * + * @element cds-popover + */ +@customElement(`${prefix}-popover`) +class CDSPopover extends LitElement { + /** + * Create popover controller instance + */ + private popoverController = new PopoverController(this); + + /** + * The `` element in the shadow DOM. + */ + @query('slot') + private _triggerSlotNode!: HTMLSlotElement; + + /** + * The `` element in the shadow DOM. + */ + @query('slot[name="content"]') + private _contentSlotNode!: HTMLSlotElement; + + /** + * Specify direction of alignment + */ + @property({ reflect: true, type: String }) + align = ''; + + /** + * Specify whether a auto align functionality should be applied + */ + @property({ type: Boolean, reflect: true }) + autoalign = false; + + /** + * Specify whether a caret should be rendered + */ + @property({ type: Boolean, reflect: true }) + caret = true; + + /** + * Specify whether a dropShadow should be rendered + */ + @property({ type: Boolean, reflect: true }) + dropShadow = true; + + /** + * Render the component using the high-contrast variant + */ + @property({ type: Boolean, reflect: true }) + highContrast = false; + + /** + * Specify whether the component is currently open or closed + */ + @property({ type: Boolean, reflect: true }) + open = false; + + /** + * Render the component using the tab tip variant + */ + @property({ type: Boolean, reflect: true }) + tabTip = false; + + /** + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + if (this.tabTip) { + const component = (target as HTMLSlotElement) + .assignedNodes() + .filter( + (node) => + node.nodeType !== Node.TEXT_NODE || node!.textContent!.trim() + ); + (component[0] as HTMLElement).classList.add( + `${prefix}--popover--tab-tip__button` + ); + } + this.requestUpdate(); + } + + updated(changedProperties) { + const { selectorPopoverContent } = this.constructor as typeof CDSPopover; + ['open', 'align', 'autoalign', 'caret', 'dropShadow', 'tabTip'].forEach( + (name) => { + if (changedProperties.has(name)) { + const { [name as keyof CDSPopover]: value } = this; + if (this.querySelector(selectorPopoverContent) as CDSPopoverContent) { + (this.querySelector(selectorPopoverContent) as CDSPopoverContent)[ + name + ] = value; + } + } + } + ); + + if (this.autoalign && this.open) { + // auto align functionality with @floating-ui/dom library + const button = this._triggerSlotNode.assignedElements()[0]; + const content = this._contentSlotNode.assignedElements()[0]; + + const tooltip = content?.shadowRoot?.querySelector( + CDSPopover.selectorPopoverContentClass + ); + const arrowElement = content?.shadowRoot?.querySelector( + CDSPopover.selectorPopoverCaret + ); + + if (button && tooltip) { + this.popoverController?.setPlacement({ + trigger: button as HTMLElement, + target: tooltip as HTMLElement, + arrowElement: + this.caret && arrowElement + ? (arrowElement as HTMLElement) + : undefined, + caret: this.caret, + flip: true, + alignment: this.align, + }); + } + } + } + + render() { + const { + dropShadow, + highContrast, + open, + tabTip, + _handleSlotChange: handleSlotChange, + } = this; + if (tabTip) { + this.caret = tabTip ? false : true; + } + this.align = this.align ? this.align : tabTip ? 'bottom-left' : 'bottom'; + + const classes = classMap({ + [`${prefix}--popover-container`]: true, + [`${prefix}--popover--caret`]: this.caret, + [`${prefix}--popover--drop-shadow`]: dropShadow, + [`${prefix}--popover--high-contrast`]: highContrast, + [`${prefix}--popover--open`]: open, + [`${prefix}--popover--${this.align}`]: true, + [`${prefix}--popover--tab-tip`]: tabTip, + }); + return html` + + + + + `; + } + + /** + * A selector that will return popover content element within + * CDSPopoverContent's shadowRoot. + */ + static get selectorPopoverContentClass() { + return `.${prefix}--popover-content`; + } + + /** + * A selector that will return popover caret element within + * CDSPopoverContent's shadowRoot. + */ + static get selectorPopoverCaret() { + return `.${prefix}--popover-caret`; + } + + /** + * A selector that will return the CDSPopoverContent. + */ + static get selectorPopoverContent() { + return `${prefix}-popover-content`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSPopover; diff --git a/packages/web-components/src/components/progress-bar/defs.ts b/packages/web-components/src/components/progress-bar/defs.ts new file mode 100644 index 000000000000..a3e5b3925de2 --- /dev/null +++ b/packages/web-components/src/components/progress-bar/defs.ts @@ -0,0 +1,63 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Status of progress bar. + */ +export enum PROGRESS_BAR_STATUS { + /** + * Currently active. + */ + ACTIVE = 'active', + + /** + * Executed. + */ + FINISHED = 'finished', + + /** + * Invalid. + */ + ERROR = 'error', +} + +/** + * Size of progress bar. + */ +export enum PROGRESS_BAR_SIZE { + /** + * small size (thinner) + */ + SMALL = 'small', + + /** + * big size + */ + BIG = 'big', +} + +/** + * Defines the alignment variant of the progress bar. + */ +export enum PROGRESS_BAR_TYPE { + /** + * default type + */ + DEFAULT = 'default', + + /** + * Inline type + */ + INLINE = 'inline', + + /** + * indented type + */ + INDENTED = 'indented', +} diff --git a/packages/web-components/src/components/progress-bar/index.ts b/packages/web-components/src/components/progress-bar/index.ts new file mode 100644 index 000000000000..f3ba34161359 --- /dev/null +++ b/packages/web-components/src/components/progress-bar/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './progress-bar'; diff --git a/packages/web-components/src/components/progress-bar/progress-bar.mdx b/packages/web-components/src/components/progress-bar/progress-bar.mdx new file mode 100644 index 000000000000..c4ba935ce7a8 --- /dev/null +++ b/packages/web-components/src/components/progress-bar/progress-bar.mdx @@ -0,0 +1,64 @@ +import { ArgTypes, Meta, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as ProgressBarStories from './progress-bar.stories'; + + + +# Progress bar + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/progress-bar) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/progress-bar) + +A progress bar indicates that the user’s request has been received and the +application is making progress toward completing the requested action. Progress +bars inform users about the status of ongoing processes, the estimated time of +how long a process will take, or if a request is being executed. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/progress-bar/index.js'; +``` + +{`${cdnJs({ components: ['progress-bar'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + +``` + +## Indeterminate + +Indeterminate progress bars are used when the loading progress is unknown or the +amount of wait time can’t be calculated. To use the indeterminate variation, +make sure the `status` property is set to `active` and there is no `value` +attribute passed in. + +```html + + +``` + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `hide-label` attribute). + + diff --git a/packages/web-components/src/components/progress-bar/progress-bar.scss b/packages/web-components/src/components/progress-bar/progress-bar.scss new file mode 100644 index 000000000000..0939d7367934 --- /dev/null +++ b/packages/web-components/src/components/progress-bar/progress-bar.scss @@ -0,0 +1,11 @@ +// +// Copyright IBM Corp. 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/components/progress-bar' as *; diff --git a/packages/web-components/src/components/progress-bar/progress-bar.stories.ts b/packages/web-components/src/components/progress-bar/progress-bar.stories.ts new file mode 100644 index 000000000000..4849d01fe498 --- /dev/null +++ b/packages/web-components/src/components/progress-bar/progress-bar.stories.ts @@ -0,0 +1,184 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { + PROGRESS_BAR_SIZE, + PROGRESS_BAR_STATUS, + PROGRESS_BAR_TYPE, +} from '../progress-bar/progress-bar'; +import './progress-bar'; +import '../../../.storybook/templates/with-layer'; + +const sizes = { + [`Small size (${PROGRESS_BAR_SIZE.SMALL})`]: PROGRESS_BAR_SIZE.SMALL, + [`Big size (${PROGRESS_BAR_SIZE.BIG})`]: PROGRESS_BAR_SIZE.BIG, +}; + +const status = { + [`Active (${PROGRESS_BAR_STATUS.ACTIVE})`]: PROGRESS_BAR_STATUS.ACTIVE, + [`Finished (${PROGRESS_BAR_STATUS.FINISHED})`]: PROGRESS_BAR_STATUS.FINISHED, + [`Error (${PROGRESS_BAR_STATUS.ERROR})`]: PROGRESS_BAR_STATUS.ERROR, +}; + +const types = { + [`Default (${PROGRESS_BAR_TYPE.DEFAULT})`]: PROGRESS_BAR_TYPE.DEFAULT, + [`Inline (${PROGRESS_BAR_TYPE.INLINE})`]: PROGRESS_BAR_TYPE.INLINE, + [`Indented (${PROGRESS_BAR_TYPE.INDENTED})`]: PROGRESS_BAR_TYPE.INDENTED, +}; + +const args = { + helperText: 'Optional helper text', + hideLabel: false, + label: 'Progress bar label', + max: 100, + size: PROGRESS_BAR_SIZE.BIG, + status: PROGRESS_BAR_STATUS.ACTIVE, + type: PROGRESS_BAR_TYPE.DEFAULT, + value: 75, +}; + +const argTypes = { + helperText: { + control: 'text', + description: 'The current progress as a textual representation.', + }, + hideLabel: { + control: 'boolean', + description: 'Whether the label should be visually hidden.', + }, + label: { + control: 'text', + description: 'A label describing the progress bar.', + }, + max: { + control: 'number', + description: 'The maximum value.', + }, + size: { + control: 'select', + description: 'Specify the size of the progress bar.', + options: sizes, + }, + status: { + control: 'select', + description: 'Specify the status.', + options: status, + }, + type: { + control: 'select', + description: 'Defines the alignment variant of the progress bar.', + options: types, + }, + value: { + control: 'number', + description: 'The current value.', + }, +}; + +export const Default = { + render: () => { + return html` + + + `; + }, +}; + +export const Example = { + render: () => { + const size = 728; + let progress = 0; + + setTimeout(() => { + const bar = document.querySelector('cds-progress-bar'); + const interval = setInterval(() => { + const advancement = Math.random() * 8; + if (progress + advancement < size) { + progress = progress + advancement; + bar!.setAttribute('value', `${progress}`); + bar!.setAttribute( + 'helper-text', + `${progress.toFixed(1)}MB of ${size}MB` + ); + } else { + clearInterval(interval); + bar!.setAttribute('value', `${size}`); + bar!.setAttribute('status', `${PROGRESS_BAR_STATUS.FINISHED}`); + bar!.setAttribute('helper-text', 'Done'); + } + }, 50); + }, 3000); + + return html` + + + `; + }, +}; + +export const Indeterminate = { + render: () => { + return html` + + + `; + }, +}; + +export const WithLayer = { + render: () => { + return html` + + + + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { helperText, hideLabel, label, max, size, status, type, value } = + args ?? {}; + return html` + + + `; + }, +}; + +const meta = { + title: 'Components/Progress Bar', +}; + +export default meta; diff --git a/packages/web-components/src/components/progress-bar/progress-bar.ts b/packages/web-components/src/components/progress-bar/progress-bar.ts new file mode 100644 index 000000000000..cee8e62d80dd --- /dev/null +++ b/packages/web-components/src/components/progress-bar/progress-bar.ts @@ -0,0 +1,199 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { classMap } from 'lit/directives/class-map.js'; +import ErrorFilled16 from '@carbon/icons/lib/error--filled/16'; +import CheckmarkFilled16 from '@carbon/icons/lib/checkmark--filled/16'; +import { + PROGRESS_BAR_SIZE, + PROGRESS_BAR_STATUS, + PROGRESS_BAR_TYPE, +} from './defs'; +import { prefix } from '../../globals/settings'; +import styles from './progress-bar.scss?lit'; + +export { PROGRESS_BAR_SIZE, PROGRESS_BAR_STATUS, PROGRESS_BAR_TYPE }; + +/** + * Progress bar. + * + * @element cds-progress-bar + */ +@customElement(`${prefix}-progress-bar`) +class CDSProgressBar extends LitElement { + /** + * The current progress as a textual representation. + */ + @property({ type: String, attribute: 'helper-text', reflect: true }) + helperText; + + /** + * Whether the label should be visually hidden. + */ + @property({ type: Boolean, attribute: 'hide-label', reflect: true }) + hideLabel; + + /** + * A label describing the progress bar. + */ + @property({ type: String }) + label; + + /** + * The maximum value. + */ + @property({ type: Number, reflect: true }) + max = 100; + + /** + * Specify the size of the ProgressBar. + */ + @property({ type: String, reflect: true }) + size = PROGRESS_BAR_SIZE.BIG; + + /** + * Specify the status. + */ + @property({ type: String, reflect: true }) + status = PROGRESS_BAR_STATUS.ACTIVE; + + /** + * Defines the alignment variant of the progress bar. + */ + @property({ type: String, reflect: true }) + type = PROGRESS_BAR_TYPE.DEFAULT; + + /** + * The current value. + */ + @property({ type: Number, reflect: true }) + value; + + protected get _cappedValue() { + const { value, max, status } = this; + + let cappedValue = value; + if (cappedValue > max) { + cappedValue = max; + } + if (cappedValue < 0) { + cappedValue = 0; + } + if (status === PROGRESS_BAR_STATUS.ERROR) { + cappedValue = 0; + } else if (status === PROGRESS_BAR_STATUS.FINISHED) { + cappedValue = max; + } + + return cappedValue; + } + + updated(changedProperties) { + if ( + changedProperties.has('value') || + changedProperties.has('max') || + changedProperties.has('status') + ) { + const { _cappedValue: cappedValue, max, status } = this; + + const percentage: number = cappedValue / max; + + const bar = this.shadowRoot!.querySelector( + `.${prefix}--progress-bar__bar` + ) as HTMLElement; + + if ( + status != PROGRESS_BAR_STATUS.ERROR && + status != PROGRESS_BAR_STATUS.FINISHED + ) { + bar.style.transform = `scaleX(${percentage})`; + } else { + bar.style.transform = 'none'; + } + } + } + + render() { + const { + _cappedValue: cappedValue, + helperText, + hideLabel, + label, + max, + size, + status, + type, + value, + } = this; + + const isFinished = status === PROGRESS_BAR_STATUS.FINISHED; + const isError = status === PROGRESS_BAR_STATUS.ERROR; + + const indeterminate = + !isFinished && !isError && (value === null || value === undefined); + + let statusIcon = null; + + if (isError) { + statusIcon = ErrorFilled16({ + class: `${prefix}--progress-bar__status-icon`, + }); + } else if (isFinished) { + statusIcon = CheckmarkFilled16({ + class: `${prefix}--progress-bar__status-icon`, + }); + } + + const wrapperClasses = classMap({ + [`${prefix}--progress-bar`]: true, + [`${prefix}--progress-bar--${size}`]: true, + [`${prefix}--progress-bar--${type}`]: true, + [`${prefix}--progress-bar--indeterminate`]: indeterminate, + [`${prefix}--progress-bar--finished`]: isFinished, + [`${prefix}--progress-bar--error`]: isError, + }); + + const labelClasses = classMap({ + [`${prefix}--progress-bar__label`]: true, + [`${prefix}--visually-hidden`]: hideLabel, + }); + + return html`
    +
    + ${label} + ${statusIcon} +
    +
    +
    +
    + ${helperText + ? html`
    + ${helperText} +
    + ${isFinished ? 'Done' : 'Loading'} +
    +
    ` + : null} +
    `; + } + + static styles = styles; +} + +export default CDSProgressBar; diff --git a/packages/web-components/src/components/progress-indicator/defs.ts b/packages/web-components/src/components/progress-indicator/defs.ts new file mode 100644 index 000000000000..f743d45456b5 --- /dev/null +++ b/packages/web-components/src/components/progress-indicator/defs.ts @@ -0,0 +1,33 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * State of progress step. + */ +export enum PROGRESS_STEP_STAT { + /** + * Complete one. + */ + COMPLETE = 'complete', + + /** + * One that is being executed now. + */ + CURRENT = 'current', + + /** + * One for future execution. + */ + INCOMPLETE = 'incomplete', + + /** + * Invalid one. + */ + INVALID = 'invalid', +} diff --git a/packages/web-components/src/components/progress-indicator/docs/overview.mdx b/packages/web-components/src/components/progress-indicator/docs/overview.mdx new file mode 100644 index 000000000000..c4e5fcc7d3a2 --- /dev/null +++ b/packages/web-components/src/components/progress-indicator/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/progress-indicator/index.ts b/packages/web-components/src/components/progress-indicator/index.ts new file mode 100644 index 000000000000..8a6569021ed3 --- /dev/null +++ b/packages/web-components/src/components/progress-indicator/index.ts @@ -0,0 +1,13 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './progress-indicator'; +import './progress-indicator-skeleton'; +import './progress-step'; +import './progress-step-skeleton'; diff --git a/packages/web-components/src/components/progress-indicator/progress-indicator-skeleton.ts b/packages/web-components/src/components/progress-indicator/progress-indicator-skeleton.ts new file mode 100644 index 000000000000..635176c8888d --- /dev/null +++ b/packages/web-components/src/components/progress-indicator/progress-indicator-skeleton.ts @@ -0,0 +1,55 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { forEach } from '../../globals/internal/collection-helpers'; +import CDSProgressStepSkeleton from './progress-step-skeleton'; +import styles from './progress-indicator.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Skeleton of progress indicator. + */ +@customElement(`${prefix}-progress-indicator-skeleton`) +export default class CDSProgressIndicatorSkeleton extends LitElement { + /** + * `true` if the progress indicator should be vertical. Corresponds to the attribute with the same name. + */ + @property({ type: Boolean, reflect: true }) + vertical = false; + + updated(changedProperties) { + if (changedProperties.has('vertical')) { + // Propagate `vertical` attribute to descendants until `:host-context()` gets supported in all major browsers + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSProgressIndicatorSkeleton).selectorStep + ), + (item) => { + (item as CDSProgressStepSkeleton).vertical = this.vertical; + } + ); + } + } + + render() { + return html``; + } + + /** + * A selector that will return progress steps. + */ + static get selectorStep() { + return `${prefix}-progress-step-skeleton`; + } + + static styles = styles; +} diff --git a/packages/web-components/src/components/progress-indicator/progress-indicator.mdx b/packages/web-components/src/components/progress-indicator/progress-indicator.mdx new file mode 100644 index 000000000000..839283a4e871 --- /dev/null +++ b/packages/web-components/src/components/progress-indicator/progress-indicator.mdx @@ -0,0 +1,89 @@ +import { ArgTypes, Meta, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as ProgressIndicatorStories from './progress-indicator.stories'; + + + +# Progress indicator + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/progress-indicator) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/progress-indicator) + +Progress indicator is a visual representation of a users progress through a set +of steps. They guide the user through a number of steps in order to complete a +specified process. + +Use progress indicators to keep the user on track when completing a specific +task. By dividing the end goal into smaller, sub-tasks, it increases the +percentage of completeness as each task is completed. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/progress-indicator/index.js'; +``` + +{`${cdnJs({ components: ['progress-indicator'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + + + + + + +``` + +## Skeleton + +For the skeleton variation, utilize `` and +``. + +```html + + + + + +``` + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `vertical` attribute). + + + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `disabled` attribute). + + diff --git a/packages/web-components/src/components/progress-indicator/progress-indicator.scss b/packages/web-components/src/components/progress-indicator/progress-indicator.scss new file mode 100644 index 000000000000..7ddee20dede3 --- /dev/null +++ b/packages/web-components/src/components/progress-indicator/progress-indicator.scss @@ -0,0 +1,127 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities/skeleton' as *; +@use '@carbon/styles/scss/components/progress-indicator/progress-indicator' as *; + +// https://github.com/carbon-design-system/carbon/issues/11408 +@include progress-indicator; + +:host(#{$prefix}-progress-indicator), +:host(#{$prefix}-progress-indicator-skeleton) { + @extend .#{$prefix}--progress; +} + +:host(#{$prefix}-progress-indicator[vertical]), +:host(#{$prefix}-progress-indicator-skeleton[vertical]) { + @extend .#{$prefix}--progress--vertical; +} + +:host(#{$prefix}-progress-step), +:host(#{$prefix}-progress-step-skeleton) { + @extend .#{$prefix}--progress-step; + @extend .#{$prefix}--progress-step--incomplete; + + outline: none; + + // Carbon core style has hard-coded width whose value is the same as `.#{$prefix}--progress-step`. + // We override it so changing width of `<#{$prefix}-progress-step>` automatically changes the width here. + // https://github.com/carbon-design-system/carbon-web-components/issues/325 + .#{$prefix}--progress-line { + inline-size: 100%; + } +} + +:host(#{$prefix}-progress-step[disabled]) { + @extend .#{$prefix}--progress-step--disabled; +} + +:host(#{$prefix}-progress-step[vertical]), +:host(#{$prefix}-progress-step-skeleton[vertical]) { + display: list-item; + inline-size: initial; + min-block-size: 3.625rem; + min-inline-size: initial; + + svg { + display: inline-block; + margin: 0.1rem $spacing-02 0.1rem $spacing-03; + } + + .#{$prefix}--progress-label { + display: inline-block; + margin: 0; + max-inline-size: none; + vertical-align: top; + } + + .#{$prefix}--progress-line { + block-size: 100%; + inline-size: 1px; + inset-block-start: 0; + inset-inline-start: 0; + } +} + +:host(#{$prefix}-progress-step[vertical]) { + .#{$prefix}--progress-label { + inline-size: initial; + } + + .#{$prefix}--progress-optional { + position: initial; + margin-block-start: auto; + margin-inline-start: $spacing-07; + } + + .#{$prefix}--progress-step-button { + display: block; + } +} + +:host(#{$prefix}-progress-step[vertical][state='current']) svg { + margin-inline-start: 0.563rem; +} + +:host(#{$prefix}-progress-step[state='current']) { + @extend .#{$prefix}--progress-step--current; + + svg { + fill: $interactive; + } +} + +:host(#{$prefix}-progress-step[state='complete']) { + @extend .#{$prefix}--progress-step--complete; + + svg { + fill: $interactive; + } +} + +:host(#{$prefix}-progress-step[state='incomplete']) { + @extend .#{$prefix}--progress-step--incomplete; +} + +:host(#{$prefix}-progress-step-skeleton) { + svg { + fill: $layer-selected-inverse; + } + + .#{$prefix}--progress-line { + background-color: $layer-accent-01; + } +} + +:host(#{$prefix}-progress-step[spaceEqually]) { + flex-grow: 1; +} diff --git a/packages/web-components/src/components/progress-indicator/progress-indicator.stories.ts b/packages/web-components/src/components/progress-indicator/progress-indicator.stories.ts new file mode 100644 index 000000000000..46d8066999c5 --- /dev/null +++ b/packages/web-components/src/components/progress-indicator/progress-indicator.stories.ts @@ -0,0 +1,155 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import './index'; +import ifNonEmpty from '../../globals/directives/if-non-empty'; + +const args = { + vertical: false, + spaceEqually: false, + iconLabel: '', + secondaryLabelText: 'Optional label', +}; + +const argTypes = { + vertical: { + control: 'boolean', + description: + 'Determines whether or not the Progress Indicator should be rendered vertically.', + }, + spaceEqually: { + control: 'boolean', + description: + 'Specify whether the progress steps should be split equally in size in the div.', + }, + iconLabel: { + control: 'text', + description: 'Label used for the SVG icons in each step.', + }, + secondaryLabelText: { + control: 'text', + description: 'The secondary progress label.', + }, +}; + +export const Default = { + render: () => html` + + + + + + + + `, +}; + +export const Interactive = { + render: () => html` + + + + + + `, +}; + +export const Skeleton = { + args: { + vertical: args['vertical'], + }, + argTypes: { + vertical: args['vertical'], + }, + parameters: { + percy: { + skip: true, + }, + }, + render: (args) => { + const { vertical } = args ?? {}; + return html` + + + + + + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { iconLabel, secondaryLabelText, spaceEqually, vertical } = + args ?? {}; + return html` + + + + + + + + `; + }, +}; + +const meta = { + title: 'Components/Progress Indicator', +}; + +export default meta; diff --git a/packages/web-components/src/components/progress-indicator/progress-indicator.ts b/packages/web-components/src/components/progress-indicator/progress-indicator.ts new file mode 100644 index 000000000000..4199746c74c6 --- /dev/null +++ b/packages/web-components/src/components/progress-indicator/progress-indicator.ts @@ -0,0 +1,87 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { forEach } from '../../globals/internal/collection-helpers'; +import CDSProgressStep from './progress-step'; +import styles from './progress-indicator.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Progress indicator. + * + * @element cds-progress-indicator + */ +@customElement(`${prefix}-progress-indicator`) +export default class CDSProgressIndicator extends LitElement { + /** + * Determines whether or not the progress indicator should be rendered + * vertically. + */ + @property({ type: Boolean, reflect: true }) + vertical = false; + + /** + * Specify whether the progress steps should be split equally in size in the + * div + */ + @property({ type: Boolean, reflect: true, attribute: 'space-equally' }) + spaceEqually = false; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'list'); + } + super.connectedCallback(); + } + + updated(changedProperties) { + const spacingValue = this.vertical ? false : this.spaceEqually; + if (changedProperties.has('vertical')) { + // Propagate `vertical` attribute to descendants until + // `:host-context()` gets supported in all major browsers + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSProgressIndicator).selectorStep + ), + (item) => { + (item as CDSProgressStep).vertical = this.vertical; + (item as CDSProgressStep).spaceEqually = spacingValue; + } + ); + } + if (changedProperties.has('spaceEqually')) { + // Propagate `spaceEqually` attribute to descendants until + // `:host-context()` gets supported in all major browsers + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSProgressIndicator).selectorStep + ), + (item) => { + (item as CDSProgressStep).spaceEqually = spacingValue; + } + ); + } + } + + render() { + return html``; + } + + /** + * A selector that will return progress steps. + */ + static get selectorStep() { + return `${prefix}-progress-step`; + } + + static styles = styles; +} diff --git a/packages/web-components/src/components/progress-indicator/progress-step-skeleton.ts b/packages/web-components/src/components/progress-indicator/progress-step-skeleton.ts new file mode 100644 index 000000000000..ecf9fada3e8b --- /dev/null +++ b/packages/web-components/src/components/progress-indicator/progress-step-skeleton.ts @@ -0,0 +1,43 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import styles from './progress-indicator.scss?lit'; +import CircleDash from '@carbon/icons/lib/circle-dash/16'; +import '../skeleton-text'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Skeleton of progress step. + */ +@customElement(`${prefix}-progress-step-skeleton`) +export default class CDSProgressStepSkeleton extends LitElement { + /** + * `true` if the progress indicator should be vertical. Corresponds to the attribute with the same name. + */ + @property({ type: Boolean, reflect: true }) + vertical = false; + + render() { + return html` +
    + ${CircleDash()} +

    + +

    + +
    + `; + } + + static styles = styles; +} diff --git a/packages/web-components/src/components/progress-indicator/progress-step.ts b/packages/web-components/src/components/progress-indicator/progress-step.ts new file mode 100644 index 000000000000..cbe1d7be0538 --- /dev/null +++ b/packages/web-components/src/components/progress-indicator/progress-step.ts @@ -0,0 +1,155 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html, svg } from 'lit'; +import { property } from 'lit/decorators.js'; +import CheckmarkOutline16 from '@carbon/icons/lib/checkmark--outline/16'; +import CircleDash16 from '@carbon/icons/lib/circle-dash/16'; +import Incomplete16 from '@carbon/icons/lib/incomplete/16'; +import Warning16 from '@carbon/icons/lib/warning/16'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import { PROGRESS_STEP_STAT } from './defs'; +import styles from './progress-indicator.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { PROGRESS_STEP_STAT }; + +/** + * Icons, keyed by state. + */ +const icons = { + [PROGRESS_STEP_STAT.COMPLETE]: CheckmarkOutline16, + [PROGRESS_STEP_STAT.INCOMPLETE]: CircleDash16, + [PROGRESS_STEP_STAT.INVALID]: Warning16, + [PROGRESS_STEP_STAT.CURRENT]: Incomplete16, +}; + +/** + * Progress step. + * + * @element cds-progress-step + * @slot secondary-label-text - The secondary progress label. + */ +@customElement(`${prefix}-progress-step`) +export default class CDSProgressStep extends FocusMixin(LitElement) { + /** + * `true` if the progress step should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * The a11y text for the icon. + */ + @property({ attribute: 'icon-label' }) + iconLabel!: string; + + @property({ reflect: true }) + description!: string; + + /** + * The primary progress label. + */ + @property({ attribute: 'label-text' }) + labelText!: string; + + @property() + label!: string; + + /** + * The secondary progress label. + */ + @property({ attribute: 'secondary-label-text' }) + secondaryLabelText!: string; + + @property({ attribute: 'secondary-label' }) + secondaryLabel!: string; + + /** + * The progress state. + */ + @property() + state = PROGRESS_STEP_STAT.INCOMPLETE; + + /** + * `true` if the progress step should be vertical. + * + * @private + */ + @property({ type: Boolean, reflect: true }) + vertical = false; + + /** + * `true` if the progress step should be spaced equally. + * + * @private + */ + @property({ type: Boolean, reflect: true }) + spaceEqually = false; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'listitem'); + } + super.connectedCallback(); + } + + updated(changedProperties) { + if (changedProperties.has('disabled')) { + this.setAttribute('aria-disabled', String(Boolean(this.disabled))); + } + } + + render() { + const { + description, + iconLabel, + label, + secondaryLabelText, + secondaryLabel, + state, + } = this; + const svgLabel = iconLabel || description; + const optionalLabel = secondaryLabelText || secondaryLabel; + return html` +
    + ${icons[state]({ + class: { + [PROGRESS_STEP_STAT.INVALID]: `${prefix}--progress__warning`, + }[state], + children: svgLabel ? svg`${svgLabel}` : undefined, + })} + +

    + ${label} +

    +
    + + ${!optionalLabel + ? undefined + : html`

    + ${optionalLabel} +

    `} +
    + +
    + `; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; +} diff --git a/packages/web-components/src/components/radio-button/defs.ts b/packages/web-components/src/components/radio-button/defs.ts new file mode 100644 index 000000000000..a7bd0f3958bb --- /dev/null +++ b/packages/web-components/src/components/radio-button/defs.ts @@ -0,0 +1,38 @@ +/** + * @license + * + * Copyright IBM Corp. 2020 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * The label position of radio button. + */ +export enum RADIO_BUTTON_LABEL_POSITION { + /** + * Placed at left. + */ + LEFT = 'left', + + /** + * Placed at right. + */ + RIGHT = 'right', +} + +/** + * How to lay out radio buttons. + */ +export enum RADIO_BUTTON_ORIENTATION { + /** + * Laying out radio buttons horizontally. + */ + HORIZONTAL = 'horizontal', + + /** + * Laying out radio buttons vertically. + */ + VERTICAL = 'vertical', +} diff --git a/packages/web-components/src/components/radio-button/docs/overview.mdx b/packages/web-components/src/components/radio-button/docs/overview.mdx new file mode 100644 index 000000000000..f15150cdde91 --- /dev/null +++ b/packages/web-components/src/components/radio-button/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/radio-button/index.ts b/packages/web-components/src/components/radio-button/index.ts new file mode 100644 index 000000000000..58e7413d493f --- /dev/null +++ b/packages/web-components/src/components/radio-button/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * + * Copyright IBM Corp. 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './radio-button'; +import './radio-button-group'; +import './radio-button-skeleton'; diff --git a/packages/web-components/src/components/radio-button/radio-button-group.ts b/packages/web-components/src/components/radio-button/radio-button-group.ts new file mode 100644 index 000000000000..1d2cf7d8ede3 --- /dev/null +++ b/packages/web-components/src/components/radio-button/radio-button-group.ts @@ -0,0 +1,303 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import { prefix } from '../../globals/settings'; +import FormMixin from '../../globals/mixins/form'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import HostListener from '../../globals/decorators/host-listener'; +import { find, forEach } from '../../globals/internal/collection-helpers'; +import { RADIO_BUTTON_LABEL_POSITION, RADIO_BUTTON_ORIENTATION } from './defs'; +import WarningFilled16 from '@carbon/icons/lib/warning--filled/16'; +import WarningAltFilled16 from '@carbon/icons/lib/warning--alt--filled/16'; +import CDSRadioButton from './radio-button'; +import styles from './radio-button.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { RADIO_BUTTON_ORIENTATION }; + +/** + * Radio button group. + * + * @element cds-radio-button-group + * @fires cds-radio-button-group-changed - The custom event fired after this radio button group changes its selected item. + * @fires cds-radio-button-changed + * The name of the custom event fired after a radio button changes its checked state. + */ +@customElement(`${prefix}-radio-button-group`) +class CDSRadioButtonGroup extends FormMixin(HostListenerMixin(LitElement)) { + /** + * Handles user-initiated change in selected radio button. + */ + @HostListener('eventChangeRadioButton') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleAfterChangeRadioButton = () => { + const { selectorRadioButton } = this + .constructor as typeof CDSRadioButtonGroup; + const selected = find( + this.querySelectorAll(selectorRadioButton), + (elem) => (elem as CDSRadioButton).checked + ); + const oldValue = this.value; + this.value = selected && selected.value; + if (oldValue !== this.value) { + const { eventChange } = this.constructor as typeof CDSRadioButtonGroup; + this.dispatchEvent( + new CustomEvent(eventChange, { + bubbles: true, + composed: true, + detail: { + value: this.value, + }, + }) + ); + } + }; + + _handleFormdata(event: Event) { + const { formData } = event as any; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const { disabled, name, value } = this; + if ( + !disabled && + typeof name !== 'undefined' && + typeof value !== 'undefined' + ) { + formData.append(name, value); + } + } + + /** + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSRadioButtonGroup).slugItem + ) + : false + ); + + this._hasSlug = Boolean(hasContent); + (hasContent[0] as HTMLElement).setAttribute('size', 'mini'); + this.requestUpdate(); + } + + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + /** + * The `value` attribute for the `` for selection. + */ + @property() + defaultSelected!: string; + + /** + * `true` if the radio button group should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * The label position. + */ + @property({ reflect: true, attribute: 'label-position' }) + labelPosition = RADIO_BUTTON_LABEL_POSITION.RIGHT; + + /** + * The label position. + */ + @property({ reflect: true, attribute: 'legend-text' }) + legendText = ''; + + /** + * The helper text. + */ + @property({ attribute: 'helper-text' }) + helperText; + + /** + * Specify whether the control is currently in warning state + */ + @property({ type: Boolean, reflect: true }) + warn = false; + + /** + * Provide the text that is displayed when the control is in warning state + */ + @property({ attribute: 'warn-text' }) + warnText = ''; + + /** + * Specify if the currently value is invalid. + */ + @property({ type: Boolean, reflect: true }) + invalid = false; + + /** + * Message which is displayed if the value is invalid. + */ + @property({ attribute: 'invalid-text' }) + invalidText = ''; + + /** + * The `name` attribute for the `` for selection. + */ + @property() + name!: string; + + /** + * The orientation to lay out radio buttons. + */ + @property({ reflect: true }) + orientation = RADIO_BUTTON_ORIENTATION.HORIZONTAL; + + /** + * Controls the readonly state of the radio button group. + */ + @property({ type: Boolean, reflect: true }) + readOnly = false; + + /** + * The `value` attribute for the `` for selection. + */ + @property() + value!: string; + + updated(changedProperties) { + const { selectorRadioButton } = this + .constructor as typeof CDSRadioButtonGroup; + ['disabled', 'labelPosition', 'orientation', 'readOnly', 'name'].forEach( + (name) => { + if (changedProperties.has(name)) { + const { [name as keyof CDSRadioButtonGroup]: value } = this; + // Propagate the property to descendants until `:host-context()` gets supported in all major browsers + forEach(this.querySelectorAll(selectorRadioButton), (elem) => { + (elem as CDSRadioButton)[name] = value; + }); + } + } + ); + if (changedProperties.has('value')) { + const { value } = this; + forEach(this.querySelectorAll(selectorRadioButton), (elem) => { + (elem as CDSRadioButton).checked = + value === (elem as CDSRadioButton).value; + }); + } + if (changedProperties.has('invalid')) { + forEach(this.querySelectorAll(selectorRadioButton), (elem) => { + (elem as CDSRadioButton).invalid = this.invalid; + }); + } + } + + render() { + const { + readOnly, + invalid, + invalidText, + warn, + warnText, + disabled, + orientation, + legendText, + helperText, + _hasSlug: hasSlug, + _handleSlotChange: handleSlotChange, + } = this; + + const showWarning = !readOnly && !invalid && warn; + const showHelper = !invalid && !disabled && !warn; + + const invalidIcon = WarningFilled16({ + class: `${prefix}--radio-button__invalid-icon`, + }); + + const warnIcon = WarningAltFilled16({ + class: `${prefix}--radio-button__invalid-icon ${prefix}--radio-button__invalid-icon--warning`, + }); + + const helper = helperText + ? html`
    ${helperText}
    ` + : null; + + const fieldsetClasses = classMap({ + [`${prefix}--radio-button-group`]: true, + [`${prefix}--radio-button-group--readonly`]: readOnly, + [`${prefix}--radio-button-group--${orientation}`]: + orientation === 'vertical', + [`${prefix}--radio-button-group--slug`]: hasSlug, + }); + + return html`
    + ${legendText + ? html` + ${legendText} + + ` + : ``} + +
    +
    + ${!readOnly && invalid + ? html` + ${invalidIcon} +
    ${invalidText}
    + ` + : null} + ${showWarning + ? html`${warnIcon} +
    ${warnText}
    ` + : null} +
    + ${showHelper ? helper : null}`; + } + + /** + * A selector that will return the radio buttons. + */ + static get selectorRadioButton() { + return `${prefix}-radio-button`; + } + + /** + * A selector that will return the slug item. + */ + static get slugItem() { + return `${prefix}-slug`; + } + + /** + * The name of the custom event fired after this radio button group changes its selected item. + */ + static get eventChange() { + return `${prefix}-radio-button-group-changed`; + } + + /** + * The name of the custom event fired after a radio button changes its checked state. + */ + static get eventChangeRadioButton() { + return `${prefix}-radio-button-changed`; + } + + static styles = styles; +} + +export default CDSRadioButtonGroup; diff --git a/packages/web-components/src/components/radio-button/radio-button-skeleton.ts b/packages/web-components/src/components/radio-button/radio-button-skeleton.ts new file mode 100644 index 000000000000..8042039966b0 --- /dev/null +++ b/packages/web-components/src/components/radio-button/radio-button-skeleton.ts @@ -0,0 +1,30 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './radio-button.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Skeleton of radio button. + */ +@customElement(`${prefix}-radio-button-skeleton`) +class CDSRadioButtonSkeleton extends LitElement { + render() { + return html` +
    + + `; + } + + static styles = styles; +} + +export default CDSRadioButtonSkeleton; diff --git a/packages/web-components/src/components/radio-button/radio-button.mdx b/packages/web-components/src/components/radio-button/radio-button.mdx new file mode 100644 index 000000000000..8b802a6f6e1d --- /dev/null +++ b/packages/web-components/src/components/radio-button/radio-button.mdx @@ -0,0 +1,70 @@ +import { ArgTypes, Meta, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as RadioButtonStories from './radio-button.stories'; + + + +# Radio button + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/radio-button) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/radio-button) + +Radio buttons are used when a list of two or more options are mutually +exclusive, meaning the user must select only one option. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/radio-button/index.js'; +``` + +{`${cdnJs({ components: ['radio-button'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + + + + +``` + +## Skeleton + +For the skeleton variation, utilize ``. + +```html + +``` + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `disabled` attribute). + + + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `disabled` attribute). + + diff --git a/packages/web-components/src/components/radio-button/radio-button.scss b/packages/web-components/src/components/radio-button/radio-button.scss new file mode 100644 index 000000000000..ba33b65d2483 --- /dev/null +++ b/packages/web-components/src/components/radio-button/radio-button.scss @@ -0,0 +1,131 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/utilities/convert' as *; +@use '@carbon/styles/scss/components/form'; +@use '@carbon/styles/scss/components/radio-button/radio-button' as *; + +// https://github.com/carbon-design-system/carbon/issues/11408 +@include radio-button; + +:host(#{$prefix}-radio-button-group) { + @extend .#{$prefix}--form-item; +} + +:host(#{$prefix}-radio-button-group[label-position='left']) { + @extend .#{$prefix}--radio-button-group--label-left; +} + +:host(#{$prefix}-radio-button-group[orientation='vertical']) { + @extend .#{$prefix}--radio-button-group--vertical; +} + +:host(#{$prefix}-radio-button-group[invalid]), +:host(#{$prefix}-radio-button-group[warn]) { + .#{$prefix}--radio-button__validation-msg { + display: flex; + + .#{$prefix}--form-requirement { + display: block; + overflow: visible; + margin-block-start: 0; + margin-inline-start: $spacing-03; + max-block-size: 100%; + } + } +} + +:host(#{$prefix}-radio-button-group[invalid]) .#{$prefix}--form-requirement { + color: $text-error; +} + +:host(#{$prefix}-radio-button) { + @extend .#{$prefix}--radio-button-wrapper; + + outline: none; + + .#{$prefix}--radio-button__label { + flex-direction: row; + } +} + +:host(#{$prefix}-radio-button:not(:last-of-type)) { + margin-inline-end: $spacing-05; +} + +:host(#{$prefix}-radio-button[orientation='vertical']) { + margin-block-end: to-rem(6px); + margin-inline-end: 0; +} + +:host(#{$prefix}-radio-button[invalid]) .#{$prefix}--radio-button__appearance { + border-color: $support-error !important; /* stylelint-disable-line declaration-no-important */ +} + +:host(#{$prefix}-radio-button[data-table]) { + .#{$prefix}--radio-button__label { + inline-size: rem(28px); + } + + .#{$prefix}--radio-button__appearance { + margin-inline-end: -#{$spacing-01}; + } +} + +:host(#{$prefix}-radio-button[readOnly]) { + @extend .#{$prefix}--radio-button-group--readonly; +} + +:host(#{$prefix}-radio-button[disabled]), +:host(#{$prefix}-radio-button[disabledItem]) { + .#{$prefix}--radio-button__label { + color: $text-disabled; + cursor: not-allowed; + } + + .#{$prefix}--radio-button__appearance { + border-color: $border-disabled; + + &::before { + background-color: $border-disabled; + } + } +} + +:host(#{$prefix}-radio-button[label-position='left']) { + .#{$prefix}--radio-button__label { + flex-direction: row-reverse; + } + + .#{$prefix}--radio-button__appearance { + margin-inline: $spacing-03 0; + } +} + +:host(#{$prefix}-radio-button[slug]) { + .#{$prefix}--radio-button__label-text { + display: flex; + } + + ::slotted(#{$prefix}-slug[inline]) { + line-height: inherit; + margin-block-start: to-rem(-1px); + } +} + +:host(#{$prefix}-radio-button-group) .#{$prefix}--radio-button-group--slug, +:host(#{$prefix}-radio-button[slug]) { + ::slotted(#{$prefix}-slug) { + margin-inline-start: $spacing-03; + } +} diff --git a/packages/web-components/src/components/radio-button/radio-button.stories.ts b/packages/web-components/src/components/radio-button/radio-button.stories.ts new file mode 100644 index 000000000000..d080475da9be --- /dev/null +++ b/packages/web-components/src/components/radio-button/radio-button.stories.ts @@ -0,0 +1,201 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { prefix } from '../../globals/settings'; +import { RADIO_BUTTON_ORIENTATION } from './radio-button-group'; +import { RADIO_BUTTON_LABEL_POSITION } from './radio-button'; +import './index'; + +const orientations = { + [`Horizontal (${RADIO_BUTTON_ORIENTATION.HORIZONTAL})`]: + RADIO_BUTTON_ORIENTATION.HORIZONTAL, + [`Vertical (${RADIO_BUTTON_ORIENTATION.VERTICAL})`]: + RADIO_BUTTON_ORIENTATION.VERTICAL, +}; + +const labelPositions = { + [`Left (${RADIO_BUTTON_LABEL_POSITION.LEFT})`]: + RADIO_BUTTON_LABEL_POSITION.LEFT, + [`Right (${RADIO_BUTTON_LABEL_POSITION.RIGHT})`]: + RADIO_BUTTON_LABEL_POSITION.RIGHT, +}; + +const args = { + disabled: false, + readOnly: false, + helperText: 'Helper text', + invalid: false, + invalidText: 'Invalid selection', + labelPosition: RADIO_BUTTON_LABEL_POSITION.RIGHT, + orientation: RADIO_BUTTON_ORIENTATION.HORIZONTAL, + name: 'radio-group', + value: '', + warn: false, + warnText: 'Please notice the warning', + checked: false, + hideLabel: false, + labelText: 'Radio button label', +}; + +const argTypes = { + disabled: { + control: 'boolean', + description: 'Disabled (disabled)', + }, + readOnly: { + control: 'boolean', + description: 'read only (readOnly)', + }, + helperText: { + control: 'text', + description: 'Helper text (helper-text)', + }, + invalid: { + control: 'boolean', + description: 'Invalid (invalid)', + }, + invalidText: { + control: 'text', + description: 'Invalid text (invalid-text)', + }, + labelPosition: { + control: 'select', + description: 'Label position (label-position)', + options: labelPositions, + }, + orientation: { + control: 'select', + description: 'Orientation (orientation)', + options: orientations, + }, + name: { + control: 'text', + description: 'Name (name)', + }, + value: { + control: 'text', + description: 'Value (value)', + }, + warn: { + control: 'boolean', + description: 'Warn (warn)', + }, + warnText: { + control: 'text', + description: 'Warn text (warn-text)', + }, + checked: { + control: 'boolean', + description: 'Checked (checked)', + }, + hideLabel: { + control: 'boolean', + description: 'Hide label (hide-label)', + }, + labelText: { + control: 'text', + description: 'Label text (label-text)', + }, + onChange: { + action: `${prefix}-radio-button-group-changed`, + }, +}; + +export const Default = { + render: () => { + return html` + + + + + + `; + }, +}; + +export const Skeleton = { + parameters: { + percy: { + skip: true, + }, + }, + render: () => html``, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + disabled, + readOnly, + helperText, + invalid, + invalidText, + labelPosition, + orientation, + name, + value, + warn, + warnText, + onChange, + checked, + hideLabel, + labelText, + } = args ?? {}; + return html` + + + + + + `; + }, +}; + +const meta = { + title: 'Components/Radio Button', +}; + +export default meta; diff --git a/packages/web-components/src/components/radio-button/radio-button.ts b/packages/web-components/src/components/radio-button/radio-button.ts new file mode 100644 index 000000000000..06ca224bafbb --- /dev/null +++ b/packages/web-components/src/components/radio-button/radio-button.ts @@ -0,0 +1,402 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import HostListener from '../../globals/decorators/host-listener'; +import FocusMixin from '../../globals/mixins/focus'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import RadioGroupManager, { + NAVIGATION_DIRECTION, + ManagedRadioButtonDelegate, +} from '../../globals/internal/radio-group-manager'; +import { RADIO_BUTTON_LABEL_POSITION, RADIO_BUTTON_ORIENTATION } from './defs'; +import styles from './radio-button.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { RADIO_BUTTON_LABEL_POSITION }; + +/** + * Map of navigation direction by key for horizontal alignment. + */ +const navigationDirectionForKeyHorizontal = { + ArrowLeft: NAVIGATION_DIRECTION.BACKWARD, + Left: NAVIGATION_DIRECTION.BACKWARD, // IE + ArrowRight: NAVIGATION_DIRECTION.FORWARD, + Right: NAVIGATION_DIRECTION.FORWARD, // IE +}; + +/** + * Map of navigation direction by key for vertical alignment. + */ +const navigationDirectionForKeyVertical = { + ArrowUp: NAVIGATION_DIRECTION.BACKWARD, + Up: NAVIGATION_DIRECTION.BACKWARD, // IE + ArrowDown: NAVIGATION_DIRECTION.FORWARD, + Down: NAVIGATION_DIRECTION.FORWARD, // IE +}; + +/** + * The interface for `RadioGroupManager` for radio button. + */ +class RadioButtonDelegate implements ManagedRadioButtonDelegate { + /** + * The radio button to target. + */ + private _radio: HTMLInputElement; + + constructor(radio: HTMLInputElement) { + this._radio = radio; + } + + get checked() { + return this._radio.checked; + } + + set checked(checked) { + const { host } = this._radio.getRootNode() as ShadowRoot; + const { eventChange } = host.constructor as typeof CDSRadioButton; // eslint-disable-line no-use-before-define + (host as CDSRadioButton).checked = checked; + this._radio.tabIndex = checked ? 0 : -1; + host.dispatchEvent( + new CustomEvent(eventChange, { + bubbles: true, + composed: true, + detail: { + checked, + }, + }) + ); + } + + get tabIndex() { + return this._radio.tabIndex; + } + + set tabIndex(tabIndex) { + this._radio.tabIndex = tabIndex; + } + + get name() { + return this._radio.name; + } + + compareDocumentPosition(other: RadioButtonDelegate) { + return this._radio.compareDocumentPosition(other._radio); + } + + focus() { + this._radio.focus(); + } +} + +/** + * Radio button. + * + * @element cds-radio-button + * @fires cds-radio-button-changed - The custom event fired after this radio button changes its checked state. + */ +@customElement(`${prefix}-radio-button`) +class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) { + /** + * The radio group manager associated with the radio button. + */ + private _manager: RadioGroupManager | null = null; + + /** + * The interface for `RadioGroupManager` for radio button. + */ + private _radioButtonDelegate!: RadioButtonDelegate; + + /** + * The hidden radio button. + */ + @query('input') + private _inputNode!: HTMLInputElement; + + /** + * Handles `click` event on this element. + */ + @HostListener('click') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleClick = (event) => { + if ( + !(event.target as HTMLElement).matches( + (this.constructor as typeof CDSRadioButton)?.slugItem + ) + ) { + const { disabled, _radioButtonDelegate: radioButtonDelegate } = this; + if (radioButtonDelegate && !disabled && !this.disabledItem) { + this.checked = true; + if (this._manager) { + this._manager.select(radioButtonDelegate, this.readOnly); + } + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSRadioButton).eventChange, + { + bubbles: true, + composed: true, + detail: { + checked: this.checked, + }, + } + ) + ); + } + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSRadioButton).eventChange, + { + bubbles: true, + composed: true, + detail: { + checked: this.checked, + }, + } + ) + ); + } + }; + + /** + * Handles `keydown` event on this element. + */ + @HostListener('keydown') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleKeydown = (event: KeyboardEvent) => { + if ( + !(event.target as HTMLElement).matches( + (this.constructor as typeof CDSRadioButton)?.slugItem + ) + ) { + const { orientation, _radioButtonDelegate: radioButtonDelegate } = this; + const manager = this._manager; + if (radioButtonDelegate && manager) { + const navigationDirectionForKey = + orientation === RADIO_BUTTON_ORIENTATION.HORIZONTAL + ? navigationDirectionForKeyHorizontal + : navigationDirectionForKeyVertical; + const navigationDirection = navigationDirectionForKey[event.key]; + if (navigationDirection) { + manager.select( + manager.navigate(radioButtonDelegate, navigationDirection), + this.readOnly + ); + } + if (event.key === ' ' || event.key === 'Enter') { + manager.select(radioButtonDelegate, this.readOnly); + } + } + } + }; + + /** + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSRadioButton).slugItem + ) + : false + ); + + this._hasSlug = Boolean(hasContent); + const type = (hasContent[0] as HTMLElement).getAttribute('kind'); + (hasContent[0] as HTMLElement).setAttribute( + 'size', + type === 'inline' ? 'md' : 'mini' + ); + this.requestUpdate(); + } + + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + /** + * `true` if this radio button should be checked. + */ + @property({ type: Boolean, reflect: true }) + checked = false; + + /** + * `true` if the radio button is used in a data table + */ + @property({ type: Boolean, reflect: true, attribute: 'data-table' }) + dataTable = false; + + /** + * `true` if the radio button item should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabledItem = false; + + /** + * `true` if the radio button group should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * `true` if the label should be hidden. + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-label' }) + hideLabel = false; + + /** + * Specify if the currently value is invalid. + */ + @property({ type: Boolean, reflect: true }) + invalid = false; + + /** + * The label position. + */ + @property({ reflect: true, attribute: 'label-position' }) + labelPosition = RADIO_BUTTON_LABEL_POSITION.RIGHT; + + /** + * The label text. + */ + @property({ attribute: 'label-text' }) + labelText = ''; + + /** + * The `name` attribute for the `` for selection. + */ + @property() + name!: string; + + /** + * The orientation to lay out radio buttons. + */ + @property({ reflect: true }) + orientation = RADIO_BUTTON_ORIENTATION.HORIZONTAL; + + /** + * `true` if the radio button group should be disabled. + */ + @property({ type: Boolean, reflect: true }) + readOnly = false; + + /** + * The `value` attribute for the `` for selection. + */ + @property() + value!: string; + + disconnectedCallback() { + if (this._manager) { + this._manager.delete(this._radioButtonDelegate); + } + super.disconnectedCallback(); + } + + firstUpdated() { + this._radioButtonDelegate = new RadioButtonDelegate(this._inputNode); + } + + updated(changedProperties) { + const { + _hasSlug: hasSlug, + _inputNode: inputNode, + _radioButtonDelegate: radioButtonDelegate, + name, + } = this; + + if (changedProperties.has('checked') || changedProperties.has('name')) { + if (this.readOnly) { + this.checked = false; + } + if (!this._manager) { + this._manager = RadioGroupManager.get( + this.getRootNode({ composed: true }) as Document + ); + } + const { _manager: manager } = this; + if (changedProperties.has('name')) { + manager!.delete(radioButtonDelegate, changedProperties.get('name')); + if (name) { + manager!.add(radioButtonDelegate); + } + } + inputNode.setAttribute( + 'tabindex', + !name || !manager || !manager.shouldBeFocusable(radioButtonDelegate) + ? '-1' + : '0' + ); + } + hasSlug ? this.setAttribute('slug', '') : this.removeAttribute('slug'); + } + + render() { + const { + checked, + hideLabel, + labelText, + name, + value, + disabled, + disabledItem, + } = this; + const innerLabelClasses = classMap({ + [`${prefix}--radio-button__label-text`]: true, + [`${prefix}--visually-hidden`]: hideLabel, + }); + return html` + + + `; + } + + /** + * A selector that will return the slug item. + */ + static get slugItem() { + return `${prefix}-slug`; + } + + /** + * The name of the custom event fired after this radio button changes its checked state. + */ + static get eventChange() { + return `${prefix}-radio-button-changed`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; +} + +export default CDSRadioButton; diff --git a/packages/web-components/src/components/search/docs/overview.mdx b/packages/web-components/src/components/search/docs/overview.mdx new file mode 100644 index 000000000000..15d1cd9b1e4d --- /dev/null +++ b/packages/web-components/src/components/search/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/search/index.ts b/packages/web-components/src/components/search/index.ts new file mode 100644 index 000000000000..dcbe3d1eb4c7 --- /dev/null +++ b/packages/web-components/src/components/search/index.ts @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './search'; +import './search-skeleton'; diff --git a/packages/web-components/src/components/search/search-skeleton.ts b/packages/web-components/src/components/search/search-skeleton.ts new file mode 100644 index 000000000000..dcced40ad455 --- /dev/null +++ b/packages/web-components/src/components/search/search-skeleton.ts @@ -0,0 +1,38 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { INPUT_SIZE } from '../text-input/text-input'; +import styles from './search.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Skeleton of search. + */ +@customElement(`${prefix}-search-skeleton`) +class CDSSearchSkeleton extends LitElement { + /** + * The search box size. Corresponds to the attribute with the same name. + */ + @property({ reflect: true }) + size = INPUT_SIZE.MEDIUM; + + render() { + return html` + +
    + `; + } + + static styles = styles; +} + +export default CDSSearchSkeleton; diff --git a/packages/web-components/src/components/search/search.mdx b/packages/web-components/src/components/search/search.mdx new file mode 100644 index 000000000000..9bf070ad44ee --- /dev/null +++ b/packages/web-components/src/components/search/search.mdx @@ -0,0 +1,53 @@ +import { ArgTypes, Meta, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as SearchStories from './search.stories'; + + + +# Search + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/search) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/search) + +Search enables users to specify a word or a phrase to find particular relevant +pieces of content without the use of navigation. Search can be used as the +primary means of discovering content, or as a filter to aid the user in finding +content. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/search/index.js'; +``` + +{`${cdnJs({ components: ['search'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + +``` + +## Skeleton + +For the skeleton variation, utilize ``. + +```html + +``` + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `light` attribute). + + diff --git a/packages/web-components/src/components/search/search.scss b/packages/web-components/src/components/search/search.scss new file mode 100644 index 000000000000..fc3867ee1512 --- /dev/null +++ b/packages/web-components/src/components/search/search.scss @@ -0,0 +1,127 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/components/form'; +@use '@carbon/styles/scss/components/search' as *; + +// https://github.com/carbon-design-system/carbon/issues/11408 +@include search; + +:host(#{$prefix}-search) { + @extend .#{$prefix}--search; + + outline: none; +} + +:host(#{$prefix}-search[expandable]) { + @extend .#{$prefix}--search--expandable; +} + +:host(#{$prefix}-search[expandable][size='sm']) { + .#{$prefix}--search-magnifier { + block-size: $spacing-07; + inline-size: $spacing-07; + } +} + +:host(#{$prefix}-search[expandable][size='md']) { + .#{$prefix}--search-magnifier { + block-size: $spacing-08; + inline-size: $spacing-08; + } +} + +:host(#{$prefix}-search[expandable][size='lg']) { + .#{$prefix}--search-magnifier { + block-size: $spacing-09; + inline-size: $spacing-09; + } +} + +:host(#{$prefix}-search[expandable][expanded]) { + @extend .#{$prefix}--search--expanded; + + .#{$prefix}--search-input { + inline-size: 100%; + } + .#{$prefix}--search-magnifier { + pointer-events: none; + } +} + +:host(#{$prefix}-search[expandable][expanded][size='sm']) { + .#{$prefix}--search-input { + padding: 0 $spacing-07; + } +} + +:host(#{$prefix}-search[expandable][expanded][size='md']) { + .#{$prefix}--search-input { + padding: 0 $spacing-08; + } +} + +:host(#{$prefix}-search[expandable][expanded][size='lg']) { + .#{$prefix}--search-input { + padding: 0 $spacing-09; + } + + ::slotted(.#{$prefix}--search-magnifier) { + block-size: rem(48px); + inline-size: rem(48px); + } +} + +:host(#{$prefix}-search[disabled]) { + svg { + fill: $icon-on-color-disabled; + } + + .#{$prefix}--search-close { + outline: none; + pointer-events: none; + + &::before { + background: none; + } + } +} + +:host(#{$prefix}-search-skeleton) { + inline-size: 100%; + + .#{$prefix}--search-input { + @include skeleton; + + inline-size: 100%; + + &::placeholder { + color: transparent; + } + } +} + +:host(#{$prefix}-search[size='sm']), +:host(#{$prefix}-search-skeleton[size='sm']) { + @extend .#{$prefix}--search--sm; +} + +:host(#{$prefix}-search[size='md']), +:host(#{$prefix}-search-skeleton[size='md']) { + @extend .#{$prefix}--search--md; +} + +:host(#{$prefix}-search[size='lg']), +:host(#{$prefix}-search-skeleton[size='lg']) { + @extend .#{$prefix}--search--lg; +} diff --git a/packages/web-components/src/components/search/search.stories.ts b/packages/web-components/src/components/search/search.stories.ts new file mode 100644 index 000000000000..4129a6be39bd --- /dev/null +++ b/packages/web-components/src/components/search/search.stories.ts @@ -0,0 +1,195 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { INPUT_SIZE } from '../text-input/text-input'; +import './search-skeleton'; +import '../layer'; +import '../../../.storybook/templates/with-layer'; +import './index'; + +const sizes = { + [`Small size (${INPUT_SIZE.SMALL})`]: INPUT_SIZE.SMALL, + [`Medium size (${INPUT_SIZE.MEDIUM})`]: INPUT_SIZE.MEDIUM, + [`Large size (${INPUT_SIZE.LARGE})`]: INPUT_SIZE.LARGE, +}; + +const args = { + autoComplete: 'off', + closeButtonLabelText: 'Clear search input', + disabled: false, + labelText: 'Search', + placeholder: 'Placeholder text', + playgroundWidth: 300, + role: 'searchbox', + size: null, + type: 'text', + value: 'Default value', +}; + +const argTypes = { + autoComplete: { + control: 'text', + description: + 'Specify an optional value for the autocomplete property on the underlying <input>, defaults to "off".', + }, + closeButtonLabelText: { + control: 'text', + description: + 'Specify a label to be read by screen readers on the "close" button.', + }, + disabled: { + control: 'boolean', + description: + 'Specify whether the <input> should be disabled.', + }, + labelText: { + control: 'text', + description: 'Provide the label text for the Search icon.', + }, + placeholder: { + control: 'text', + description: + 'Provide an optional placeholder text for the Search. Note: if the label and placeholder differ, VoiceOver on Mac will read both.', + }, + playgroundWidth: { + control: { type: 'range', min: 300, max: 800, step: 50 }, + description: 'Playground width', + }, + role: { + control: 'text', + description: + 'Specify the role for the underlying <input>, defaults to searchbox.', + }, + size: { + control: 'select', + description: 'Specify the size of the Search.', + options: sizes, + }, + type: { + control: 'text', + description: + 'Optional prop to specify the type of the <input>.', + }, + value: { + control: 'text', + description: 'Specify the value of the <input>.', + }, +}; + +export const Default = { + render: () => { + return html` + + `; + }, +}; + +export const Disabled = { + render: () => { + return html` + + `; + }, +}; + +export const Expandable = { + render: () => { + return html` + + `; + }, +}; + +export const ExpandableWithLayer = { + render: () => { + return html` + + + + `; + }, +}; + +export const WithLayer = { + render: () => { + return html` + + + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + autoComplete, + closeButtonLabelText, + colorScheme, + disabled, + labelText, + placeholder, + playgroundWidth, + size, + role, + type, + value, + onInput, + } = args ?? {}; + + const mainDiv = document.querySelector('#main-content'); + + if (mainDiv) { + (mainDiv as HTMLElement).style.width = `${playgroundWidth}px`; + } + + return html` + + + `; + }, +}; + +const meta = { + title: 'Components/Search', +}; + +export default meta; diff --git a/packages/web-components/src/components/search/search.ts b/packages/web-components/src/components/search/search.ts new file mode 100644 index 000000000000..c30a5bf7dbbf --- /dev/null +++ b/packages/web-components/src/components/search/search.ts @@ -0,0 +1,276 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import Close16 from '@carbon/icons/lib/close/16'; +import Search16 from '@carbon/icons/lib/search/16'; +import { prefix } from '../../globals/settings'; +import ifNonEmpty from '../../globals/directives/if-non-empty'; +import FocusMixin from '../../globals/mixins/focus'; +import FormMixin from '../../globals/mixins/form'; +import { INPUT_SIZE } from '../text-input/text-input'; +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import styles from './search.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Search box. + * + * @element cds-search + * @csspart search-icon The search icon. + * @csspart label-text The label text. + * @csspart input The input box. + * @csspart close-button The close button. + * @csspart close-icon The close icon. + * @fires cds-search-input - The custom event fired after the search content is changed upon a user gesture. + */ +@customElement(`${prefix}-search`) +class CDSSearch extends HostListenerMixin(FocusMixin(FormMixin(LitElement))) { + /** + * Handles `input` event on the `` in the shadow DOM. + */ + private _handleInput(event: Event) { + const { target } = event; + const { value } = target as HTMLInputElement; + this.dispatchEvent( + new CustomEvent((this.constructor as typeof CDSSearch).eventInput, { + bubbles: true, + composed: true, + cancelable: false, + detail: { + value, + }, + }) + ); + this.value = value; + } + + /** + * Handles `click` event on the button to clear search box content. + */ + private _handleClearInputButtonClick() { + if (this.value) { + this.dispatchEvent( + new CustomEvent((this.constructor as typeof CDSSearch).eventInput, { + bubbles: true, + composed: true, + cancelable: false, + detail: { + value: '', + }, + }) + ); + this.value = ''; + + // set focus on back to input once search is cleared + const input = this.shadowRoot!.querySelector('input'); + (input as HTMLElement).focus(); + } + } + + /** + * Handles `focus` event on the button when the button can be expanded + */ + @HostListener('focus') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleExpand() { + if (this.expandable && !this.expanded) { + this.setAttribute('expanded', ''); + } + } + + /** + * Handles `focusout` event on the component to be closed after being expanded + * Will not close if there is a value typed within. + */ + @HostListener('focusout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleClose() { + if (this.expandable && this.expanded && !this.value) { + this.removeAttribute('expanded'); + } + } + + /** + * Handler for @slotchange, will only be ran if user sets an element under the "icon" slot. + * + * @private + */ + private _handleSlotChange() { + const icon = this.querySelector('svg'); + icon?.setAttribute('part', 'search-icon'); + icon?.setAttribute('class', `${prefix}--search-magnifier-icon`); + icon?.setAttribute('role', `img`); + this.hasCustomIcon = true; + } + + _handleFormdata(event: Event) { + const { formData } = event as any; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const { disabled, name, value } = this; + if (!disabled) { + formData.append(name, value); + } + } + + /** + * Specify an optional value for the autocomplete property on the underlying , + * defaults to "off" + */ + @property({ attribute: 'autocomplete' }) + autoComplete = 'off'; + + /** + * Specify a label to be read by screen readers on the "close" button + */ + @property({ attribute: 'close-button-label-text' }) + closeButtonLabelText = ''; + + /** + * `true` if the search box should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * `true` if the search bar can be expandable + */ + @property({ type: Boolean, reflect: true }) + expandable = false; + + /** + * `true` if the expandable search has been expanded + */ + @property({ type: Boolean, reflect: true }) + expanded = false; + + @property({ type: Boolean }) + hasCustomIcon = false; + + /** + * The label text. + */ + @property({ attribute: 'label-text' }) + labelText = ''; + + /** + * The form name in `FormData`. + */ + @property() + name = ''; + + /** + * Specify the role for the underlying , defaults to searchbox + */ + @property() + role = ''; + + /** + * The placeholder text. + */ + @property() + placeholder = 'Search'; + + /** + * The search box size. + */ + @property({ reflect: true }) + size = INPUT_SIZE.MEDIUM; + + /** + * The `` name. + */ + @property() + type = ''; + + /** + * The value. + */ + @property({ type: String }) + value = ''; + + render() { + const { + autoComplete, + closeButtonLabelText, + disabled, + hasCustomIcon, + labelText, + name, + placeholder, + role, + type, + value = '', + _handleInput: handleInput, + _handleClearInputButtonClick: handleClearInputButtonClick, + _handleSlotChange: handleSlotChange, + } = this; + const clearClasses = classMap({ + [`${prefix}--search-close`]: true, + [`${prefix}--search-close--hidden`]: !this.value, + }); + return html` +
    + + ${hasCustomIcon + ? html`` + : html`${Search16({ + part: 'search-icon', + class: `${prefix}--search-magnifier-icon`, + role: 'img', + })}`} + +
    + + + + `; + } + + /** + * The name of the custom event fired after the search content is changed upon a user gesture. + */ + static get eventInput() { + return `${prefix}-search-input`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSSearch; diff --git a/packages/web-components/src/components/select/docs/overview.mdx b/packages/web-components/src/components/select/docs/overview.mdx new file mode 100644 index 000000000000..443c0084469e --- /dev/null +++ b/packages/web-components/src/components/select/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/select/index.ts b/packages/web-components/src/components/select/index.ts new file mode 100644 index 000000000000..949958cbf02f --- /dev/null +++ b/packages/web-components/src/components/select/index.ts @@ -0,0 +1,13 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './select'; +import './select-item'; +import './select-item-group'; +import './select-skeleton'; diff --git a/packages/web-components/src/components/select/select-item-group.ts b/packages/web-components/src/components/select/select-item-group.ts new file mode 100644 index 000000000000..b303be07679a --- /dev/null +++ b/packages/web-components/src/components/select/select-item-group.ts @@ -0,0 +1,35 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * An option group in select box. + * + * @element cds-select-item-group + */ +@customElement(`${prefix}-select-item-group`) +class CDSSelectItemGroup extends LitElement { + /** + * `true` to disable this option. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * The label. + */ + @property({ reflect: true }) + label = ''; +} + +export default CDSSelectItemGroup; diff --git a/packages/web-components/src/components/select/select-item.ts b/packages/web-components/src/components/select/select-item.ts new file mode 100644 index 000000000000..f5154265899e --- /dev/null +++ b/packages/web-components/src/components/select/select-item.ts @@ -0,0 +1,47 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * An option in select box. + * + * @element cds-select-item + */ +@customElement(`${prefix}-select-item`) +class CDSSelectItem extends LitElement { + /** + * `true` to disable this option. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * The label. If this is not specified, the child text content is used. + */ + @property({ reflect: true }) + label = ''; + + /** + * `true` to select this option. + */ + @property({ type: Boolean, reflect: true }) + selected = false; + + /** + * The value. + */ + @property({ reflect: true }) + value = ''; +} + +export default CDSSelectItem; diff --git a/packages/web-components/src/components/select/select-skeleton.ts b/packages/web-components/src/components/select/select-skeleton.ts new file mode 100644 index 000000000000..ee13831d55ef --- /dev/null +++ b/packages/web-components/src/components/select/select-skeleton.ts @@ -0,0 +1,39 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { prefix } from '../../globals/settings'; +import styles from './select.scss?lit'; + +/** + * Skeleton of number input. + */ +@customElement(`${prefix}-select-skeleton`) +class CDSSelectSkeleton extends LitElement { + /** + * `true` if the label should be hidden. Corresponds to the attribute with the same name. + */ + @property({ type: Boolean, reflect: true, attribute: 'hide-label' }) + hideLabel = false; + + render() { + const { hideLabel } = this; + return html` + ${!hideLabel && + html` `} +
    + `; + } + + static styles = styles; +} + +export default CDSSelectSkeleton; diff --git a/packages/web-components/src/components/select/select.mdx b/packages/web-components/src/components/select/select.mdx new file mode 100644 index 000000000000..064821bddccb --- /dev/null +++ b/packages/web-components/src/components/select/select.mdx @@ -0,0 +1,72 @@ +import { ArgTypes, Meta, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as SelectStories from './select.stories'; + + + +# Select + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/select) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/select) + +The select component allows users to choose one option from a list. It is used +in forms for users to submit data. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/select/index.js'; +``` + +{`${cdnJs({ components: ['select'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + + Option 1 + Option 2 + + + Option 3 + Option 4 + Option 5 + + +``` + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `autofocus` attribute). + + + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `disabled` attribute). + + + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `disabled` attribute). + + diff --git a/packages/web-components/src/components/select/select.scss b/packages/web-components/src/components/select/select.scss new file mode 100644 index 000000000000..43bb90d5f6df --- /dev/null +++ b/packages/web-components/src/components/select/select.scss @@ -0,0 +1,89 @@ +// +// Copyright IBM Corp. 2020, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/components/select'; + +:host(#{$prefix}-select) { + @extend .#{$prefix}--select; + + outline: none; + + ::slotted(#{$prefix}-slug) { + position: absolute; + inset-block-start: 50%; + inset-inline-end: $spacing-08; + } + + ::slotted(#{$prefix}-slug:not([revert-active])) { + transform: translateY(-50%); + } +} + +:host(#{$prefix}-select[disabled]) { + @extend .#{$prefix}--select--disabled; +} + +:host(#{$prefix}-select[invalid]) { + @extend .#{$prefix}--select--invalid; +} + +:host(#{$prefix}-select[readonly]) select { + pointer-events: none; +} + +:host(#{$prefix}-select[inline][warn]) { + .#{$prefix}--form__helper-text, + .#{$prefix}--label { + align-self: flex-start; + margin-block-start: 0.8125rem; + } + + select { + padding-inline-end: 3.5rem; + } + + .#{$prefix}--select__invalid-icon--warning { + inset-inline-end: $spacing-07; + } +} + +:host(#{$prefix}-select[pagination]) { + .#{$prefix}--label { + margin: 0; + } + + .#{$prefix}--select-input { + padding: 0 2.25rem 0 $spacing-05; + + &:focus { + background-color: transparent; + } + } + + .#{$prefix}--select__arrow { + inset-block-start: 50%; + transform: translate(-#{$spacing-03}, -50%); + } +} + +:host(#{$prefix}-select[pagination][left-select]) { + .#{$prefix}--select-input { + border-inline-end: 1px solid $border-subtle; + } +} + +:host(#{$prefix}-select[warn]), +:host(#{$prefix}-select[invalid]) { + ::slotted(#{$prefix}-slug) { + inset-inline-end: $spacing-10; + } +} diff --git a/packages/web-components/src/components/select/select.stories.ts b/packages/web-components/src/components/select/select.stories.ts new file mode 100644 index 000000000000..b583dc938220 --- /dev/null +++ b/packages/web-components/src/components/select/select.stories.ts @@ -0,0 +1,251 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +// Below path will be there when an application installs `carbon-web-components` package. +// In our dev env, we auto-generate the file and re-map below path to to point to the generated file. +// @ts-ignore +import { prefix } from '../../globals/settings'; +import { INPUT_SIZE } from '../text-input/text-input'; +import './index'; +import '../form/form-item'; +import '../layer'; +import '../../../.storybook/templates/with-layer'; + +const sizes = { + [`Small size (${INPUT_SIZE.SMALL})`]: INPUT_SIZE.SMALL, + [`Medium size (${INPUT_SIZE.MEDIUM})`]: INPUT_SIZE.MEDIUM, + [`Large size (${INPUT_SIZE.LARGE})`]: INPUT_SIZE.LARGE, +}; + +const args = { + disabled: false, + helperText: 'Optional helper text', + hideLabel: false, + inline: false, + invalid: false, + invalidText: 'Error message', + labelText: 'Select an option', + placeholder: 'Choose an option', + size: INPUT_SIZE.MEDIUM, + readOnly: false, + warn: false, + warnText: 'Warning message', + value: '', +}; + +const argTypes = { + disabled: { + control: 'boolean', + description: 'Specify whether the control is disabled.', + }, + helperText: { + control: 'text', + description: + 'Provide text that is used alongside the control label for additional help.', + }, + hideLabel: { + control: 'boolean', + description: 'Specify whether the label should be hidden, or not.', + }, + inline: { + control: 'boolean', + description: 'Specify whether you want the inline version of this control.', + }, + invalid: { + control: 'boolean', + description: 'Specify if the currently value is invalid.', + }, + invalidText: { + control: 'text', + description: 'Message which is displayed if the value is invalid.', + }, + labelText: { + control: 'text', + description: + 'Provide label text to be read by screen readers when interacting with the control.', + }, + placeholder: { + control: 'text', + description: + 'Placeholder text to be used with the <input>.', + }, + size: { + control: 'select', + description: 'Specify the size of the Select Input.', + options: sizes, + }, + readOnly: { + control: 'boolean', + description: 'Whether the select should be read-only.', + }, + warn: { + control: 'boolean', + description: 'Specify whether the control is currently in warning state.', + }, + warnText: { + control: 'text', + description: + 'Provide the text that is displayed when the control is in warning state.', + }, + value: { + control: 'text', + description: 'The value of the selected item.', + }, + onInput: { + action: `${prefix}-select-selected`, + }, +}; + +export const Default = { + render: () => { + return html` + + + + Option 1 + Option 2 + + + Option 3 + Option 4 + Option 5 + + + + `; + }, +}; + +export const Inline = { + render: () => { + return html` + + + + Option 1 + Option 2 + + + Option 3 + Option 4 + Option 5 + + + + `; + }, +}; + +export const Skeleton = { + parameters: { + percy: { + skip: true, + }, + }, + render: () => html` `, +}; + +export const WithLayer = { + render: () => { + return html` + + + + Option 1 + Option 2 + + + Option 3 + Option 4 + Option 5 + + + + `; + }, +}; + +export const Playground = { + args, + argTypes, + render: (args) => { + const { + disabled, + helperText, + hideLabel, + inline, + invalid, + invalidText, + labelText, + name, + placeholder, + size, + readOnly, + warn, + warnText, + value, + children = html` + + Option 1 + Option 2 + + + Option 3 + Option 4 + Option 5 + + `, + onInput, + } = args ?? {}; + return html` + + + ${children} + + + `; + }, +}; + +const meta = { + decorators: [ + (story) => { + return html`
    ${story()}
    `; + }, + ], + title: 'Components/Select', +}; + +export default meta; diff --git a/packages/web-components/src/components/select/select.ts b/packages/web-components/src/components/select/select.ts new file mode 100644 index 000000000000..49344e3e6ba7 --- /dev/null +++ b/packages/web-components/src/components/select/select.ts @@ -0,0 +1,513 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import ChevronDown16 from '@carbon/icons/lib/chevron--down/16'; +import WarningFilled16 from '@carbon/icons/lib/warning--filled/16'; +import WarningAltFilled16 from '@carbon/icons/lib/warning--alt--filled/16'; +import { prefix } from '../../globals/settings'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import FormMixin from '../../globals/mixins/form'; +import { filter } from '../../globals/internal/collection-helpers'; +import { INPUT_SIZE } from '../text-input/text-input'; +import styles from './select.scss?lit'; +import ifNonEmpty from '../../globals/directives/if-non-empty'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Select box. + * + * @element cds-select + * @fires cds-select-selected + * The name of the custom event fired after an item is selected. + * @slot helper-text - The helper text. + * @slot label-text - The label text. + * @slot validity-message - The validity message. If present and non-empty, this input shows the UI of its invalid state. + */ +@customElement(`${prefix}-select`) +class CDSSelect extends FormMixin(LitElement) { + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + /** + * The mutation observer DOM mutation. + */ + private _observerMutation: MutationObserver | null = null; + + /** + * The `value` for placeholder `
    +
    + + `; + } + + /** + * The name of the custom event fired after this selectable tile changes its selected state. + */ + static get eventRadioChange() { + return `${prefix}-radio-tile-selected`; + } +} + +export default CDSRadioTile; diff --git a/packages/web-components/src/components/tile/selectable-tile.ts b/packages/web-components/src/components/tile/selectable-tile.ts new file mode 100644 index 000000000000..7397ed95a1f3 --- /dev/null +++ b/packages/web-components/src/components/tile/selectable-tile.ts @@ -0,0 +1,230 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html, svg } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import Checkbox16 from '@carbon/icons/lib/checkbox/16'; +import CheckboxCheckedFilled16 from '@carbon/icons/lib/checkbox--checked--filled/16'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import { TILE_COLOR_SCHEME } from './defs'; +import styles from './tile.scss?lit'; +import HostListener from '../../globals/decorators/host-listener'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Multi-selectable tile. + * + * @element cds-selectable-tile + * @fires cds-selectable-tile-changed - The custom event fired after this selectable tile changes its selected state. + */ +@customElement(`${prefix}-selectable-tile`) +class CDSSelectableTile extends HostListenerMixin(FocusMixin(LitElement)) { + @query('input') + protected _inputNode!: HTMLInputElement; + + /** + * The `type` attribute of the ``. + */ + protected _inputType = 'checkbox'; + + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + /** + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSSelectableTile)?.slugItem + ) + : false + ); + if (hasContent.length > 0) { + this._hasSlug = Boolean(hasContent); + (hasContent[0] as HTMLElement).setAttribute('size', 'xs'); + } + this.requestUpdate(); + } + + /** + * Handles `change` event on the `` in the shadow DOM. + */ + protected _handleChange() { + this.selected = this._inputNode.checked; + + const selected = this.selected; + const { eventChange } = this.constructor as typeof CDSSelectableTile; + this.dispatchEvent( + new CustomEvent(eventChange, { + bubbles: true, + composed: true, + detail: { + selected, + }, + }) + ); + } + + /** + * Handles the rendering of the icon. + */ + protected _renderIcon() { + const { selected, checkmarkLabel } = this; + + return html` ${selected + ? CheckboxCheckedFilled16({ + children: !checkmarkLabel + ? undefined + : svg`${checkmarkLabel}`, + }) + : Checkbox16({ + children: !checkmarkLabel + ? undefined + : svg`${checkmarkLabel}`, + })}`; + } + + /** + * Listener function for keyboard interaction. + * + * @param event to get the key pressed + */ + @HostListener('keydown') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleKeydown = (event: KeyboardEvent) => { + const { key } = event; + + if ( + key === ' ' || + (key === 'Enter' && + !(event.target as HTMLElement)?.matches( + (this.constructor as typeof CDSSelectableTile).slugItem + )) + ) { + this.selected = !this.selected; + } + }; + + /** + * The a11y text for the checkmark icon of the selected state. + */ + @property({ attribute: 'checkmark-label' }) + checkmarkLabel!: string; + + /** + * The color scheme. + */ + @property({ attribute: 'color-scheme', reflect: true }) + colorScheme = TILE_COLOR_SCHEME.REGULAR; + + /** + * Specify if the `SeletableTile` component should be rendered with rounded corners. + * Only valid when `slug` prop is present + */ + @property({ type: Boolean, attribute: 'has-rounded-corners' }) + hasRoundedCorners = false; + + /** + * The form name. + */ + @property() + name!: string; + + /** + * `true` to show the selected state. + */ + @property({ type: Boolean, reflect: true }) + selected = false; + + /** + * The form value. + */ + @property() + value!: string; + + updated() { + if (this._hasSlug) { + this.setAttribute('slug', ''); + } else { + this.removeAttribute('slug'); + } + } + + render() { + const { + colorScheme, + hasRoundedCorners: hasRoundedCorners, + name, + selected, + value, + _inputType: inputType, + _handleChange: handleChange, + _hasSlug: hasSlug, + } = this; + const classes = classMap({ + [`${prefix}--tile`]: true, + [`${prefix}--tile--selectable`]: true, + [`${prefix}--tile--is-selected`]: selected, + [`${prefix}--tile--${colorScheme}`]: colorScheme, + [`${prefix}--tile--slug-rounded`]: hasSlug && hasRoundedCorners, + }); + return html` + + + + `; + } + + /** + * A selector that will return the slug item. + */ + static get slugItem() { + return `${prefix}-slug`; + } + + /** + * The name of the custom event fired after this selectable tile changes its selected state. + */ + static get eventChange() { + return `${prefix}-selectable-tile-changed`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + + static styles = styles; +} + +export default CDSSelectableTile; diff --git a/packages/web-components/src/components/tile/tile-group.ts b/packages/web-components/src/components/tile/tile-group.ts new file mode 100644 index 000000000000..9c1543c73e6a --- /dev/null +++ b/packages/web-components/src/components/tile/tile-group.ts @@ -0,0 +1,313 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { NAVIGATION_DIRECTION } from '../../globals/internal/radio-group-manager'; +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import styles from './tile.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Map of navigation direction by key. + */ +const navigationDirectionForKey = { + ArrowUp: NAVIGATION_DIRECTION.BACKWARD, + Up: NAVIGATION_DIRECTION.BACKWARD, // IE + ArrowDown: NAVIGATION_DIRECTION.FORWARD, + Down: NAVIGATION_DIRECTION.FORWARD, // IE +}; + +/** + * Tile group. + * + * @element cds-tile-group + * @fires cds-current-radio-tile-selection + * The name of the custom event fired after a radio tile changes its selected state. + * @fires cds-current-selectable-tile-selections + * The name of the custom event fired after a selectable tile changes its selected state. + */ +@customElement(`${prefix}-tile-group`) +class CDSTileGroup extends HostListenerMixin(LitElement) { + private _handleRadioClick(event) { + const { target } = event; + const { currentRadioSelection } = this; + const { eventCurrentRadioTileSelection } = this + .constructor as typeof CDSTileGroup; + + if (!currentRadioSelection) { + this.currentRadioSelection = target; + } else if (currentRadioSelection !== target) { + currentRadioSelection.toggleAttribute('selected'); + this.currentRadioSelection = target; + } + + this.dispatchEvent( + new CustomEvent(eventCurrentRadioTileSelection, { + bubbles: true, + composed: true, + detail: { + target, + }, + }) + ); + } + + private _handleSelectableClick(event) { + const { target } = event; + const { currentSelections } = this; + const { eventCurrentSelectableTilesSelection } = this + .constructor as typeof CDSTileGroup; + + if (!currentSelections.includes(target)) { + currentSelections.push(target); + } else { + currentSelections.splice(currentSelections.indexOf(target), 1); + } + (target as HTMLElement).toggleAttribute('selected'); + + this.dispatchEvent( + new CustomEvent(eventCurrentSelectableTilesSelection, { + bubbles: true, + composed: true, + detail: { + currentSelections, + }, + }) + ); + event.stopPropagation(); + event.preventDefault(); + } + + /** + * Click listener to ensure selectability. + * + * @param event click + */ + @HostListener('click') + // @ts-ignore + private _handleTileSelect(event: Event) { + if (this.radioTiles.length) { + this._handleRadioClick(event); + } else { + this._handleSelectableClick(event); + } + } + + /** + * Handle keyboard navigation for radio tiles + * + * @param nextSibling to focus on + */ + private _handleKeydownRadio(nextSibling) { + const { currentRadioSelection } = this; + + const { eventCurrentRadioTileSelection } = this + .constructor as typeof CDSTileGroup; + + if (currentRadioSelection) { + currentRadioSelection.toggleAttribute('selected'); + } + nextSibling.focus(); + nextSibling.toggleAttribute('selected'); + this.currentRadioSelection = nextSibling; + + this.dispatchEvent( + new CustomEvent(eventCurrentRadioTileSelection, { + bubbles: true, + composed: true, + detail: { + nextSibling, + }, + }) + ); + } + + /** + * Handle keyboard navigation for selectable tiles + * + * @param event to get target + * @param nextSibling to focus on + */ + private _handleKeydownSelectable(event, nextSibling?) { + const { target } = event; + const { currentSelections } = this; + const { eventCurrentSelectableTilesSelection } = this + .constructor as typeof CDSTileGroup; + + if (nextSibling) { + nextSibling.focus(); + } else { + if (!currentSelections.includes(target)) { + currentSelections.push(target); + } else { + currentSelections.splice(currentSelections.indexOf(target), 1); + } + + this.dispatchEvent( + new CustomEvent(eventCurrentSelectableTilesSelection, { + bubbles: true, + composed: true, + detail: { + currentSelections, + }, + }) + ); + } + } + + /** + * Keyboard listener to ensure keyboard navigation. + * + * @param event to get key pressed + */ + @HostListener('keydown') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleKeydown = (event: KeyboardEvent) => { + const { target, key } = event; + const { radioTiles, selectableTiles } = this; + const navigationDirection = navigationDirectionForKey[key]; + + const tiles = radioTiles.length ? radioTiles : selectableTiles; + const currentIndex = [...tiles].findIndex((e) => e == target); + const nextIndex = currentIndex + navigationDirection; + const nextSibling = + nextIndex !== -1 + ? tiles[nextIndex % tiles.length] + : tiles[tiles.length - 1]; + + if (navigationDirection) { + event.preventDefault(); // Prevent default (scrolling) behavior + + if (this.radioTiles.length) { + this._handleKeydownRadio(nextSibling); + } else { + this._handleKeydownSelectable(event, nextSibling); + } + } else if (key === ' ' || key === 'Enter') { + this._handleKeydownSelectable(event); + } + }; + + /** + * Focus listener to focus on selected element upon focusing + * + * @param event to get focused + */ + @HostListener('focusin') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleFocus = (event: KeyboardEvent) => { + const { relatedTarget, target } = event as any; + + if (this.radioTiles.length) { + if (!this.currentRadioSelection) { + target.toggleAttribute('selected'); + this.currentRadioSelection = target; + } else if ( + !relatedTarget?.matches( + (this.constructor as typeof CDSTileGroup).selectorRadioTile + ) && + target !== this.currentRadioSelection + ) { + this.currentRadioSelection.focus(); + } + } + }; + + /** + * Provide an optional className to be applied to the component + */ + @property({ reflect: true, attribute: 'fieldset-class-name' }) + fieldsetClassName; + + /** + * Specify whether the group is disabled + */ + @property({ reflect: true, type: Boolean }) + disabled; + + @property() + currentRadioSelection; + + @property() + currentSelections = [] as any; + + @property() + radioTiles; + + @property() + selectableTiles; + + firstUpdated() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'group'); + } + + if (!this.radioTiles) { + this.radioTiles = this.querySelectorAll( + (this.constructor as typeof CDSTileGroup).selectorRadioTile + ); + } + + if (!this.selectableTiles) { + this.selectableTiles = this.querySelectorAll( + (this.constructor as typeof CDSTileGroup).selectorSelectableTile + ); + } + + if (this.disabled) { + this.radioTiles.forEach((e) => e.toggleAttribute('disabled')); + this.selectableTiles.forEach((e) => e.toggleAttribute('disabled')); + } + } + + render() { + const { fieldsetClassName, disabled } = this; + return html` +
    + + +
    + `; + } + + /** + * A selector that selects a radio tile component. + */ + static get selectorRadioTile() { + return `${prefix}-radio-tile`; + } + + /** + * A selector that selects a selectable tile component. + */ + static get selectorSelectableTile() { + return `${prefix}-selectable-tile`; + } + + /** + * The name of the custom event fired after a radio tile changes its selected state. + */ + static get eventCurrentRadioTileSelection() { + return `${prefix}-current-radio-tile-selection`; + } + + /** + * The name of the custom event fired after a radio tile changes its selected state. + */ + static get eventCurrentSelectableTilesSelection() { + return `${prefix}-current-selectable-tile-selections`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSTileGroup; diff --git a/packages/web-components/src/components/tile/tile.mdx b/packages/web-components/src/components/tile/tile.mdx new file mode 100644 index 000000000000..c6d3efaccb06 --- /dev/null +++ b/packages/web-components/src/components/tile/tile.mdx @@ -0,0 +1,166 @@ +import { ArgTypes, Markdown } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; + +# Tile + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/tile) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/tile) + +Tiles are a highly flexible component for displaying a wide variety of content, +including informational, getting started, how-to, next steps, and more. + +Carbon ships a basic tile structure that responds to the grid. Tiles have no +pre-set styles for the content within them. You can customize tiles to fit your +specific use case. + +When using a call-to-action (CTA) within a tile, use a secondary button. Primary +buttons should be reserved for the most important action a user can take on the +page. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/tile/index.js'; +``` + +{`${cdnJs({ components: ['tile'] })}`} +{`${cdnCss()}`} + +### HTML + +```html +Default tile +``` + +## Read-only tile (default) + +Read-only tiles are used to display information to the user, such as features or +services offered. Read-only tiles are often seen on marketing pages to promote +content. These tiles can have internal calls-to-action (CTAs), such as a button +or a link. + +## Clickable tile + +Clickable tiles can be used as navigational items, where the entire tile is a +clickable state, which redirects the user to a new page. Clickable tiles cannot +contain separate internal CTAs. + +```html + Clickable tile +``` + +## `` attributes and properties + + + +## Radio tile + +Radio tiles work like a radio button, where the entire tile is a click target. +Radio tiles may contain internal CTAs (like links to docs) if the internal CTA +is given its own click target. Radio tiles work well for presenting options to a +user in a structured manner, such as a set of pricing plans. + +```html + + Single-select Tile + Single-select Tile + Single-select Tile + +``` + +## `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `selected` attribute). + + + +## Selectable tile + +```html + + Selectable Tile + +``` + +## `` attributes and properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `selected` attribute). + + + +## Multi Select + +```html + + + Selectable Tile 1 + + + Selectable Tile 2 + + + Selectable Tile 3 + + +``` + +## Capturing tile selection + +If using the `cds-tile-group` component alongside either Radio or Selectable +tiles, you can capture the events using an event listener for the following +event names: + +- For radio tiles, capture: + - `cds-current-radio-tile-selection` +- For selectable tiles, capture: + - `cds-current-selectable-tile-selections` + +```javascript +document.addEventListener('cds-current-radio-tile-selection', (event) => { + // use values from the detail object within the event +}); +``` + +## Expandable tile + +Expandable tiles are helpful for hiding/showing larger amounts of content to a +user. They can only be stacked in a single column, and cannot live in a row or +horizontal grid. When expanded, tiles push content down the page. Expandable +tiles may contain internal CTAs (like links to docs) if the internal CTA is +given its own click target. + +```html + + + Above the fold content here + + + Below the fold content here + + +``` + +If the desired behavior is expanding only upon clicking the button with the +caret icon, use the `with-interactive` attribute instead. + +## `` attributes, properties and events + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `expanded` attribute). + + diff --git a/packages/web-components/src/components/tile/tile.scss b/packages/web-components/src/components/tile/tile.scss new file mode 100644 index 000000000000..845a9d64c6de --- /dev/null +++ b/packages/web-components/src/components/tile/tile.scss @@ -0,0 +1,251 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/utilities/focus-outline' as *; +@use '@carbon/styles/scss/motion' as *; +@use '@carbon/styles/scss/components/tile/index' as *; +@use '@carbon/styles/scss/components/link/index' as *; +@use '@carbon/styles/scss/components/form/index' as *; +@use '@carbon/styles/scss/utilities/ai-gradient' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/layout' as *; + +:host(#{$prefix}-tile) { + @extend .#{$prefix}--tile; + @include emit-layout-tokens(); + + ::slotted(.#{$prefix}--link) { + @extend .#{$prefix}--link; + } +} + +:host(#{$prefix}-tile-group) { + @extend .#{$prefix}--tile-group; + + background: transparent; + + fieldset { + border: none; + } +} + +:host(#{$prefix}-clickable-tile) { + @include emit-layout-tokens(); + + display: grid; + outline: none; + + .#{$prefix}--link--disabled { + display: block; + } + + .#{$prefix}--tile { + // Overrides what `.#{$prefix}--link` defines + padding: $spacing-05; + outline: $spacing-01 solid transparent; + } + + .#{$prefix}--tile--clickable { + @extend .#{$prefix}--tile--clickable; + // Overrides what `.#{$prefix}--link` defines + display: block; + transition: $duration-moderate-01 motion(standard, productive); + + &:focus { + @include focus-outline('outline'); + } + } + + &:hover { + .#{$prefix}--tile--clickable { + color: inherit; + } + } + + ::slotted(#{$prefix}-slug) { + pointer-events: none; + } +} + +:host(#{$prefix}-radio-tile) { + @include emit-layout-tokens(); + + display: block; + + margin-block-end: $spacing-03; + outline: none; +} + +:host(#{$prefix}-selectable-tile) { + @include emit-layout-tokens(); + + position: relative; + + display: content; + outline: none; + + .#{$prefix}--tile__chevron { + @extend .#{$prefix}--tile__chevron; + } +} + +:host(#{$prefix}-radio-tile), +:host(#{$prefix}-selectable-tile) { + .#{$prefix}--tile-input:checked + ~ .#{$prefix}--tile--selectable + .#{$prefix}--tile__checkmark { + opacity: 1; + } +} + +:host(#{$prefix}-clickable-tile) ::slotted(*), +:host(#{$prefix}-selectable-tile) ::slotted(*) { + position: relative; + z-index: 1; + cursor: pointer; +} + +:host(#{$prefix}-expandable-tile) { + @extend .#{$prefix}--tile; + @extend .#{$prefix}--tile--expandable; + @include emit-layout-tokens(); + + ::slotted(#{$prefix}-tile-below-the-fold-content) { + @extend .#{$prefix}--tile-content__below-the-fold; + } + + .#{$prefix}-ce--expandable-tile--below-the-fold-content { + max-block-size: 0; + transition: max-height $duration-fast-02 motion(standard, productive); + } +} + +:host(#{$prefix}-expandable-tile[expanded]) { + @extend .#{$prefix}--tile--is-expanded; + + ::slotted(#{$prefix}-tile-below-the-fold-content) { + opacity: 1; + transition: $duration-fast-02 motion(standard, productive); + visibility: visible; + } +} + +:host(#{$prefix}-expandable-tile[with-interactive]) { + cursor: default; + transition: max-height $duration-moderate-01 motion(standard, productive); + + &:hover { + background-color: $layer; + } + + &:focus { + outline: none; + } +} + +:host(#{$prefix}-expandable-tile:not([with-interactive])) { + .#{$prefix}--tile__chevron { + border: none; + background: none; + cursor: pointer; + outline: none; + } +} + +:host(#{$prefix}-tile[color-scheme='light']), +:host(#{$prefix}-expandable-tile[color-scheme='light']) { + @extend .#{$prefix}--tile--light; +} + +// Slug styles +:host(#{$prefix}-tile[slug]), +:host(#{$prefix}-expandable-tile[slug]), +:host(#{$prefix}-clickable-tile[slug]) .#{$prefix}--tile, +:host(#{$prefix}-selectable-tile[slug]) .#{$prefix}--tile { + @include ai-popover-gradient('default', 0, 'layer'); + + border: 1px solid transparent; + box-shadow: inset 0 -80px 70px -65px $ai-inner-shadow, + 0 24px 40px -24px $ai-drop-shadow; +} + +:host(#{$prefix}-tile), +:host(#{$prefix}-expandable-tile), +:host(#{$prefix}-clickable-tile), +:host(#{$prefix}-selectable-tile) { + ::slotted(#{$prefix}-slug) { + position: absolute; + inset-block-start: $spacing-05; + inset-inline-end: $spacing-05; + } +} + +:host(#{$prefix}-selectable-tile) ::slotted(#{$prefix}-slug) { + inset-inline-end: $spacing-08; +} + +:host(#{$prefix}-expandable-tile[slug]):hover { + @include ai-popover-gradient('default', 0, 'layer'); +} + +:host(#{$prefix}-selectable-tile[slug]) .#{$prefix}--tile::before, +:host(#{$prefix}-selectable-tile[slug]) .#{$prefix}--tile::after, +:host(#{$prefix}-clickable-tile[slug]) .#{$prefix}--tile::before { + position: absolute; + display: block; + block-size: 100%; + content: ''; + inline-size: 100%; + inset-block-start: 0; + inset-inline-start: 0; + opacity: 0; + transition: opacity $duration-fast-02 motion(standard, productive); +} + +:host(#{$prefix}-selectable-tile[slug]) .#{$prefix}--tile::before, +:host(#{$prefix}-clickable-tile[slug]) .#{$prefix}--tile::before { + @include ai-popover-gradient('hover', 0, 'layer'); + + box-shadow: inset 0 -80px 70px -65px $ai-inner-shadow; +} + +:host(#{$prefix}-selectable-tile[slug]) .#{$prefix}--tile:hover::before, +:host(#{$prefix}-clickable-tile[slug]) .#{$prefix}--tile:hover::before { + opacity: 1; +} + +:host(#{$prefix}-selectable-tile[slug]) .#{$prefix}--tile--is-selected { + border: 1px solid $layer-selected-inverse; + .#{$prefix}--tile__checkmark { + z-index: 1; + } +} + +:host(#{$prefix}-selectable-tile[slug]) .#{$prefix}--tile--is-selected::after { + @include ai-popover-gradient('selected', 0, 'layer'); + + box-shadow: inset 0 -80px 70px -65px $ai-inner-shadow; +} + +:host(#{$prefix}-expandable-tile[slug]) { + overflow: visible; +} + +:host(#{$prefix}-tile[slug][has-rounded-corners]), +:host(#{$prefix}-expandable-tile[slug][has-rounded-corners]), +:host(#{$prefix}-clickable-tile[slug][has-rounded-corners]), +:host(#{$prefix}-selectable-tile[slug][has-rounded-corners]) { + @extend .#{$prefix}--tile--slug-rounded; + + .#{$prefix}--tile__chevron { + border-end-end-radius: $spacing-03; + } +} diff --git a/packages/web-components/src/components/tile/tile.stories.ts b/packages/web-components/src/components/tile/tile.stories.ts new file mode 100644 index 000000000000..5e9089ecb436 --- /dev/null +++ b/packages/web-components/src/components/tile/tile.stories.ts @@ -0,0 +1,372 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { TILE_COLOR_SCHEME } from './tile'; +import './index'; +import storyDocs from './tile.mdx'; +import '../../../.storybook/templates/with-layer'; + +const colorSchemes = { + [`Regular`]: null, + [`Light (${TILE_COLOR_SCHEME.LIGHT})`]: TILE_COLOR_SCHEME.LIGHT, +}; + +const defaultArgs = { + checkmarkLabel: '', + colorScheme: null, + name: 'selectable-tile', + value: '', + onInput: 'input', +}; + +const colorSchemeControl = { + colorScheme: { + control: 'select', + description: 'Color scheme (color-scheme)', + options: colorSchemes, + }, +}; + +const defaultHref = { + href: 'https://example.com', +}; + +const hrefControl = { + href: { + control: 'text', + description: 'Href for clickable UI (href)', + }, +}; + +const radioControls = { + checkmarkLabel: { + control: 'text', + description: 'Label text for the checkmark icon (checkmark-label)', + }, + ...colorSchemeControl, + name: { + control: 'text', + description: 'Name (name)', + }, + value: { + control: 'text', + description: 'Value (value)', + }, + onInput: { + action: `input`, + table: { + disable: true, + }, + }, +}; + +const multiSelectableControls = { + ...radioControls, + selected: { + control: 'boolean', + description: 'Selected (selected)', + }, +}; + +const expandableArgs = { + colorScheme: null, + expanded: false, + disableChange: false, + onBeforeChange: 'cds-expandable-tile-beingchanged', + onChange: 'cds-expandable-tile-changed', +}; + +const expandableControls = { + ...colorSchemeControl, + expanded: { + control: 'boolean', + description: 'Expanded (expanded)', + }, + disableChange: { + control: 'boolean', + description: + 'Disable user-initiated change in expanded state (Call event.preventDefault() in cds-expandable-tile-beingchanged event)', + }, + onBeforeChange: { + action: 'cds-expandable-tile-beingchanged', + table: { + disable: true, + }, + }, + onChange: { + action: 'cds-expandable-tile-changed', + table: { + disable: true, + }, + }, +}; + +export const clickable = { + args: defaultHref, + argTypes: hrefControl, + render: ({ href }) => html` + + Clickable tile + + `, +}; + +export const ClickableWithLayer = { + args: defaultHref, + argTypes: hrefControl, + render: ({ href }) => html` + + + Clickable tile + + + `, +}; + +export const Default = { + argTypes: colorSchemeControl, + render: ({ colorScheme }) => html` + + Default tile + Link + + `, +}; + +export const DefaultWithLayer = { + argTypes: colorSchemeControl, + render: ({ colorScheme }) => html` + + + Default layer + Link + + + `, +}; + +export const expandable = { + args: expandableArgs, + argTypes: expandableControls, + render: ({ + colorScheme, + expanded, + disableChange, + onBeforeChange, + onChange, + }) => { + const handleBeforeChanged = (event: CustomEvent) => { + onBeforeChange(event); + if (disableChange) { + event.preventDefault(); + } + }; + return html` + + + Above the fold content here + + + Below the fold content here + + + `; + }, +}; + +export const ExpandableWithInteractive = { + args: expandableArgs, + argTypes: expandableControls, + render: ({ + colorScheme, + expanded, + disableChange, + onBeforeChange, + onChange, + }) => { + const handleBeforeChanged = (event: CustomEvent) => { + onBeforeChange(event); + if (disableChange) { + event.preventDefault(); + } + }; + return html` + + + Above the fold content here +
    + Example +
    +
    + + Below the fold content here + + +
    + `; + }, +}; + +export const ExpandableWithLayer = { + render: ({ + colorScheme, + expanded, + disableChange, + onBeforeChange, + onChange, + }) => { + const handleBeforeChanged = (event: CustomEvent) => { + onBeforeChange(event); + if (disableChange) { + event.preventDefault(); + } + }; + return html` + + + + Above the fold content here + + + Below the fold content here + + + + `; + }, +}; + +export const MultiSelect = { + args: defaultArgs, + argTypes: multiSelectableControls, + render: ({ + checkmarkLabel, + colorScheme, + name, + selected, + value, + onInput, + }) => html` + + + Option 1 + + + Option 2 + + + Option 3 + + + `, +}; + +export const Radio = { + args: defaultArgs, + argTypes: radioControls, + render: ({ checkmarkLabel, colorScheme, name, value, onInput }) => html` + + Radio tile group + + Option 1 + + + Option 2 + + + Option 3 + + + `, +}; + +export const RadioWithLayer = { + render: () => html` + + + Radio tile group + Option 1 + Option 2 + + + `, +}; + +export const Selectable = { + render: () => + html` Default tile `, +}; + +const meta = { + title: 'Components/Tile', + decorators: [(story) => html`
    ${story()}
    `], + parameters: { + actions: { argTypesRegex: '^on.*' }, + docs: { + page: storyDocs, + }, + }, +}; + +export default meta; diff --git a/packages/web-components/src/components/tile/tile.ts b/packages/web-components/src/components/tile/tile.ts new file mode 100644 index 000000000000..0534c131275b --- /dev/null +++ b/packages/web-components/src/components/tile/tile.ts @@ -0,0 +1,95 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { TILE_COLOR_SCHEME } from './defs'; +import styles from './tile.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { TILE_COLOR_SCHEME }; + +/** + * Basic tile. + * + * @element cds-tile + */ +@customElement(`${prefix}-tile`) +class CDSTile extends LitElement { + /** + * `true` if there is a slug. + */ + protected _hasSlug = false; + + /** + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement) + .assignedNodes() + .filter((elem) => + (elem as HTMLElement).matches !== undefined + ? (elem as HTMLElement).matches( + (this.constructor as typeof CDSTile).slugItem + ) + : false + ); + if (hasContent.length > 0) { + this._hasSlug = Boolean(hasContent); + (hasContent[0] as HTMLElement).setAttribute('size', 'xs'); + } + this.requestUpdate(); + } + + /** + * The color scheme. + */ + @property({ attribute: 'color-scheme', reflect: true }) + colorScheme = TILE_COLOR_SCHEME.REGULAR; + + /** + * Specify if the `Tile` component should be rendered with rounded corners. + * Only valid when `slug` prop is present + */ + @property({ type: Boolean, attribute: 'has-rounded-corners' }) + hasRoundedCorners = false; + + updated() { + const anchorTag = this.querySelector('a'); + + if (anchorTag) { + anchorTag?.classList.add(`${prefix}--link`); + anchorTag.before(document.createElement('br')); + anchorTag.before(document.createElement('br')); + } + + if (this._hasSlug) { + this.setAttribute('slug', ''); + } else { + this.removeAttribute('slug'); + } + } + + render() { + return html` `; + } + + /** + * A selector that will return the slug item. + */ + static get slugItem() { + return `${prefix}-slug`; + } + + static styles = styles; +} + +export default CDSTile; diff --git a/packages/web-components/src/components/toggle-tip/index.ts b/packages/web-components/src/components/toggle-tip/index.ts new file mode 100644 index 000000000000..28bf60934d5f --- /dev/null +++ b/packages/web-components/src/components/toggle-tip/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './toggletip'; diff --git a/packages/web-components/src/components/toggle-tip/toggletip.mdx b/packages/web-components/src/components/toggle-tip/toggletip.mdx new file mode 100644 index 000000000000..04ec2e35fad0 --- /dev/null +++ b/packages/web-components/src/components/toggle-tip/toggletip.mdx @@ -0,0 +1,55 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as ToggleTip from './toggletip.stories'; + + + +# Toggletip + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/toggletip) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/toggletip) + +The Toggletip component provides an accessible way to render interactive content +within a popover. If you do not have any interactive content inside of your +Toggletip, consider using Tooltip instead. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/toggle-tip/index.js'; +import '@carbon/web-components/es/components/link/index.js'; +import '@carbon/web-components/es/components/button/index.js'; +``` + +{`${cdnJs({ components: ['toggle-tip'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + Toggletip label + +

    + Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

    + Test + Button +
    +``` + +### `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `open` attribute). + + diff --git a/packages/web-components/src/components/toggle-tip/toggletip.scss b/packages/web-components/src/components/toggle-tip/toggletip.scss new file mode 100644 index 000000000000..4846dd81dacc --- /dev/null +++ b/packages/web-components/src/components/toggle-tip/toggletip.scss @@ -0,0 +1,47 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/type' as *; +@use '@carbon/styles/scss/utilities'; +@use '@carbon/styles/scss/utilities/custom-property' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/type' as *; +@use '@carbon/styles/scss/components/toggletip/index' as *; +@use '@carbon/styles/scss/components/tooltip/index' as *; +@use '@carbon/styles/scss/utilities/button-reset'; +@use '../popover/popover.scss' as *; + +:host(#{$prefix}-toggletip), +:host(#{$prefix}-slug) { + // TODO: audit + @extend .#{$prefix}--toggletip; + + display: flex; + align-items: center; + justify-content: center; + + outline: none; + + .#{$prefix}--popover-caret { + background-color: $background-inverse; + } +} + +:host(#{$prefix}-slug[open][autoalign]), +:host(#{$prefix}-toggletip[open][autoalign]) { + .#{$prefix}--popover-content { + display: block; + + @include declaration('popover-background-color', $background-inverse); + + @include declaration('popover-text-color', $text-inverse); + } +} diff --git a/packages/web-components/src/components/toggle-tip/toggletip.stories.ts b/packages/web-components/src/components/toggle-tip/toggletip.stories.ts new file mode 100644 index 000000000000..02307184dddd --- /dev/null +++ b/packages/web-components/src/components/toggle-tip/toggletip.stories.ts @@ -0,0 +1,101 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './toggletip'; +import '../button'; +import { POPOVER_ALIGNMENT } from '../popover/defs'; + +const tooltipAlignments = { + [`top`]: POPOVER_ALIGNMENT.TOP, + [`top-left`]: POPOVER_ALIGNMENT.TOP_LEFT, + [`top-right`]: POPOVER_ALIGNMENT.TOP_RIGHT, + [`bottom`]: POPOVER_ALIGNMENT.BOTTOM, + [`bottom-left`]: POPOVER_ALIGNMENT.BOTTOM_LEFT, + [`bottom-right`]: POPOVER_ALIGNMENT.BOTTOM_RIGHT, + [`left`]: POPOVER_ALIGNMENT.LEFT, + [`left-bottom`]: POPOVER_ALIGNMENT.LEFT_BOTTOM, + [`left-top`]: POPOVER_ALIGNMENT.LEFT_TOP, + [`right`]: POPOVER_ALIGNMENT.RIGHT, + [`right-bottom`]: POPOVER_ALIGNMENT.RIGHT_BOTTOM, + [`right-top`]: POPOVER_ALIGNMENT.RIGHT_TOP, +}; + +const defaultArgs = { + alignment: 'bottom', + open: true, +}; + +const controls = { + alignment: { + control: 'select', + description: 'Specify how the toggletip should align with the button', + options: tooltipAlignments, + }, + open: { + control: 'boolean', + description: 'Specify if the toggletip should be open', + }, +}; + +export const Default = { + render: () => html` +
    +
    + + Toggletip label + +

    + Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed + do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

    + Test + Button +
    +
    +
    +
    +
    + + Toggletip label -- using open prop + +

    + Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed + do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

    + Test + Button +
    +
    +
    + `, +}; + +export const Playground = { + argTypes: controls, + args: defaultArgs, + render: ({ alignment, open }) => html` + + Toggletip label -- using open prop + +

    + Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut fsil labore et dolore magna aliqua. +

    + Test + Button +
    + `, +}; + +const meta = { + title: 'Components/Toggletip', +}; + +export default meta; diff --git a/packages/web-components/src/components/toggle-tip/toggletip.ts b/packages/web-components/src/components/toggle-tip/toggletip.ts new file mode 100644 index 000000000000..773778305e40 --- /dev/null +++ b/packages/web-components/src/components/toggle-tip/toggletip.ts @@ -0,0 +1,224 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { html, LitElement } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import Information16 from '@carbon/icons/lib/information/16'; +import { prefix } from '../../globals/settings'; +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import FocusMixin from '../../globals/mixins/focus'; +import { POPOVER_ALIGNMENT } from '../popover/defs'; +import PopoverController from '../../globals/controllers/popover-controller'; +import styles from './toggletip.scss?lit'; + +/** + * Definition tooltip. + * + * @element cds-toggletip + */ +@customElement(`${prefix}-toggletip`) +class CDSToggletip extends HostListenerMixin(FocusMixin(LitElement)) { + /** + * Create popover controller instance + */ + private popoverController = new PopoverController(this); + + /** + * How the tooltip is aligned to the trigger button. + */ + @property({ reflect: true }) + alignment = POPOVER_ALIGNMENT.TOP; + + /** + * Specify whether a auto align functionality should be applied + */ + @property({ type: Boolean, reflect: true }) + autoalign = false; + + /** + * Set whether toggletip is open + */ + @property({ type: Boolean, reflect: true }) + open = false; + + /** + * Handles `slotchange` event. + */ + private _handleActionsSlotChange({ target }: Event) { + const hasContent = (target as HTMLSlotElement).assignedNodes(); + hasContent + ? this.setAttribute('has-actions', '') + : this.removeAttribute('has-actions'); + } + + protected _handleClick = () => { + this.open = !this.open; + }; + + /** + * Handles `keydown` event on this element. + */ + @HostListener('keydown') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + protected _handleKeydown = async (event) => { + if (event.key === 'Escape') { + this.open = false; + } + }; + + /** + * Handles `blur` event handler on the document this element is in. + * + * @param event The event. + */ + @HostListener('focusout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + protected _handleFocusOut(event: FocusEvent) { + if (!this.contains(event.relatedTarget as Node)) { + this.open = false; + } + } + + protected _renderToggleTipLabel = () => { + return html` + + + + `; + }; + + protected _renderTooltipButton = () => { + return html` + + `; + }; + + protected _renderTooltipContent = () => { + return this.autoalign + ? html` + +
    + +
    + +
    +
    + +
    + ` + : html` + + +
    + +
    + +
    +
    +
    + +
    + `; + }; + + protected _renderInnerContent = () => { + return html` + ${this._renderTooltipButton()} ${this._renderTooltipContent()} + `; + }; + + updated() { + if (this.autoalign && this.open) { + // auto align functionality with @floating-ui/dom library + const button = this.shadowRoot?.querySelector( + CDSToggletip.selectorToggletipButton + ); + + const tooltip = this.shadowRoot?.querySelector( + CDSToggletip.selectorToggletipContent + ); + const arrowElement = this.shadowRoot?.querySelector( + CDSToggletip.selectorToggletipCaret + ); + + if (button && tooltip) { + this.popoverController?.setPlacement({ + trigger: button as HTMLElement, + target: tooltip as HTMLElement, + arrowElement: arrowElement as HTMLElement, + caret: true, + flip: true, + alignment: this.alignment, + }); + } + } + } + + render() { + const { alignment, open } = this; + const classes = classMap({ + [`${prefix}--popover-container`]: true, + [`${prefix}--popover--caret`]: true, + [`${prefix}--popover--high-contrast`]: true, + [`${prefix}--popover--open`]: open, + [`${prefix}--popover--${alignment}`]: alignment, + [`${prefix}--toggletip`]: true, + [`${prefix}--toggletip--open`]: open, + }); + return html` + ${this._renderToggleTipLabel()} + + ${this._renderInnerContent()} + + + `; + } + + /** + * A selector that will return the toggletip content. + */ + static get selectorToggletipContent() { + return `.${prefix}--popover-content`; + } + + /** + * A selector that will return the toggletip caret. + */ + static get selectorToggletipCaret() { + return `.${prefix}--popover-caret`; + } + + /** + * A selector that will return the trigger element. + */ + static get selectorToggletipButton() { + return `.${prefix}--toggletip-button`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + + static styles = styles; +} + +export default CDSToggletip; diff --git a/packages/web-components/src/components/toggle/defs.ts b/packages/web-components/src/components/toggle/defs.ts new file mode 100644 index 000000000000..debf14bae4bd --- /dev/null +++ b/packages/web-components/src/components/toggle/defs.ts @@ -0,0 +1,23 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Toggle size. + */ +export enum TOGGLE_SIZE { + /** + * Regular size. + */ + REGULAR = '', + + /** + * Small size. + */ + SMALL = 'sm', +} diff --git a/packages/web-components/src/components/toggle/docs/overview.mdx b/packages/web-components/src/components/toggle/docs/overview.mdx new file mode 100644 index 000000000000..5f6bc95407cf --- /dev/null +++ b/packages/web-components/src/components/toggle/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/toggle/index.ts b/packages/web-components/src/components/toggle/index.ts new file mode 100644 index 000000000000..33d523b34459 --- /dev/null +++ b/packages/web-components/src/components/toggle/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './toggle'; diff --git a/packages/web-components/src/components/toggle/toggle.mdx b/packages/web-components/src/components/toggle/toggle.mdx new file mode 100644 index 000000000000..3e630a222d3e --- /dev/null +++ b/packages/web-components/src/components/toggle/toggle.mdx @@ -0,0 +1,53 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as Toggle from './toggle.stories'; + + + +# Toggle + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/toggle) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/toggle) + +Toggle is a control that is used to quickly switch between two possible states. +Toggles are only used for these binary actions that occur immediately after the +user “flips” the toggle switch. They are commonly used for “on/off” switches. + +Use `small` property/attribute to make it more compact in size, so they can be +used in use cases such as data tables. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/toggle/index.js'; +``` + +{`${cdnJs({ components: ['toggle'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + +``` + +## Small toggle + +```html + +``` + +## `` attributes, properties and events + + diff --git a/packages/web-components/src/components/toggle/toggle.scss b/packages/web-components/src/components/toggle/toggle.scss new file mode 100644 index 000000000000..8c62eb8fd5c8 --- /dev/null +++ b/packages/web-components/src/components/toggle/toggle.scss @@ -0,0 +1,27 @@ +// +// Copyright IBM Corp. 2019, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/components/toggle/index' as *; +@use '@carbon/styles/scss/config' as *; + +:host(#{$prefix}-toggle) { + outline: none; +} + +:host(#{$prefix}-toggle[disabled]) { + @extend .#{$prefix}--toggle--disabled !optional; + + .#{$prefix}--toggle__appearance { + cursor: not-allowed; + } +} + +:host(#{$prefix}-toggle[read-only]) { + @extend .#{$prefix}--toggle--readonly; +} diff --git a/packages/web-components/src/components/toggle/toggle.stories.ts b/packages/web-components/src/components/toggle/toggle.stories.ts new file mode 100644 index 000000000000..a3ef3a794c03 --- /dev/null +++ b/packages/web-components/src/components/toggle/toggle.stories.ts @@ -0,0 +1,114 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './index'; +import '../stack/index'; +import { TOGGLE_SIZE } from './toggle'; + +const sizes = { + 'Regular size': null, + [`Small size (${TOGGLE_SIZE.SMALL})`]: TOGGLE_SIZE.SMALL, +}; + +const defaultArgs = { + labelA: 'On', + labelB: 'Off', + checked: true, +}; + +const controls = { + disabled: { + control: 'boolean', + description: 'Whether this control should be disabled', + }, + hideLabel: { + control: 'boolean', + description: + "If true, the side labels (props.labelA and props.labelB) will be replaced by props.labelText (if passed), so that the toggle doesn't render a top label.", + }, + labelA: { + control: 'text', + description: 'The text for the checked state.', + }, + labelB: { + control: 'text', + description: 'The text for the unchecked state', + }, + labelText: { + control: 'text', + description: 'The text that is read for the control', + }, + readonly: { + control: 'boolean', + description: 'Whether the toggle should be read-only', + }, + size: { + control: 'radio', + description: + "Specify the size of the Toggle. Currently only supports 'sm' or 'md' (default)", + options: sizes, + }, + checked: { + control: 'boolean', + description: 'Specify whether the control is toggled', + }, +}; + +export const Default = { + render: () => html` + + `, +}; + +export const SmallToggle = { + render: () => html` + + `, +}; + +export const Playground = { + argTypes: controls, + args: defaultArgs, + render: ({ + disabled, + hideLabel, + labelA, + labelB, + labelText, + readonly, + size, + checked, + }) => html` + + `, +}; + +const meta = { + title: 'Components/Toggle', +}; + +export default meta; diff --git a/packages/web-components/src/components/toggle/toggle.ts b/packages/web-components/src/components/toggle/toggle.ts new file mode 100644 index 000000000000..e427a4823c69 --- /dev/null +++ b/packages/web-components/src/components/toggle/toggle.ts @@ -0,0 +1,180 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { prefix } from '../../globals/settings'; +import CDSCheckbox from '../checkbox/checkbox'; +import { TOGGLE_SIZE } from './defs'; +import styles from './toggle.scss?lit'; +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { TOGGLE_SIZE }; + +/** + * Basic toggle. + * + * @element cds-toggle + * @slot label-text - The label text. + * @slot checked-text - The text for the checked state. + * @slot unchecked-text - The text for the unchecked state. + * @fires cds-toggle-changed - The custom event fired after this changebox changes its checked state. + */ +@customElement(`${prefix}-toggle`) +class CDSToggle extends HostListenerMixin(CDSCheckbox) { + @query('button') + protected _checkboxNode!: HTMLInputElement; + + /** + * Handles `click` event on the ` + + `; + } + + /** + * The name of the custom event fired after this changebox changes its checked state. + */ + static get eventChange() { + return `${prefix}-toggle-changed`; + } + + static styles = styles; +} + +export default CDSToggle; diff --git a/packages/web-components/src/components/tooltip/docs/overview.mdx b/packages/web-components/src/components/tooltip/docs/overview.mdx new file mode 100644 index 000000000000..44c8272511a6 --- /dev/null +++ b/packages/web-components/src/components/tooltip/docs/overview.mdx @@ -0,0 +1,20 @@ +## Live demo + + diff --git a/packages/web-components/src/components/tooltip/index.ts b/packages/web-components/src/components/tooltip/index.ts new file mode 100644 index 000000000000..074fbabb12af --- /dev/null +++ b/packages/web-components/src/components/tooltip/index.ts @@ -0,0 +1,11 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './tooltip'; +import './tooltip-content'; diff --git a/packages/web-components/src/components/tooltip/tooltip-content.ts b/packages/web-components/src/components/tooltip/tooltip-content.ts new file mode 100644 index 000000000000..4f8b592ba2f0 --- /dev/null +++ b/packages/web-components/src/components/tooltip/tooltip-content.ts @@ -0,0 +1,39 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { prefix } from '../../globals/settings'; +import CDSPopoverContent from '../popover/popover-content'; +import styles from './tooltip.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Tooltip content. + */ +@customElement(`${prefix}-tooltip-content`) +class CDSTooltipContent extends CDSPopoverContent { + connectedCallback() { + if (!this.hasAttribute('aria-hidden')) { + this.setAttribute('aria-hidden', 'true'); + } + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'tooltip'); + } + super.connectedCallback(); + } + + updated() { + this.shadowRoot + ?.querySelector(`.${prefix}--popover-content`) + ?.classList.add(`${prefix}--tooltip-content`); + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSTooltipContent; diff --git a/packages/web-components/src/components/tooltip/tooltip-story.scss b/packages/web-components/src/components/tooltip/tooltip-story.scss new file mode 100644 index 000000000000..98566107b151 --- /dev/null +++ b/packages/web-components/src/components/tooltip/tooltip-story.scss @@ -0,0 +1,37 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/utilities/button-reset'; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/type'; + +// This is a utility class to make sure that tooltip stories have a minimum +// height when used in MDX docs +.sb-tooltip-story { + display: flex; + align-items: center; + justify-content: center; + margin: auto; + min-block-size: 250px; +} + +.sb-tooltip-trigger { + @include button-reset.reset(); + + display: flex; + align-items: center; + justify-content: center; + border: 1px solid theme.$border-subtle; + block-size: $spacing-07; + inline-size: $spacing-07; +} + +.sb-tooltip-trigger svg { + fill: theme.$background-inverse; +} diff --git a/packages/web-components/src/components/tooltip/tooltip.mdx b/packages/web-components/src/components/tooltip/tooltip.mdx new file mode 100644 index 000000000000..02b11bb5c77d --- /dev/null +++ b/packages/web-components/src/components/tooltip/tooltip.mdx @@ -0,0 +1,66 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as Tooltip from './tooltip.stories'; + + + +# Tooltip + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/tooltip) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/tooltip) + +You can use the Tooltip component as a wrapper to display a popup for an +interactive element that you provide. If you are trying to place interactive +content inside of the Tooltip itself, consider using Toggletip instead. You can +provide the interactive element as a child to Tooltip. Tooltips provide +additional information upon hover or focus. The information should be +contextual, useful, and nonessential information. Keep tooltips short. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/tooltip/index.js'; +import Information16 from '@carbon/icons/lib/information/16'; +``` + +{`${cdnJs({ components: ['tooltip'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + +
    + ${Information16()} +
    + + Occassionally, services are updated in a specified time window to ensure no + down time for customers. + +
    +``` + +## Toggletips vs Tooltips + +Toggletips and tooltips are similar visually and both contain a popover and +interactive trigger element. The two components differ in the way they are +invoked and dismissed and if the user must interact with the contents. A tooltip +is exposed on hover or focus when you need to expose brief, supplemental +information that is not interactive. A toggletip is used on click or enter when +you need to expose interactive elements, such as button, that a user needs to +interact with. + +### `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `open` attribute). + + diff --git a/packages/web-components/src/components/tooltip/tooltip.scss b/packages/web-components/src/components/tooltip/tooltip.scss new file mode 100644 index 000000000000..2b4f81ac53ed --- /dev/null +++ b/packages/web-components/src/components/tooltip/tooltip.scss @@ -0,0 +1,46 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +@use '@carbon/styles/scss/config' as *; +@use '../popover/popover' as *; +@use '@carbon/styles/scss/components/tooltip'; +@use '@carbon/styles/scss/theme' as *; + +// For some reason `#{prefix}-tooltip` doesn't work here, will need to investigate +:host(#{$prefix}-tooltip[data-table]) { + display: contents; + + &:hover { + ::slotted(button) { + /* stylelint-disable-next-line declaration-no-important */ + background-color: $layer-selected-hover !important; + } + } +} + +:host(#{$prefix}-tooltip[data-table][size='xs']), +:host(#{$prefix}-tooltip[data-table][size='sm']) { + ::slotted(button) { + /* stylelint-disable-next-line declaration-no-important */ + block-size: calc(100% + 1px) !important; + } +} + +:host(#{$prefix}-tooltip[toolbar-action]) { + ::slotted(button) { + /* stylelint-disable-next-line declaration-no-important */ + outline: none !important; + } +} + +:host(#{prefix}-tooltip-content) { + ::slotted(.#{$prefix}-tooltip-content) { + @extend .#{$prefix}--tooltip-content; + } +} diff --git a/packages/web-components/src/components/tooltip/tooltip.stories.ts b/packages/web-components/src/components/tooltip/tooltip.stories.ts new file mode 100644 index 000000000000..732ad8afb61e --- /dev/null +++ b/packages/web-components/src/components/tooltip/tooltip.stories.ts @@ -0,0 +1,161 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +// Below path will be there when an application installs `@carbon/web-components` package. +// In our dev env, we auto-generate the file and re-map below path to to point to the generated file. +// @ts-ignore +import './index'; +import { POPOVER_ALIGNMENT } from '../popover/defs'; +import styles from './tooltip-story.scss?lit'; +import Information16 from '@carbon/icons/lib/information/16'; + +const tooltipAlignments = { + [`top`]: POPOVER_ALIGNMENT.TOP, + [`top-left`]: POPOVER_ALIGNMENT.TOP_LEFT, + [`top-right`]: POPOVER_ALIGNMENT.TOP_RIGHT, + [`bottom`]: POPOVER_ALIGNMENT.BOTTOM, + [`bottom-left`]: POPOVER_ALIGNMENT.BOTTOM_LEFT, + [`bottom-right`]: POPOVER_ALIGNMENT.BOTTOM_RIGHT, + [`left`]: POPOVER_ALIGNMENT.LEFT, + [`left-bottom`]: POPOVER_ALIGNMENT.LEFT_BOTTOM, + [`left-top`]: POPOVER_ALIGNMENT.LEFT_TOP, + [`right`]: POPOVER_ALIGNMENT.RIGHT, + [`right-bottom`]: POPOVER_ALIGNMENT.RIGHT_BOTTOM, + [`right-top`]: POPOVER_ALIGNMENT.RIGHT_TOP, +}; + +const defaultArgs = { + align: POPOVER_ALIGNMENT.BOTTOM, + closeOnActivation: false, + defaultOpen: true, + enterDelayMs: 100, + label: 'Custom label', + leaveDelayMs: 300, +}; + +const controls = { + align: { + control: 'select', + description: 'Specify how the trigger should align with the tooltip', + options: tooltipAlignments, + }, + closeOnActivation: { + control: 'boolean', + description: + 'Determines wether the tooltip should close when inner content is activated (click, Enter or Space)', + }, + defaultOpen: { + control: 'boolean', + description: + 'Specify whether the tooltip should be open when it first renders', + }, + enterDelayMs: { + control: 'number', + description: + 'Specify the duration in milliseconds to delay before displaying the tooltip', + }, + label: { + control: 'text', + description: 'Provide the label to be rendered inside of the Tooltip.', + }, + leaveDelayMs: { + control: 'number', + description: + 'Specify the duration in milliseconds to delay before hiding the tooltip', + }, +}; + +export const Default = { + render: () => html` + + + + Occassionally, services are updated in a specified time window to ensure + no down time for customers. + + + `, +}; + +export const Alignment = { + render: () => html` + + + + Tooltip alignment + + + `, +}; + +export const Duration = { + render: () => html` + + + Label one + + `, +}; + +export const Playground = { + argTypes: controls, + args: defaultArgs, + render: ({ + align, + closeOnActivation, + defaultOpen, + enterDelayMs, + label, + leaveDelayMs, + }) => html` + + + ${label} + + `, +}; + +const meta = { + title: 'Components/Tooltip', + decorators: [ + (story) => html`
    + ${story()} +
    `, + ], +}; + +export default meta; diff --git a/packages/web-components/src/components/tooltip/tooltip.ts b/packages/web-components/src/components/tooltip/tooltip.ts new file mode 100644 index 000000000000..737791c38cd0 --- /dev/null +++ b/packages/web-components/src/components/tooltip/tooltip.ts @@ -0,0 +1,220 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { css } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import HostListener from '../../globals/decorators/host-listener'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import CDSPopover from '../popover/popover'; +import '../popover/popover-content'; +import styles from './tooltip.scss?lit'; +import CDSTooltipContent from './tooltip-content'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Trigger button of tooltip. + * + * @element cds-tooltip + */ +@customElement(`${prefix}-tooltip`) +class CDSTooltip extends HostListenerMixin(CDSPopover) { + /** + * Specify how the trigger should align with the tooltip + */ + @property({ reflect: true, type: String }) + align = 'top'; + + /** + * Specify whether a auto align functionality should be applied + */ + @property({ type: Boolean, reflect: true }) + autoalign = false; + + /** + * `true` if this tooltip is in a data table row + */ + @property({ type: Boolean, reflect: true, attribute: 'data-table' }) + dataTable = false; + + /** + * Specify whether the tooltip should be closed when clicked + */ + @property({ reflect: true, type: Boolean }) + closeOnActivation = false; + + /** + * Specify whether the tooltip should be open when it first renders + */ + @property({ reflect: true, type: Boolean }) + defaultOpen = false; + + /** + * Specify the duration in milliseconds to delay before displaying the tooltip + */ + @property({ attribute: 'enter-delay-ms', type: Number }) + enterDelayMs = 100; + + /** + * Specify the duration in milliseconds to delay before hiding the tooltip + */ + @property({ attribute: 'leave-delay-ms', type: Number }) + leaveDelayMs = 300; + + /** + * Specify the size of the tooltip + */ + @property({ reflect: true }) + size = false; + + /** + * Specify the timeout reference for the tooltip + */ + @property({ reflect: true }) + timeoutId = 0; + + /** + * Specify whether the tooltip should be open when it first renders + */ + @property({ reflect: true, attribute: 'toolbar-action', type: Boolean }) + toolbarAction = false; + + /** + * Handles `mouseover` event on this element. + */ + private _handleHover = async () => { + window.clearTimeout(this.timeoutId); + this.timeoutId = window.setTimeout(async () => { + this.open = true; + const { open, updateComplete } = this; + if (open) { + await updateComplete; + const { selectorTooltipContent } = this + .constructor as typeof CDSTooltip; + (this.querySelector(selectorTooltipContent) as HTMLElement)?.focus(); + } + }, this.enterDelayMs); + }; + + /** + * Handles `mouseleave` event on this element. + */ + private _handleHoverOut = async () => { + window.clearTimeout(this.timeoutId); + this.timeoutId = window.setTimeout(async () => { + const { open } = this; + if (open) { + this.open = false; + } + }, this.leaveDelayMs); + }; + + /** + * Handles `click` event on this element. + */ + @HostListener('click') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleClick = async () => { + if (this.closeOnActivation) { + this._handleHoverOut(); + } + }; + + /** + * Handles `keydown` event on this element. + */ + @HostListener('click') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleKeydown = async (event) => { + if (event.key === ' ' || event.key === 'Enter' || event.key === 'Escape') { + this._handleHoverOut(); + } + }; + + /** + * Handles `slotchange` event. + */ + protected _handleSlotChange({ target }: Event) { + const component = (target as HTMLSlotElement) + .assignedNodes() + .filter( + (node) => node.nodeType !== Node.TEXT_NODE || node!.textContent!.trim() + ); + if (!component[0]) { + return; + } + (component[0] as HTMLElement).addEventListener('focus', this._handleHover); + (component[0] as HTMLElement).addEventListener( + 'focusout', + this._handleHoverOut + ); + (component[0] as HTMLElement).addEventListener( + 'mouseover', + this._handleHover + ); + (component[0] as HTMLElement).addEventListener( + 'mouseleave', + this._handleHoverOut + ); + this.requestUpdate(); + } + + connectedCallback() { + if (!this.hasAttribute('highContrast')) { + this.setAttribute('highContrast', ''); + } + if (!this.shadowRoot) { + this.attachShadow({ mode: 'open' }); + } + super.connectedCallback(); + } + + updated(changedProperties) { + const { selectorTooltipContent } = this.constructor as typeof CDSTooltip; + const toolTipContent = this.querySelector(selectorTooltipContent); + + if (changedProperties.has('defaultOpen')) { + this.open = this.defaultOpen; + } + + if (changedProperties.has('open')) { + this.open + ? toolTipContent?.setAttribute('open', '') + : toolTipContent?.removeAttribute('open'); + } + + ['align', 'caret', 'autoalign'].forEach((name) => { + if (changedProperties.has(name)) { + const { [name as keyof CDSTooltip]: value } = this; + (toolTipContent as CDSTooltipContent)[name] = value; + } + }); + + this.shadowRoot + ?.querySelector(`.${prefix}--popover-container`) + ?.classList.add(`${prefix}--tooltip`); + + super.updated(changedProperties); + } + + /** + * A selector that will return the CDSTooltipContent. + */ + static get selectorTooltipContent() { + return `${prefix}-tooltip-content`; + } + + static get styles() { + return css` + ${super.styles}${styles} + `; + } // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSTooltip; diff --git a/packages/web-components/src/components/ui-shell/defs.ts b/packages/web-components/src/components/ui-shell/defs.ts new file mode 100644 index 000000000000..ecd6f3dabc7b --- /dev/null +++ b/packages/web-components/src/components/ui-shell/defs.ts @@ -0,0 +1,48 @@ +/** + * @license + * + * Copyright IBM Corp. 2020 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Collapse modes of side nav. + */ +export enum SIDE_NAV_COLLAPSE_MODE { + /** + * Fixed mode. + * In this mode, side nav is non-collapsible. + */ + FIXED = 'fixed', + + /** + * Rail mode. + * In this mode, side nav can be collapsed to a narrower width ("rail" look) with a toggle button. + */ + RAIL = 'rail', + + /** + * Responsive mode. + * In this mode, side nav sticks in wider screen, and can be completely collapsed with a toggle button in narrower screen. + */ + RESPONSIVE = 'responsive', +} + +/** + * The usage purpose of side nav. + */ +export enum SIDE_NAV_USAGE_MODE { + /** + * Regular usage. + */ + REGULAR = '', + + /** + * To represent header nav. + * In this mode, side nav is hidden when header nav is shown, and side nav is shown then header nav is hidden. + * This mode can be used only with `SIDE_NAV_COLLAPSE_MODE.REGULAR`. + */ + HEADER_NAV = 'header-nav', +} diff --git a/packages/web-components/src/components/ui-shell/docs/overview.mdx b/packages/web-components/src/components/ui-shell/docs/overview.mdx new file mode 100644 index 000000000000..0ade930f0551 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/docs/overview.mdx @@ -0,0 +1,20 @@ +## Live demo + + diff --git a/packages/web-components/src/components/ui-shell/header-global-action.ts b/packages/web-components/src/components/ui-shell/header-global-action.ts new file mode 100644 index 000000000000..f886ccb09eb0 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header-global-action.ts @@ -0,0 +1,117 @@ +/** + * @license + * + * Copyright IBM Corp. 2023, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { BUTTON_TOOLTIP_POSITION } from '../button/button'; +import CDSButton from '../button/button'; +import HostListener from '../../globals/decorators/host-listener'; +import styles from './header.scss?lit'; +import { prefix } from '../../globals/settings'; + +/** + * Header global action button + * + * @element cds-header-global-action + */ +@customElement(`${prefix}-header-global-action`) +class CDSHeaderGlobalAction extends CDSButton { + @query('button') + protected _buttonNode!: HTMLButtonElement; + + /** + * Specify whether the action is currently active + */ + @property({ type: Boolean, reflect: true }) + active; + + /** + * Specify which header panel the button is associated with. + */ + @property({ type: String, attribute: 'panel-id', reflect: true }) + panelId; + + /** + * The `aria-label` attribute for the button in its active state. + */ + @property({ attribute: 'button-label-active' }) + buttonLabelActive; + + /** + * The `aria-label` attribute for the button in its inactive state. + */ + @property({ attribute: 'button-label-inactive' }) + buttonLabelInactive; + + connectedCallback() { + this.tooltipPosition = BUTTON_TOOLTIP_POSITION.BOTTOM; + super.connectedCallback(); + } + + @HostListener('click', { capture: true }) + // @ts-ignore + private _handleClick(event: Event) { + const { disabled } = this; + if (disabled) { + event.stopPropagation(); + } else { + const panel = document.querySelector(`#${this.panelId}`); + + // see if there is related panel for header-global-action button first + // and then set the expanded attr of it accordingly + if (panel) { + const expanded = panel.getAttribute('expanded'); + + if (expanded) { + panel.removeAttribute('expanded'); + } else { + panel.setAttribute('expanded', 'true'); + } + + const active = !this.active; + this.active = active; + } + } + } + + updated() { + if (this._buttonNode) { + this._buttonNode.classList.add(`${prefix}--header__action`); + } + } + + shouldUpdate(changedProperties) { + if (changedProperties.has('active')) { + if (this.active) { + this._buttonNode.classList.add(`${prefix}--header__action--active`); + + if (this.buttonLabelActive) { + this.tooltipText = this.buttonLabelActive; + } + } else { + this._buttonNode.classList.remove(`${prefix}--header__action--active`); + + if (this.buttonLabelInactive) { + this.tooltipText = this.buttonLabelInactive; + } + } + } + return true; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSHeaderGlobalAction; diff --git a/packages/web-components/src/components/ui-shell/header-menu-button.ts b/packages/web-components/src/components/ui-shell/header-menu-button.ts new file mode 100644 index 000000000000..0185fbd8b36a --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header-menu-button.ts @@ -0,0 +1,130 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import Close20 from '@carbon/icons/lib/close/20'; +import Menu20 from '@carbon/icons/lib/menu/20'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import { SIDE_NAV_COLLAPSE_MODE } from './side-nav'; +import styles from './header.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * The trigger button for side nav in header nav. + * + * @element cds-header-menu-button + * @csspart button The button. + * @csspart toggle-icon The toggle icon. + * @fires cds-header-menu-button-toggled - The custom event fired after this header menu button is toggled upon a user gesture. + */ +@customElement(`${prefix}-header-menu-button`) +class CDSHeaderMenuButton extends FocusMixin(LitElement) { + private _handleClick() { + const active = !this.active; + this.active = active; + this.dispatchEvent( + new CustomEvent( + (this.constructor as typeof CDSHeaderMenuButton).eventToggle, + { + bubbles: true, + cancelable: true, + composed: true, + detail: { + active, + }, + } + ) + ); + } + + /** + * `true` if the button should represent its active state. + */ + @property({ type: Boolean, reflect: true }) + active = false; + + /** + * The `aria-label` attribute for the button in its active state. + */ + @property({ attribute: 'button-label-active' }) + buttonLabelActive = 'Close navigation menu'; + + /** + * The `aria-label` attribute for the button in its inactive state. + */ + @property({ attribute: 'button-label-inactive' }) + buttonLabelInactive = 'Open navigation menu'; + + /** + * Collapse mode of the side nav. + */ + @property({ reflect: true, attribute: 'collapse-mode' }) + collapseMode = SIDE_NAV_COLLAPSE_MODE.RESPONSIVE; + + /** + * `true` if the button should be disabled. + */ + @property({ type: Boolean, reflect: true }) + disabled = false; + + /** + * If `true` will style the side nav to sit below the header + */ + @property({ + type: Boolean, + attribute: 'is-not-child-of-header', + }) + isNotChildOfHeader = false; + + render() { + const { + active, + buttonLabelActive, + buttonLabelInactive, + disabled, + _handleClick: handleClick, + } = this; + const buttonLabel = active ? buttonLabelActive : buttonLabelInactive; + const classes = classMap({ + [`${prefix}--header__action`]: true, + [`${prefix}--header__menu-trigger`]: true, + [`${prefix}--header__menu-toggle`]: true, + [`${prefix}--header__action--active`]: active, + }); + return html` + + `; + } + + /** + * The name of the custom event fired after this header menu button is toggled upon a user gesture. + */ + static get eventToggle() { + return `${prefix}-header-menu-button-toggled`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSHeaderMenuButton; diff --git a/packages/web-components/src/components/ui-shell/header-menu-item.ts b/packages/web-components/src/components/ui-shell/header-menu-item.ts new file mode 100644 index 000000000000..b5b0f9e844b0 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header-menu-item.ts @@ -0,0 +1,22 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { prefix } from '../../globals/settings'; +import CDSHeaderNavItem from './header-nav-item'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Header submenu item. + * + * @element cds-header-menu-item + */ +@customElement(`${prefix}-header-menu-item`) +class CDSHeaderMenuItem extends CDSHeaderNavItem {} + +export default CDSHeaderMenuItem; diff --git a/packages/web-components/src/components/ui-shell/header-menu.ts b/packages/web-components/src/components/ui-shell/header-menu.ts new file mode 100644 index 000000000000..a44030db264a --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header-menu.ts @@ -0,0 +1,189 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ifDefined } from 'lit/directives/if-defined.js'; +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import ChevronDownGlyph from '@carbon/icons/lib/chevron--down/16'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import HostListener from '../../globals/decorators/host-listener'; +import { forEach } from '../../globals/internal/collection-helpers'; +import CDSHeaderMenuItem from './header-menu-item'; +import styles from './header.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Header menu. + * + * @element cds-header-menu + * @csspart trigger The trigger button. + * @csspart trigger-icon The trigger button icon. + * @csspart menu-body The menu body. + */ +@customElement(`${prefix}-header-menu`) +class CDSHeaderMenu extends HostListenerMixin(FocusMixin(LitElement)) { + /** + * The trigger button. + */ + @query('[part="trigger"]') + protected _topMenuItem!: HTMLElement; + + /** + * keeps track if header menu has any active submenus + */ + private _hasActiveChildren = false; + + /** + * Handles `click` event handler on this element. + */ + private _handleClick() { + this._handleUserInitiatedToggle(); + } + + /** + * Handler for the `keydown` event on the trigger button. + */ + @HostListener('keydown') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleKeydownTrigger({ key }: KeyboardEvent) { + if (key === 'Esc' || key === 'Escape') { + this._handleUserInitiatedToggle(false); + } + } + + /** + * Handles user-initiated toggling the open state. + * + * @param [force] If specified, forces the open state to the given one. + */ + private _handleUserInitiatedToggle(force = !this.expanded) { + this.expanded = force; + if (!force) { + this._topMenuItem.focus(); + } + } + + /** + * Handles `blur` event handler on this element. + */ + @HostListener('focusout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleBlur({ relatedTarget }: FocusEvent) { + if (!this.contains(relatedTarget as Node)) { + this.expanded = false; + } + } + + /** + * `true` if the menu should be expanded. + */ + @property({ type: Boolean, reflect: true }) + expanded = false; + + /** + * Applies selected styles to the item if a user sets this to true and `aria-current !== 'page'`. + */ + @property({ type: Boolean, attribute: 'is-active', reflect: true }) + isActive = false; + + /** + * The content of the trigger button. + */ + @property({ attribute: 'trigger-content' }) + triggerContent = ''; + + /** + * The `aria-label` attribute for the menu UI. + */ + @property({ attribute: 'menu-label' }) + menuLabel!: string; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'listitem'); + } + const { selectorItem } = this.constructor as typeof CDSHeaderMenu; + forEach(this.querySelectorAll(selectorItem), (elem) => { + if ((elem as CDSHeaderMenuItem).isActive === true) { + this._hasActiveChildren = true; + } + }); + + super.connectedCallback(); + } + + updated(changedProperties) { + if (changedProperties.has('expanded')) { + const { selectorItem } = this.constructor as typeof CDSHeaderMenu; + const { expanded } = this; + forEach(this.querySelectorAll(selectorItem), (elem) => { + (elem as HTMLElement).tabIndex = expanded ? 0 : -1; + }); + } + } + + render() { + const { + expanded, + isActive, + triggerContent, + menuLabel, + _hasActiveChildren, + _handleClick: handleClick, + } = this; + + const linkClasses = classMap({ + [`${prefix}--header__menu-item`]: true, + [`${prefix}--header__menu-title`]: true, + [`${prefix}--header__menu-item--current`]: + isActive || (_hasActiveChildren && !expanded), + }); + + return html` + + ${triggerContent}${ChevronDownGlyph({ + part: 'trigger-icon', + class: `${prefix}--header__menu-arrow`, + })} + +
      + +
    + `; + } + + /** + * A selector that will return the menu items. + */ + static get selectorItem() { + return `${prefix}-header-menu-item`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSHeaderMenu; diff --git a/packages/web-components/src/components/ui-shell/header-name.ts b/packages/web-components/src/components/ui-shell/header-name.ts new file mode 100644 index 000000000000..bcfdbaafcfc0 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header-name.ts @@ -0,0 +1,62 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ifDefined } from 'lit/directives/if-defined.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import styles from './header.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * The product name UI in header nav. + * + * @element cds-header-name + * @csspart link The link. + * @csspart prefix The prefix content. + */ +@customElement(`${prefix}-header-name`) +class CDSHeaderName extends FocusMixin(LitElement) { + /** + * Link `href`. + */ + @property() + href!: string; + + /** + * The product name prefix. + */ + @property() + prefix!: string; + + render() { + const { href, prefix: namePrefix } = this; + const namePrefixPart = !namePrefix + ? undefined + : html` + ${namePrefix} + `; + return html` + ${namePrefixPart}  + `; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSHeaderName; diff --git a/packages/web-components/src/components/ui-shell/header-nav-item.ts b/packages/web-components/src/components/ui-shell/header-nav-item.ts new file mode 100644 index 000000000000..5ebf54b3e8d0 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header-nav-item.ts @@ -0,0 +1,100 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ifDefined } from 'lit/directives/if-defined.js'; +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import styles from './header.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Header nav item. + * + * @element cds-header-nav-item + * @csspart link The link. + * @csspart title The title. + */ +@customElement(`${prefix}-header-nav-item`) +class CDSHeaderNavItem extends FocusMixin(LitElement) { + /** + * Link `href`. + */ + @property() + href!: string; + + /** + * The link type. + */ + @property({ reflect: true }) + rel!: string; + + /** + * The link target. + */ + @property({ reflect: true }) + target!: string; + + /** + * The title. + */ + @property() + title!: string; + + /** + * Applies selected styles to the item if a user sets this to true and `aria-current !== 'page'`. + */ + @property({ type: Boolean, attribute: 'is-active' }) + isActive = false; + + /** + * indicates that this element represents the current item + */ + @property({ type: String, attribute: 'aria-current' }) + ariaCurrent; + + /** + * As child of
      , this element must have role of listitem + */ + @property({ reflect: true }) + role = 'listitem'; + + render() { + const { ariaCurrent, href, isActive, title, rel, target } = this; + const linkClass = classMap({ + [`${prefix}--header__menu-item`]: true, + [`${prefix}--header__menu-item--current`]: + isActive && ariaCurrent !== 'page', + }); + + return html` + + ${title} + + `; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSHeaderNavItem; diff --git a/packages/web-components/src/components/ui-shell/header-nav.ts b/packages/web-components/src/components/ui-shell/header-nav.ts new file mode 100644 index 000000000000..59ef4b5ef043 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header-nav.ts @@ -0,0 +1,54 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import styles from './header.scss?lit'; + +/** + * Header. + * + * @element cds-header-nav + * @csspart menu-body The menu body. + * @csspart divider The divider. + */ +@customElement(`${prefix}-header-nav`) +class CDSHeaderNav extends LitElement { + /** + * The `aria-label` attribute for the menu bar UI. + */ + @property({ attribute: 'menu-bar-label' }) + menuBarLabel!: string; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'navigation'); + } + super.connectedCallback(); + } + + render() { + const { menuBarLabel } = this; + return html` +
      +
        + +
      + `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSHeaderNav; diff --git a/packages/web-components/src/components/ui-shell/header-panel.ts b/packages/web-components/src/components/ui-shell/header-panel.ts new file mode 100644 index 000000000000..542def56119d --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header-panel.ts @@ -0,0 +1,41 @@ +/** + * @license + * + * Copyright IBM Corp. 2023, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import styles from './header.scss?lit'; +import { prefix } from '../../globals/settings'; + +/** + * Header panel + * + * @element cds-header-panel + */ +@customElement(`${prefix}-header-panel`) +class CDSHeaderPanel extends LitElement { + /** + * Specify whether the panel is expanded + */ + @property({ type: Boolean, reflect: true }) + expanded; + + render() { + return html``; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSHeaderPanel; diff --git a/packages/web-components/src/components/ui-shell/header-side-nav-items.ts b/packages/web-components/src/components/ui-shell/header-side-nav-items.ts new file mode 100644 index 000000000000..db945ebb4752 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header-side-nav-items.ts @@ -0,0 +1,44 @@ +/** + * @license + * + * Copyright IBM Corp. 2023, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { prefix } from '../../globals/settings'; +import styles from './side-nav.scss?lit'; + +/** + * Header Side Nav Items section + * + * @element cds-header-side-nav-items + */ +@customElement(`${prefix}-header-side-nav-items`) +class CDSHeaderSideNavItems extends LitElement { + /** + * Optionally specify if container will have a bottom divider to differentiate + * between original sidenav items and header menu items. False by default. + */ + @property({ type: Boolean, attribute: 'has-divider' }) + hasDivider = false; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'list'); + } + super.connectedCallback(); + } + + render() { + return html``; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSHeaderSideNavItems; diff --git a/packages/web-components/src/components/ui-shell/header.scss b/packages/web-components/src/components/ui-shell/header.scss new file mode 100644 index 000000000000..3a057c0f729d --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header.scss @@ -0,0 +1,165 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/breakpoint' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/utilities' as *; +@use '@carbon/styles/scss/components/button'; +@use '@carbon/styles/scss/components/popover/index'; +@use '@carbon/styles/scss/components/tooltip'; +@use '@carbon/styles/scss/components/ui-shell/header'; +@use '@carbon/styles/scss/components/ui-shell/header-panel'; +@use '@carbon/styles/scss/components/ui-shell/switcher'; + +:host(#{$prefix}-header) { + @extend .#{$prefix}--header; + + ::slotted(.#{$prefix}--header__global) { + @extend .#{$prefix}--header__global; + } +} + +:host(#{$prefix}-header-nav) { + @extend .#{$prefix}--header__nav; + + .#{$prefix}-ce--header__divider { + position: absolute; + background-color: $border-subtle; + block-size: $spacing-06; + inline-size: rem(1px); + inset-block-start: 50%; + inset-inline-start: 0; + transform: translateY(-50%); + } +} + +:host(#{$prefix}-header-nav-item) { + outline: none; +} + +:host(#{$prefix}-header-menu) { + @extend .#{$prefix}--header__submenu; + + outline: none; +} + +:host(#{$prefix}-header-menu-item) { + outline: none; + + a.#{$prefix}--header__menu-item { + background-color: $layer; + block-size: $spacing-09; + + &:hover { + background-color: $background-hover; + color: $text-primary; + } + + &:active { + background-color: $background-active; + } + } + + a.#{$prefix}--header__menu-item--current { + background-color: $layer-selected; + + &:hover { + background-color: $layer-selected-hover; + } + + &::after { + position: absolute; + background-color: $border-interactive; + block-size: 100%; + content: ''; + inline-size: 3px; + inset-block: -#{$spacing-01}; + inset-inline-start: -#{$spacing-01}; + } + } +} + +:host(#{$prefix}-header-global-action) { + ::slotted(svg) { + fill: $icon-secondary; + } + + &:hover ::slotted(svg) { + fill: $icon-primary; + } + + .#{$prefix}--popover { + z-index: 8001; + } +} + +:host(#{$prefix}-header-nav-item), +:host(#{$prefix}-header-menu) { + a.#{$prefix}--header__menu-item { + box-sizing: border-box; + } +} + +:host(#{$prefix}-header-menu-button) { + display: content; + outline: none; + + @include breakpoint('lg') { + display: none; + } +} + +:host(#{$prefix}-header-menu-button[collapse-mode='fixed']) { + display: none; +} + +:host(#{$prefix}-header-menu-button[collapse-mode='rail']) { + @include breakpoint('lg') { + display: block; + } +} + +:host(#{$prefix}-header-name) { + display: content; + block-size: 100%; + + a { + box-sizing: border-box; + } +} + +:host(#{$prefix}-header-panel) { + @extend .#{$prefix}--header-panel; +} + +:host(#{$prefix}-header-panel[expanded]) { + @extend .#{$prefix}--header-panel--expanded; +} + +:host(#{$prefix}-switcher) { + @extend .#{$prefix}--switcher; +} + +:host(#{$prefix}-switcher-item) { + @extend .#{$prefix}--switcher__item; + + a { + box-sizing: border-box; + } +} + +:host(#{$prefix}-switcher-item:nth-child(1)) { + margin-block-start: $spacing-05; +} + +:host(#{$prefix}-switcher-divider) { + @extend .#{$prefix}--switcher__item--divider; +} diff --git a/packages/web-components/src/components/ui-shell/header.ts b/packages/web-components/src/components/ui-shell/header.ts new file mode 100644 index 000000000000..fe935443b346 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/header.ts @@ -0,0 +1,36 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import styles from './header.scss?lit'; + +/** + * Header. + * + * @element cds-header + */ +@customElement(`${prefix}-header`) +class CDSHeader extends LitElement { + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'banner'); + } + super.connectedCallback(); + } + + render() { + return html` `; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSHeader; diff --git a/packages/web-components/src/components/ui-shell/index.ts b/packages/web-components/src/components/ui-shell/index.ts new file mode 100644 index 000000000000..0b9050d56e23 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/index.ts @@ -0,0 +1,28 @@ +/** + * @license + * + * Copyright IBM Corp. 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './header'; +import './header-global-action'; +import './header-menu'; +import './header-menu-button'; +import './header-menu-item'; +import './header-name'; +import './header-nav'; +import './header-nav-item'; +import './header-panel'; +import './header-side-nav-items'; +import './side-nav'; +import './side-nav-divider'; +import './side-nav-items'; +import './side-nav-link'; +import './side-nav-menu'; +import './side-nav-menu-item'; +import './switcher'; +import './switcher-divider'; +import './switcher-item'; diff --git a/packages/web-components/src/components/ui-shell/side-nav-divider.ts b/packages/web-components/src/components/ui-shell/side-nav-divider.ts new file mode 100644 index 000000000000..2ef2278a9592 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/side-nav-divider.ts @@ -0,0 +1,32 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement } from 'lit'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import styles from './side-nav.scss?lit'; + +/** + * A divider in side nav. + * + * @element cds-side-nav-divider + */ +@customElement(`${prefix}-side-nav-divider`) +class CDSSideNavDivider extends LitElement { + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'separator'); + } + super.connectedCallback(); + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSSideNavDivider; diff --git a/packages/web-components/src/components/ui-shell/side-nav-items.ts b/packages/web-components/src/components/ui-shell/side-nav-items.ts new file mode 100644 index 000000000000..9a5656dde137 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/side-nav-items.ts @@ -0,0 +1,36 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { prefix } from '../../globals/settings'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import styles from './side-nav.scss?lit'; + +/** + * Side nav items. + * + * @element cds-side-nav-items + */ +@customElement(`${prefix}-side-nav-items`) +class CDSSideNavItems extends LitElement { + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'list'); + } + super.connectedCallback(); + } + + render() { + return html``; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSSideNavItems; diff --git a/packages/web-components/src/components/ui-shell/side-nav-link.ts b/packages/web-components/src/components/ui-shell/side-nav-link.ts new file mode 100644 index 000000000000..726c9ebbc37c --- /dev/null +++ b/packages/web-components/src/components/ui-shell/side-nav-link.ts @@ -0,0 +1,131 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import styles from './side-nav.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Side nav menu item. + * + * @element cds-side-nav-link + * @slot link - The link. + * @slot title - The title. + * @slot title-icon-container - The title icon container. + */ +@customElement(`${prefix}-side-nav-link`) +class CDSSideNavLink extends FocusMixin(LitElement) { + /** + * The container for the title icon. + */ + @query('#title-icon-container') + private _titleIconContainerNode!: HTMLDivElement; + + /** + * Handles `slotchange` event on the `` for the title icon. + */ + private _handleSlotChangeTitleIcon({ target }) { + this._titleIconContainerNode?.toggleAttribute( + 'hidden', + target.assignedNodes().length === 0 + ); + } + + /** + * `true` if the menu item should be active. + */ + @property({ type: Boolean, reflect: true }) + active = false; + + /** + * Link `href`. + */ + @property() + href = ''; + + /** + * The link type. + */ + @property({ reflect: true }) + rel!: string; + + /** + * The link target. + */ + @property({ reflect: true }) + target!: string; + + /** + * Specify if this is a large variation of the side nav link + */ + @property({ type: Boolean, reflect: true }) + large = false; + + /** + * The title. + */ + @property() + title!: string; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'listitem'); + } + super.connectedCallback(); + } + + render() { + const { + active, + href, + rel, + target, + title, + _handleSlotChangeTitleIcon: handleSlotChangeTitleIcon, + } = this; + const classes = classMap({ + [`${prefix}--side-nav__link`]: true, + [`${prefix}--side-nav__link--current`]: active, + }); + return html` + + + + ${title} + + + `; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSSideNavLink; diff --git a/packages/web-components/src/components/ui-shell/side-nav-menu-item.ts b/packages/web-components/src/components/ui-shell/side-nav-menu-item.ts new file mode 100644 index 000000000000..13872b645238 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/side-nav-menu-item.ts @@ -0,0 +1,93 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import CDSSideNavMenu from './side-nav-menu'; +import styles from './side-nav.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Side nav menu item. + * + * @element cds-side-nav-menu-item + * @csspart link The link. + * @csspart title The title. + */ +@customElement(`${prefix}-side-nav-menu-item`) +class CDSSideNavMenuItem extends FocusMixin(LitElement) { + /** + * `true` if the menu item should be active. + */ + @property({ type: Boolean, reflect: true }) + active = false; + + /** + * Link `href`. + */ + @property() + href = ''; + + /** + * The title. + */ + @property() + title!: string; + + shouldUpdate(changedProperties) { + if (changedProperties.has('active') && this.active) { + const { selectorMenu } = this.constructor as typeof CDSSideNavMenuItem; + const parent = this.closest(selectorMenu); + if (parent) { + (parent as CDSSideNavMenu).active = true; + } + } + return true; + } + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'button'); + } + super.connectedCallback(); + } + + render() { + const { active, href, title } = this; + const classes = classMap({ + [`${prefix}--side-nav__link`]: true, + [`${prefix}--side-nav__link--current`]: active, + }); + return html` + + + ${title} + + + `; + } + + /** + * A selector that will return the parent menu. + */ + static get selectorMenu() { + return `${prefix}-side-nav-menu`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSSideNavMenuItem; diff --git a/packages/web-components/src/components/ui-shell/side-nav-menu.ts b/packages/web-components/src/components/ui-shell/side-nav-menu.ts new file mode 100644 index 000000000000..2e5d8fb08115 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/side-nav-menu.ts @@ -0,0 +1,228 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property, query } from 'lit/decorators.js'; +import ChevronDown20 from '@carbon/icons/lib/chevron--down/20'; +import { prefix } from '../../globals/settings'; +import { forEach } from '../../globals/internal/collection-helpers'; +import FocusMixin from '../../globals/mixins/focus'; +import styles from './side-nav.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * Side nav menu. + * + * @element cds-side-nav-menu + * @fires cds-side-nav-menu-beingtoggled + * The name of the custom event fired before this side nav menu is being toggled upon a user gesture. + * Cancellation of this event stops the user-initiated action of toggling this side nav menu. + * @fires cds-side-nav-menu-toggled + * The name of the custom event fired after this side nav menu is toggled upon a user gesture. + * @slot title-icon - The icon. + * @csspart expando The expando. + * @csspart expando-icon-container The expando icon container. + * @csspart expando-icon The expando icon. + * @csspart title The title. + * @csspart title-icon-container The title icon container. + * @csspart menu-body The menu body. + */ +@customElement(`${prefix}-side-nav-menu`) +class CDSSideNavMenu extends FocusMixin(LitElement) { + /** + * `true` if this menu has an icon. + */ + private _hasIcon = false; + + /** + * The container for the title icon. + */ + @query('#title-icon-container') + private _titleIconContainerNode!: HTMLDivElement; + + /** + * Handles user-initiated toggle request of this side nav menu. + * + * @param expanded The new expanded state. + */ + private _handleUserInitiatedToggle(expanded = !this.expanded) { + const { eventBeforeToggle, eventToggle } = this + .constructor as typeof CDSSideNavMenu; + const init = { + bubbles: true, + cancelable: true, + composed: true, + detail: { + expanded, + }, + }; + if (this.dispatchEvent(new CustomEvent(eventBeforeToggle, init))) { + this.expanded = expanded; + this.dispatchEvent(new CustomEvent(eventToggle, init)); + } + } + + /** + * Handler for the `click` event on the expando button. + */ + private _handleClickExpando() { + this._handleUserInitiatedToggle(); + } + + /** + * Handles `slotchange` event on the non-named ``. + */ + private _handleSlotChange({ target }) { + const { _hasIcon: hasIcon } = this; + forEach(target.assignedNodes(), (item) => { + if (item.nodeType === Node.ELEMENT_NODE) { + item.toggleAttribute( + (this.constructor as typeof CDSSideNavMenu).attribItemHasIcon, + hasIcon + ); + } + }); + } + + /** + * Handles `slotchange` event on the `` for the title icon. + */ + private _handleSlotChangeTitleIcon({ target }) { + const constructor = this.constructor as typeof CDSSideNavMenu; + const hasIcon = target.assignedNodes().length > 0; + this._hasIcon = hasIcon; + this._titleIconContainerNode?.toggleAttribute('hidden', !hasIcon); + forEach(this.querySelectorAll(constructor.selectorItem), (item) => { + item.toggleAttribute(constructor.attribItemHasIcon, hasIcon); + }); + } + + /** + * `true` if the menu has active menu item. + */ + @property({ type: Boolean, reflect: true }) + active = false; + + /** + * `true` if the menu should be open. + */ + @property({ type: Boolean, reflect: true }) + expanded = false; + + /** + * Specify if this is a large variation of the side nav menu + */ + @property({ type: Boolean, reflect: true }) + large = false; + + /** + * `true` if the menu should be forced collapsed upon side nav's expanded state. + */ + @property({ type: Boolean, reflect: true, attribute: 'force-collapsed' }) + forceCollapsed = false; + + /** + * The title text. + */ + @property() + title = ''; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'listitem'); + } + super.connectedCallback(); + } + + updated(changedProperties) { + if (changedProperties.has('expanded')) { + const { selectorItem } = this.constructor as typeof CDSSideNavMenu; + const { expanded } = this; + forEach(this.querySelectorAll(selectorItem), (elem) => { + (elem as HTMLElement).tabIndex = expanded ? 0 : -1; + }); + } + } + + render() { + const { + expanded, + forceCollapsed, + title, + _handleClickExpando: handleClickExpando, + _handleSlotChange: handleSlotChange, + _handleSlotChangeTitleIcon: handleSlotChangeTitleIcon, + } = this; + return html` + +
        + +
      + `; + } + + /** + * The attribute name of the menu items, that is set if this menu has an icon. + */ + static attribItemHasIcon = 'parent-has-icon'; + + /** + * A selector that will return the menu items. + */ + static get selectorItem() { + return `${prefix}-side-nav-menu-item`; + } + + /** + * The name of the custom event fired before this side nav menu is being toggled upon a user gesture. + * Cancellation of this event stops the user-initiated action of toggling this side nav menu. + */ + static get eventBeforeToggle() { + return `${prefix}-side-nav-menu-beingtoggled`; + } + + /** + * The name of the custom event fired after this side nav menu is toggled upon a user gesture. + */ + static get eventToggle() { + return `${prefix}-side-nav-menu-toggled`; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSSideNavMenu; diff --git a/packages/web-components/src/components/ui-shell/side-nav.scss b/packages/web-components/src/components/ui-shell/side-nav.scss new file mode 100644 index 000000000000..91f7a93afcfd --- /dev/null +++ b/packages/web-components/src/components/ui-shell/side-nav.scss @@ -0,0 +1,143 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/breakpoint' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/theme' as *; +@use '@carbon/styles/scss/components/ui-shell/side-nav'; + +:host(#{$prefix}-side-nav[expanded]) ::slotted(#{$prefix}-side-nav-items) { + overflow-y: auto; +} + +:host(#{$prefix}-side-nav-items) { + @extend .#{$prefix}--side-nav__items; +} + +:host(#{$prefix}-side-nav-link) { + @extend .#{$prefix}--side-nav__item; + + display: block; + block-size: auto; + inline-size: auto; + outline: none; + + .#{$prefix}--side-nav__icon { + // TODO: audit + color: $text-primary; + + &[hidden] { + display: none; + } + } +} + +:host(#{$prefix}-side-nav-link[large]) { + @extend .#{$prefix}--side-nav__item--large; +} + +:host(#{$prefix}-side-nav-divider) { + @extend .#{$prefix}--side-nav__divider; + + display: block; +} + +:host(#{$prefix}-side-nav-menu) { + @extend .#{$prefix}--side-nav__item; + + display: block; + + .#{$prefix}--side-nav__icon[hidden] { + display: none; + } + + .#{$prefix}--side-nav__menu { + padding: 0; + margin: 0; + } + + .#{$prefix}--side-nav__submenu[aria-expanded='true'] + + .#{$prefix}--side-nav__menu { + max-block-size: none; + } +} + +:host(#{$prefix}-side-nav-menu[active]) { + @extend .#{$prefix}--side-nav__item--active; + + position: relative; + + // TODO: audit + color: $text-primary; + + &::before { + position: absolute; + background-color: $border-interactive; + content: ''; + inline-size: $spacing-02; + inset-block: 0; + inset-inline-start: 0; + } +} + +:host(#{$prefix}-side-nav-menu[active][expanded]) { + position: inherit; + background-color: inherit; + color: inherit; + + &::before { + content: none; + } +} + +:host(#{$prefix}-side-nav-menu[has-icon]) { + @extend .#{$prefix}--side-nav__item--icon; +} + +:host(#{$prefix}-side-nav-menu[large]) { + @extend .#{$prefix}--side-nav__item--large; +} + +:host(#{$prefix}-side-nav-menu-item) { + @extend .#{$prefix}--side-nav__menu-item; + + display: block; + block-size: auto; + inline-size: auto; + outline: none; + + a.#{$prefix}--side-nav__link { + block-size: $spacing-07; + font-weight: 400; + min-block-size: $spacing-07; + padding-inline-start: $spacing-07; + } +} + +:host(#{$prefix}-side-nav-menu-item[parent-has-icon]) + a.#{$prefix}--side-nav__link { + padding-inline-start: 4.5rem; +} + +:host(#{$prefix}-side-nav-item) .#{$prefix}--side-nav__link:hover, +:host(#{$prefix}-side-nav-menu) .#{$prefix}--side-nav__submenu:hover, +:host(#{$prefix}-side-nav-menu-item) .#{$prefix}--side-nav__link:hover { + // TODO: audit + background-color: $background-hover; + color: $text-primary; +} + +:host(#{$prefix}-header-side-nav-items) { + @extend .#{$prefix}--side-nav__header-navigation; +} + +:host(#{$prefix}-header-side-nav-items[has-divider]) { + @extend .#{$prefix}--side-nav__header-divider; +} diff --git a/packages/web-components/src/components/ui-shell/side-nav.ts b/packages/web-components/src/components/ui-shell/side-nav.ts new file mode 100644 index 000000000000..4a7c750e5185 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/side-nav.ts @@ -0,0 +1,303 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import { prefix } from '../../globals/settings'; +import HostListenerMixin from '../../globals/mixins/host-listener'; +import HostListener from '../../globals/decorators/host-listener'; +import { forEach } from '../../globals/internal/collection-helpers'; +import Handle from '../../globals/internal/handle'; +import { SIDE_NAV_COLLAPSE_MODE, SIDE_NAV_USAGE_MODE } from './defs'; +import CDSHeaderMenuButton from './header-menu-button'; +import CDSSideNavMenu from './side-nav-menu'; +import styles from './side-nav.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +export { SIDE_NAV_COLLAPSE_MODE, SIDE_NAV_USAGE_MODE }; + +/** + * Side nav. + * + * @element cds-side-nav + * @fires cds-header-menu-button-toggled + * The name of the custom event fired after the header menu button in the document is toggled upon a user gesture. + */ +@customElement(`${prefix}-side-nav`) +class CDSSideNav extends HostListenerMixin(LitElement) { + /** + * `true` if this side nav is hovered. + */ + private _hovered = false; + + /** + * The handle for `transitionend` event listener. + */ + private _hTransition: Handle | null = null; + + /** + * Cleans the handle for `transitionend` event listener. + */ + private _cleanHTransition() { + if (this._hTransition) { + this._hTransition = this._hTransition.release(); + } + } + + /** + * Handles `${prefix}-header-menu-button-toggle` event on the document. + */ + @HostListener('parentRoot:eventButtonToggle') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + protected _handleButtonToggle = async (event: CustomEvent) => { + this.expanded = event.detail.active; + }; + + /** + * Force child side nav menus collapsed upon the hover/expanded state of this side nav. + */ + private _updatedSideNavMenuForceCollapsedState() { + const { expanded, _hovered: hovered } = this; + forEach( + this.querySelectorAll( + (this.constructor as typeof CDSSideNav).selectorMenu + ), + (item) => { + (item as CDSSideNavMenu).forceCollapsed = !expanded && !hovered; + } + ); + } + + /** + * Collapse mode of the side nav. + */ + @property({ reflect: true, attribute: 'collapse-mode' }) + collapseMode = SIDE_NAV_COLLAPSE_MODE.RESPONSIVE; + + /** + * `true` to expand the side nav. + */ + @property({ type: Boolean, reflect: true }) + expanded = false; + + /** + * If `true` will style the side nav to sit below the header + */ + @property({ + type: Boolean, + attribute: 'is-not-child-of-header', + }) + isNotChildOfHeader = false; + + /** + * Specify if the side-nav will be persistent above the lg breakpoint + */ + @property({ type: Boolean, reflect: true, attribute: 'is-not-persistent' }) + isNotPersistent = false; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'navigation'); + } + super.connectedCallback(); + } + + disconnectedCallback() { + this._cleanHTransition(); + super.disconnectedCallback(); + } + + updated(changedProperties) { + const doc = this.getRootNode() as Document; + if (changedProperties.has('collapseMode')) { + forEach( + doc.querySelectorAll( + (this.constructor as typeof CDSSideNav).selectorButtonToggle + ), + (item) => { + (item as CDSHeaderMenuButton).collapseMode = this.collapseMode; + } + ); + } + if (changedProperties.has('expanded')) { + const headerItems = doc.querySelectorAll( + (this.constructor as typeof CDSSideNav).selectorHeaderItems + ); + forEach( + doc.querySelectorAll( + (this.constructor as typeof CDSSideNav).selectorButtonToggle + ), + (item) => { + (item as CDSHeaderMenuButton).active = this.expanded; + } + ); + if (this.expanded) { + forEach(headerItems, (item) => { + item.setAttribute('tabindex', '-1'); + }); + ( + this.querySelector( + (this.constructor as typeof CDSSideNav).selectorNavItems + ) as HTMLElement + )?.focus(); + } else { + forEach(headerItems, (item) => { + item.removeAttribute('tabindex'); + }); + } + } + if (changedProperties.has('isNotChildOfHeader')) { + forEach( + doc.querySelectorAll( + (this.constructor as typeof CDSSideNav).selectorButtonToggle + ), + (item) => { + (item as CDSHeaderMenuButton).isNotChildOfHeader = + this.isNotChildOfHeader; + } + ); + } + } + + /** + * Handles `blur` event handler on this element. + * + * @param event The event. + * @param event.relatedTarget The event relatedTarget. + */ + @HostListener('focusout') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleFocusOut({ relatedTarget }: FocusEvent) { + const { collapseMode } = this; + if (collapseMode !== SIDE_NAV_COLLAPSE_MODE.FIXED) { + if (!this.contains(relatedTarget as Node)) { + this.expanded = false; + } + } + } + + /** + * Handles `focus` event handler on this element. + * + */ + @HostListener('focusin') + // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to + private _handleFocusIn() { + const { collapseMode } = this; + if (collapseMode !== SIDE_NAV_COLLAPSE_MODE.FIXED) { + this.expanded = true; + } + } + + /** + * Handles the `mouseover` event for the side nav in rail mode. + * + */ + private _handleNavMouseOver() { + const { collapseMode } = this; + if (collapseMode === SIDE_NAV_COLLAPSE_MODE.RAIL) { + this.expanded = true; + this._hovered = true; + this._updatedSideNavMenuForceCollapsedState(); + } + } + + /** + * Handles the `mouseout` event for the side nav in rail mode. + * + */ + private _handleNavMouseOut() { + const { collapseMode } = this; + if (collapseMode === SIDE_NAV_COLLAPSE_MODE.RAIL) { + this.expanded = false; + this._hovered = false; + this._updatedSideNavMenuForceCollapsedState(); + } + } + + /** + * Handles the `click` event for the side nav overlay. + * + */ + private _onOverlayClick() { + this.expanded = false; + } + + render() { + const { collapseMode, expanded, isNotChildOfHeader, isNotPersistent } = + this; + const classes = classMap({ + [`${prefix}--side-nav__navigation`]: true, + [`${prefix}--side-nav`]: true, + [`${prefix}--side-nav--expanded`]: expanded, + [`${prefix}--side-nav--collapsed`]: + !expanded && collapseMode === SIDE_NAV_COLLAPSE_MODE.FIXED, + [`${prefix}--side-nav--rail`]: + collapseMode === SIDE_NAV_COLLAPSE_MODE.RAIL, + [`${prefix}--side-nav--ux`]: !isNotChildOfHeader, + [`${prefix}--side-nav--hidden`]: isNotPersistent, + }); + + const overlayClasses = classMap({ + [`${prefix}--side-nav__overlay`]: true, + [`${prefix}--side-nav__overlay-active`]: expanded, + }); + return html`${this.collapseMode === SIDE_NAV_COLLAPSE_MODE.FIXED + ? null + : html`
      `} +
      + +
      `; + } + + /** + * A selector that will return the toggle buttons. + */ + static get selectorButtonToggle() { + return `${prefix}-header-menu-button`; + } + + /** + * A selector that will return the header name + global action elements. + */ + static get selectorHeaderItems() { + return `${prefix}-header-name, ${prefix}-header-global-action`; + } + + /** + * A selector that will return side nav focusable items. + */ + static get selectorNavItems() { + return `${prefix}-side-nav-menu, ${prefix}-side-nav-menu-item, ${prefix}-side-nav-link`; + } + + /** + * A selector that will return side nav menus. + */ + static get selectorMenu() { + return `${prefix}-side-nav-menu`; + } + + /** + * The name of the custom event fired after the header menu button in the document is toggled upon a user gesture. + */ + static get eventButtonToggle() { + return `${prefix}-header-menu-button-toggled`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSSideNav; diff --git a/packages/web-components/src/components/ui-shell/switcher-divider.ts b/packages/web-components/src/components/ui-shell/switcher-divider.ts new file mode 100644 index 000000000000..096301e6859b --- /dev/null +++ b/packages/web-components/src/components/ui-shell/switcher-divider.ts @@ -0,0 +1,32 @@ +/** + * @license + * + * Copyright IBM Corp. 2023, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement } from 'lit'; +import { prefix } from '../../globals/settings'; +import styles from './header.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +/** + * A divider in switcher. + * + * @element cds-switcher-divider + */ +@customElement(`${prefix}-switcher-divider`) +class CDSSwitcherDivider extends LitElement { + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'separator'); + } + super.connectedCallback(); + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSSwitcherDivider; diff --git a/packages/web-components/src/components/ui-shell/switcher-item.ts b/packages/web-components/src/components/ui-shell/switcher-item.ts new file mode 100644 index 000000000000..007851446534 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/switcher-item.ts @@ -0,0 +1,90 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { classMap } from 'lit/directives/class-map.js'; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import { prefix } from '../../globals/settings'; +import FocusMixin from '../../globals/mixins/focus'; +import styles from './header.scss?lit'; + +/** + * Switcher menu item. + * + * @element cds-switcher-item + */ +@customElement(`${prefix}-switcher-item`) +class CDSSwitcherItem extends FocusMixin(LitElement) { + /** + * Required props for accessibility label + */ + @property({ type: String, attribute: 'aria-label' }) + ariaLabel; + + /** + * Props for accessibility labelled by + */ + @property({ type: String, attribute: 'aria-labelledby' }) + ariaLabelledBy; + + /** + * Link `href`. + */ + @property() + href = ''; + + /** + * Specify if this is a large variation of the side nav link + */ + @property({ type: Boolean, reflect: true }) + selected = false; + + /** + * Specify if this is a large variation of the side nav link + */ + @property({ type: Number, reflect: true, attribute: 'tab-index' }) + tabIndex = 0; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'listitem'); + } + super.connectedCallback(); + } + + render() { + const { href, selected, ariaLabel, ariaLabelledBy, tabIndex } = this; + + const classes = classMap({ + [`${prefix}--switcher__item-link`]: true, + [`${prefix}--switcher__item-link--selected`]: selected, + }); + + return html` + + + + `; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSSwitcherItem; diff --git a/packages/web-components/src/components/ui-shell/switcher.ts b/packages/web-components/src/components/ui-shell/switcher.ts new file mode 100644 index 000000000000..1a46261add26 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/switcher.ts @@ -0,0 +1,54 @@ +/** + * @license + * + * Copyright IBM Corp. 2023, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; +import styles from './header.scss?lit'; +import { prefix } from '../../globals/settings'; + +/** + * Switcher + * + * @element cds-switcher + */ +@customElement(`${prefix}-switcher`) +class CDSSwitcher extends LitElement { + /** + * Required props for accessibility label on the underlying menu + */ + @property({ type: String, attribute: 'aria-label' }) + ariaLabel; + + /** + * Prop for accessibility labelled by on the underlying menu + */ + @property({ type: String, attribute: 'aria-labelledby' }) + ariaLabelledBy; + + connectedCallback() { + if (!this.hasAttribute('role')) { + this.setAttribute('role', 'list'); + } + super.connectedCallback(); + } + + render() { + return html``; + } + + static shadowRootOptions = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSSwitcher; diff --git a/packages/web-components/src/components/ui-shell/ui-shell-story.scss b/packages/web-components/src/components/ui-shell/ui-shell-story.scss new file mode 100644 index 000000000000..cd36a14ce59a --- /dev/null +++ b/packages/web-components/src/components/ui-shell/ui-shell-story.scss @@ -0,0 +1,26 @@ +// +// Copyright IBM Corp. 2020, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/breakpoint' as *; +@use '@carbon/styles/scss/spacing' as *; +@use '@carbon/styles/scss/components/ui-shell/functions'; + +#{$prefix}-header ~ #{$prefix}-side-nav { + block-size: calc(100% - $spacing-09); + margin-block-start: $spacing-09; +} + +.#{$prefix}-ce-demo-devenv--container { + transition: margin-left 0.11s cubic-bezier(0.2, 0, 1, 0.9); + // Ref: https://github.com/carbon-design-system/carbon/blob/v10.10.0/packages/components/src/components/ui-shell/_side-nav.scss#L82 + will-change: margin-left; + + @include breakpoint('lg') { + margin-inline-start: 16rem; + } +} diff --git a/packages/web-components/src/components/ui-shell/ui-shell.mdx b/packages/web-components/src/components/ui-shell/ui-shell.mdx new file mode 100644 index 000000000000..2fc66add2b6f --- /dev/null +++ b/packages/web-components/src/components/ui-shell/ui-shell.mdx @@ -0,0 +1,257 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as UIShell from './ui-shell.stories'; + + + +# UI Shell + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/ui-shell) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/ui-shell) + +UI Shell in Carbon Design System consists of several component groups. + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/ui-shell/index.js'; +``` + +{`${cdnJs({ components: ['ui-shell'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + + + [Platform] + + Link 1 + Link 2 + Link 3 + + Sub-link 1 + Sub-link 2 + Sub-link 3 + + + + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + L0 link + L0 link + + +``` + +## Side nav + +Side nav in UI Shell consists of the following components: + +| Tag | Description | +| ---------------------- | ------------------------------------------------ | +| `` | The top-level container | +| `` | The container of the nav items | +| `` | Nav item, working as a link | +| `` | Nav item, working as a container of sub-items | +| `` | Nav item, working as as a sub-item and as a link | + +```html + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + L0 link + L0 link + + +``` + +### Expanding/collapsing + +`` has `expanded` attribute to make it expanded. In its collapsed +state, hovering over the side nav expands it temporarily. + +`` can be made non-collapsible, by setting `fixed` attribute. + +### Selecting a nav item + +Unlike ``, etc., user gesture of side nav item won't update the +selection by itself. The assumption is that following the link in +``/`` triggers routing in application, and +application chooses which ``/`` to set +`active` attribute to, with the new URL. + +### Using with header nav + +If `` is used along with header (``), the side nav +should be pushed down. To do that, add below style to your application: + +```css +cds-header ~ cds-side-nav { + margin-top: 3rem; + height: calc(100% - 3rem); +} +``` + +### `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `expanded` attribute). + + + +### `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `active` attribute). + + + +### `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `active` attribute). + + + +### `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `active` attribute). + + + +## Header nav + +Header nav in UI Shell consists of the following components: + +| Tag | Description | +| -------------------------- | --------------------------------------------- | +| `` | The top-level container | +| `` | The nav bar | +| `` | Nav item | +| `` | Nav item, working as a container of sub-items | +| `` | Nav item, working as as a sub-item | +| `` | The expando button for side nav | +| `` | The UI to show product name | + +### `` attributes and properties + + + +### `` attributes and properties + + + +### `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute (e.g. +`` without `expanded` attribute). + + + +### `` attributes and properties + +Note: For `boolean` attributes, `true` means simply setting the attribute (e.g. +``) and `false` means not setting the attribute +(e.g. `` without `active` attribute). + + + +### `` attributes and properties + + + +### `` attributes and properties + + diff --git a/packages/web-components/src/components/ui-shell/ui-shell.stories.ts b/packages/web-components/src/components/ui-shell/ui-shell.stories.ts new file mode 100644 index 000000000000..5c4892aec197 --- /dev/null +++ b/packages/web-components/src/components/ui-shell/ui-shell.stories.ts @@ -0,0 +1,1048 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +// Below path will be there when an application installs `@carbon/web-components` package. +// In our dev env, we auto-generate the file and re-map below path to to point to the generated file. +// @ts-ignore +import Fade16 from '@carbon/icons/lib/fade/16'; +import Search20 from '@carbon/icons/lib/search/20'; +import Notification20 from '@carbon/icons/lib/notification/20'; +import SwitcherIcon20 from '@carbon/icons/lib/switcher/20'; +import contentStyles from '@carbon/styles/scss/components/ui-shell/content/_content.scss?lit'; +import { SIDE_NAV_COLLAPSE_MODE, SIDE_NAV_USAGE_MODE } from './side-nav'; +import { classMap } from 'lit/directives/class-map.js'; +import './index'; +import '../skip-to-content'; +import '../modal/modal'; +import '../button/button'; +import styles from './ui-shell-story.scss?lit'; +import { prefix } from '../../globals/settings'; + +const linksHref = 'https://www.carbondesignsystem.com/'; + +const StoryContent = ({ useResponsiveOffset = true }) => { + const firstColumnClasses = classMap({ + [`${prefix}--col-lg-13`]: true, + [`${prefix}--offset-lg-3`]: useResponsiveOffset, + }); + const toggleButton = () => { + document.querySelector('cds-modal')?.toggleAttribute('open'); + }; + return html` + +
      +
      +
      +
      +

      Purpose and function

      +

      + The shell is perhaps the most crucial piece of any UI built with + Carbon. It contains the + shared navigation framework for the entire design system and ties + the products in IBM’s portfolio together in a cohesive and elegant + way. The shell is the home of the topmost navigation, where users + can quickly and dependably gain their bearings and move between + pages. +
      +
      + The shell was designed with maximum flexibility built in, to serve + the needs of a broad range of products and users. Adopting the + shell ensures compliance with IBM design standards, simplifies + development efforts, and provides great user experiences. All IBM + products built with Carbon are required to use the shell’s header. +
      +
      + To better understand the purpose and function of the UI shell, + consider the “shell” of MacOS, which contains the Apple menu, + top-level navigation, and universal, OS-level controls at the top + of the screen, as well as a universal dock along the bottom or + side of the screen. The Carbon UI shell is roughly analogous in + function to these parts of the Mac UI. For example, the app + switcher portion of the shell can be compared to the dock in + MacOS. +

      +

      Header responsive behavior

      +

      + As a header scales down to fit smaller screen sizes, headers with + persistent side nav menus should have the side nav collapse into + “hamburger” menu. See the example to better understand responsive + behavior of the header. +

      +

      Secondary navigation

      +

      + The side-nav contains secondary navigation and fits below the + header. It can be configured to be either fixed-width or flexible, + with only one level of nested items allowed. Both links and + category lists can be used in the side-nav and may be mixed + together. There are several configurations of the side-nav, but + only one configuration should be used per product section. If tabs + are needed on a page when using a side-nav, then the tabs are + secondary in hierarchy to the side-nav. +

      + + + + Account resources + Add a custom domain + + + + Custom domains direct requests for your apps in this Cloud + Foundry organization to a URL that you own. A custom domain + can be a shared domain, a shared subdomain, or a shared domain + and host. + + + + Cancel + Add + + + Launch modal +
      +
      +
      +
      + `; +}; + +export const FixedSideNav = { + name: 'Fixed SideNav', + render: () => { + const result = html` + + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + L0 link + L0 link + + + ${StoryContent({ useResponsiveOffset: false })} + `; + (result as any).hasMainTag = true; + return result; + }, +}; + +export const FixedSideNavDivider = { + name: 'Fixed SideNav w/Divider', + render: () => { + const result = html` + + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + + L0 menu item + + + L0 menu item + + + L0 menu item + + + + L0 link + L0 link + + + ${StoryContent({ useResponsiveOffset: false })} + `; + (result as any).hasMainTag = true; + return result; + }, +}; + +export const FixedSideNavIcons = { + name: 'Fixed SideNav w/ Icons', + render: () => { + const result = html` + + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + ${Fade16({ slot: 'title-icon' })}Link + ${Fade16({ slot: 'title-icon' })}Link + + + ${StoryContent({ useResponsiveOffset: false })} + `; + (result as any).hasMainTag = true; + return result; + }, +}; + +export const HeaderBase = { + render: () => + html` + + [Platform] + `, +}; + +export const HeaderBaseWActions = { + name: 'Header Base w/ Actions', + render: () => + html` + + [Platform] +
      + + ${Search20({ slot: 'icon' })} + + + ${Notification20({ slot: 'icon' })} + + + ${SwitcherIcon20({ slot: 'icon' })} + +
      +
      `, +}; + +export const HeaderBaseWActionsRightPanel = { + name: 'Header Base w/ Actions and Right Panel', + render: () => + html` + + [Platform] +
      + + ${Search20({ slot: 'icon' })} + + + ${Notification20({ slot: 'icon' })} + + + ${SwitcherIcon20({ slot: 'icon' })} + +
      + +
      `, +}; + +export const HeaderBaseWActionsSwitcher = { + name: 'Header Base w/ Actions and Switcher', + render: () => + html` + + [Platform] +
      + + ${Search20({ slot: 'icon' })} + + + ${Notification20({ slot: 'icon' })} + + + ${SwitcherIcon20({ slot: 'icon' })} + +
      + + + Link 1 + + Link 2 + Link 3 + Link 4 + Link 5 + + Link 6 + + +
      + ${StoryContent({ useResponsiveOffset: true })}`, +}; + +export const HeaderBaseWNavigationActionsAndSideNav = { + name: 'Header Base w/ Navigation, Actions and SideNav', + render: () => + html` + + + [Platform] + + Link 1 + Link 2 + Link 3 + + Sub-link 1 + Sub-link 2 + Sub-link 3 + + +
      + + ${Search20({ slot: 'icon' })} + + + ${Notification20({ slot: 'icon' })} + + + ${SwitcherIcon20({ slot: 'icon' })} + +
      + + + + + Link 1 + + + Link 2 + + + Link 3 + + + + Sub-link 1 + + + Sub-link 2 + + + Sub-link 3 + + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + ${Fade16({ slot: 'title-icon' })}Link + ${Fade16({ slot: 'title-icon' })}Link + + +
      + ${StoryContent({ useResponsiveOffset: true })}`, +}; + +export const HeaderBaseWNavigationActions = { + name: 'Header Base w/ Navigation and Actions', + render: () => + html` + + + [Platform] + + Link 1 + Link 2 + Link 3 + + Sub-link 1 + Sub-link 2 + Sub-link 3 + + +
      + + ${Search20({ slot: 'icon' })} + + + ${Notification20({ slot: 'icon' })} + + + ${SwitcherIcon20({ slot: 'icon' })} + +
      + + + + Link 1 + + + Link 2 + + + Link 3 + + + + Sub-link 1 + + + Sub-link 2 + + + Sub-link 3 + + + + +
      `, +}; + +export const HeaderBaseWNavigation = { + name: 'Header Base w/ Navigation', + render: () => + html` + + + [Platform] + + Link 1 + Link 2 + Link 3 + + Sub-link 1 + Sub-link 2 + Sub-link 3 + + + + + + Link 1 + + + Link 2 + + + Link 3 + + + + Sub-link 1 + + + Sub-link 2 + + + Sub-link 3 + + + + + `, +}; + +export const HeaderBaseWSideNav = { + name: 'Header Base w/ SideNav', + render: () => { + const result = html` + + + + [Platform] + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + ${Fade16({ slot: 'title-icon' })}Link + ${Fade16({ slot: 'title-icon' })}Link + + + + ${StoryContent({ useResponsiveOffset: true })} + `; + (result as any).hasMainTag = true; + return result; + }, +}; + +export const HeaderBaseWSkipToContent = { + name: 'Header Base w/ SkipToContent', + render: () => + html` + + + [Platform] +
      + + ${Search20({ slot: 'icon' })} + + + ${Notification20({ slot: 'icon' })} + + + ${SwitcherIcon20({ slot: 'icon' })} + +
      +
      + ${StoryContent({ useResponsiveOffset: true })}`, +}; + +export const SideNavRail = { + name: 'SideNav Rail', + render: () => + html` + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + ${Fade16({ slot: 'title-icon' })}Link + ${Fade16({ slot: 'title-icon' })}Link + + + ${StoryContent({ useResponsiveOffset: true })}`, +}; + +export const SideNavRailWHeader = { + name: 'SideNav Rail w/ Header', + render: () => + html` + + + [Platform] + + Link 1 + Link 2 + Link 3 + + Sub-link 1 + Sub-link 2 + Sub-link 3 + + +
      + + ${Search20({ slot: 'icon' })} + + + ${Notification20({ slot: 'icon' })} + + + ${SwitcherIcon20({ slot: 'icon' })} + +
      + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + + ${Fade16({ slot: 'title-icon' })} + + Link + + + Link + + + Link + + + ${Fade16({ slot: 'title-icon' })}Link + ${Fade16({ slot: 'title-icon' })}Link + + +
      + ${StoryContent({ useResponsiveOffset: true })}`, +}; + +export const SideNavWLargeSideNavItems = { + name: 'SideNav w/ large side nav items', + render: () => { + const result = html` + + + + + + Menu 1 + + + Menu 2 + + + Menu 3 + + + Large link + ${Fade16({ slot: 'title-icon' })} + + Menu 1 + + + Menu 2 + + + Menu 3 + + + + ${Fade16({ slot: 'title-icon' })} Large link + w/icon + + + ${StoryContent({ useResponsiveOffset: true })} + `; + (result as any).hasMainTag = true; + return result; + }, +}; + +export default { + title: 'Components/UI Shell', +}; diff --git a/packages/web-components/src/globals/controllers/popover-controller.ts b/packages/web-components/src/globals/controllers/popover-controller.ts new file mode 100644 index 000000000000..88c8c23d0b6e --- /dev/null +++ b/packages/web-components/src/globals/controllers/popover-controller.ts @@ -0,0 +1,159 @@ +/** + * @license + * + * Copyright IBM Corp. 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ReactiveController, LitElement } from 'lit'; +import { + computePosition, + flip, + offset, + arrow, + autoUpdate, + Placement, +} from '@floating-ui/dom'; + +type PopoverControllerOptions = { + target: HTMLElement; + trigger: HTMLElement; + arrowElement?: HTMLElement | undefined; + alignment: string; + flip: boolean; + caret: boolean; +}; + +interface PopoverElement extends LitElement { + open: boolean; +} + +export default class PopoverController implements ReactiveController { + /** + * Host component + */ + private host!: PopoverElement; + + /** + * Floating-ui options to pass to `computePlacement()` + */ + private options!: PopoverControllerOptions; + + /** + * cleanup function to stop auto updates + */ + private cleanup?: () => void; + + /** + * register with host component + * @param host host component + */ + constructor(host: PopoverElement) { + (this.host = host).addController(this); + } + + async setPlacement(options: PopoverControllerOptions = this.options) { + this.options = options; + const { trigger, target } = options; + + this.cleanup = autoUpdate(trigger, target, this.updatePlacement); + } + + updatePlacement = (): void => { + this.computePlacement(); + }; + + async computePlacement() { + const { arrowElement, alignment, caret, trigger, target } = this.options; + + let shimmedAlign; + switch (alignment) { + case 'top-left': + shimmedAlign = 'top-start'; + break; + case 'top-right': + shimmedAlign = 'top-end'; + break; + case 'bottom-left': + shimmedAlign = 'bottom-start'; + break; + case 'bottom-right': + shimmedAlign = 'bottom-end'; + break; + case 'left-bottom': + shimmedAlign = 'left-end'; + break; + case 'left-top': + shimmedAlign = 'left-start'; + break; + case 'right-bottom': + shimmedAlign = 'right-end'; + break; + case 'right-top': + shimmedAlign = 'right-start'; + break; + default: + shimmedAlign = alignment; + break; + } + + const middleware = [ + flip({ fallbackAxisSideDirection: 'start' }), + offset(caret ? 10 : 0), + ...(caret && arrowElement + ? [arrow({ element: arrowElement, padding: 15 })] + : []), + ]; + + if (this.host.hasAttribute('open')) { + const { x, y, placement, middlewareData, strategy } = + await computePosition(trigger, target, { + strategy: 'fixed', + middleware, + placement: shimmedAlign as Placement, + }); + + target.style.left = `${x}px`; + target.style.top = `${y}px`; + target.style.position = `${strategy}`; + + if (arrowElement) { + // @ts-ignore + const { x: arrowX, y: arrowY } = middlewareData.arrow; + + const staticSide: any = { + top: 'bottom', + right: 'left', + bottom: 'top', + left: 'right', + }[placement.split('-')[0]]; + + arrowElement.style.left = arrowX != null ? `${arrowX}px` : ''; + arrowElement.style.top = arrowY != null ? `${arrowY}px` : ''; + arrowElement.style.right = ''; + arrowElement.style.bottom = ''; + arrowElement.style[staticSide] = `${-arrowElement.offsetWidth / 2}px`; + } + + // adding specific case here where the style of the caret/arrow + // is dependent on the placement + if (this.host.tagName === 'CDS-SLUG') { + this.host?.setAttribute('alignment', placement); + } + } + } + + hostUpdated(): void { + if (!this.host.hasAttribute('open')) { + this.cleanup?.(); + this.cleanup = undefined; + } + } + + hostDisconnected(): void { + this.cleanup?.(); + this.cleanup = undefined; + } +} diff --git a/packages/web-components/src/globals/decorators/carbon-element.ts b/packages/web-components/src/globals/decorators/carbon-element.ts new file mode 100644 index 000000000000..f072ef13798c --- /dev/null +++ b/packages/web-components/src/globals/decorators/carbon-element.ts @@ -0,0 +1,93 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* + * IMPORTANT: For compatibility with tsickle and the Closure JS compiler, all + * property decorators (but not class decorators) in this file that have + * an @ExportDecoratedItems annotation must be defined as a regular function, + * not an arrow function. + */ +export declare type Constructor = { + new (...args: any[]): T; +}; +export interface ClassDescriptor { + kind: 'class'; + elements: ClassElement[]; + finisher?: (clazz: Constructor) => void | Constructor; +} +export interface ClassElement { + kind: 'field' | 'method'; + key: PropertyKey; + placement: 'static' | 'prototype' | 'own'; + initializer?: Function; + extras?: ClassElement[]; + finisher?: (clazz: Constructor) => void | Constructor; + descriptor?: PropertyDescriptor; +} + +/** + * Allow for custom element classes with private constructors + */ +type CustomElementClass = Omit; + +const legacyCustomElement = (tagName: string, clazz: CustomElementClass) => { + try { + customElements.define(tagName, clazz as CustomElementConstructor); + } catch (error) { + console.warn(`Attempting to re-define ${tagName}`); + } + // Cast as any because TS doesn't recognize the return type as being a + // subtype of the decorated class when clazz is typed as + // `Constructor` for some reason. + // `Constructor` is helpful to make sure the decorator is + // applied to elements however. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return clazz as any; +}; + +const standardCustomElement = ( + tagName: string, + descriptor: ClassDescriptor +) => { + const { kind, elements } = descriptor; + return { + kind, + elements, + // This callback is called once the class is otherwise fully defined + finisher(clazz: Constructor) { + try { + customElements.define(tagName, clazz); + } catch (error) { + console.warn(`Attempting to re-define ${tagName}`); + } + }, + }; +}; + +/** + * Class decorator factory that defines the decorated class as a custom element. + * + * ```js + * @customElement('my-element') + * class MyElement extends LitElement { + * render() { + * return html``; + * } + * } + * ``` + * + * @category Decorator + * @param tagName The tag name of the custom element to define. + */ +export const carbonElement = + (tagName: string) => + (classOrDescriptor: CustomElementClass | ClassDescriptor) => + typeof classOrDescriptor === 'function' + ? legacyCustomElement(tagName, classOrDescriptor) + : standardCustomElement(tagName, classOrDescriptor as ClassDescriptor); diff --git a/packages/web-components/src/globals/decorators/host-listener.ts b/packages/web-components/src/globals/decorators/host-listener.ts new file mode 100644 index 000000000000..15adcb7d4627 --- /dev/null +++ b/packages/web-components/src/globals/decorators/host-listener.ts @@ -0,0 +1,86 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Puts an event listener to an internal table for `@HostListener()`. + * + * @param type + * The event type. Can be prefixed with `document:` or `window:`. + * The event listener is attached to host element's owner document or its default view in such case. + * @param options The event listener options. + * @param Clazz The target class. + * @param name The method name in the given target class that works as the event listener. + */ +const setHostListener = ( + type: string, + options: boolean | AddEventListenerOptions, + Clazz, + name: string +) => { + const hostListeners = Clazz._hostListeners; + if (!hostListeners) { + throw new Error( + 'The method `@HostListener()` is defined on has to be of a class that has `HostListerMixin`.' + ); + } + if (!hostListeners[name]) { + hostListeners[name] = {}; + } + hostListeners[name][type] = { options }; +}; + +/** + * @param type + * The event type. Can be prefixed with `document:` or `window:`. + * The event listener is attached to host element's owner document or its default view in such case. + * @param options The event listener options. + * @param descriptor The original class element descriptor of the event listener method. + * @returns The updated class element descriptor with `@HostListener()` decorator. + */ +const HostListenerStandard = ( + type: string, + options: boolean | AddEventListenerOptions, + descriptor +) => { + const { kind, key, placement } = descriptor; + if ( + !( + (kind === 'method' && placement === 'prototype') || + (kind === 'field' && placement === 'own') + ) + ) { + throw new Error( + '`@HostListener()` must be defined on instance methods, but you may have defined it on static, field, etc.' + ); + } + return { + ...descriptor, + finisher(Clazz) { + setHostListener(type, options, Clazz, key); + }, + }; +}; + +/** + * A decorator to add event listener to the host element, or its `document`/`window`, of a custom element. + * The `target` must extend `HostListenerMixin`. + * + * @param type + * The event type. Can be prefixed with `document:` or `window:`. + * The event listener is attached to host element's owner document or its default view in such case. + * @param options The event listener options. + */ +const HostListener = + (type: string, options?: boolean | AddEventListenerOptions) => + (targetOrDescriptor, name: string) => + typeof name !== 'undefined' + ? setHostListener(type, options!, targetOrDescriptor.constructor, name) + : HostListenerStandard(type, options!, targetOrDescriptor); + +export default HostListener; diff --git a/packages/web-components/src/globals/directives/if-non-empty.ts b/packages/web-components/src/globals/directives/if-non-empty.ts new file mode 100644 index 000000000000..022de7f3626e --- /dev/null +++ b/packages/web-components/src/globals/directives/if-non-empty.ts @@ -0,0 +1,18 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ifDefined } from 'lit/directives/if-defined.js'; + +/** + * A variant of `if-non-null` which stops rendering if the given value is an emptry string in addition to `null`/`undefined`. + * + * @param value The value. + */ +export default (value) => + ifDefined(value === '' ? undefined : value ?? undefined); diff --git a/packages/web-components/src/globals/directives/spread.ts b/packages/web-components/src/globals/directives/spread.ts new file mode 100644 index 000000000000..bc75f5e185e3 --- /dev/null +++ b/packages/web-components/src/globals/directives/spread.ts @@ -0,0 +1,85 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { + AttributePart, + Directive, + DirectiveParameters, +} from 'lit/directive.js'; +import { directive } from 'lit/async-directive.js'; + +export interface AttributesInfo { + readonly [name: string]: string; +} + +/** + * Stores the ClassInfo object applied to a given AttributePart. + * Used to unset existing values when a new ClassInfo object is applied. + */ +const attributesMapCache = new WeakMap(); + +/** + * A directive that applies attributes from a key-value pairs. + * This must be used in the `...` name and must be the only part used in the attribute. + * It applies the key-value pairs in the `attributesInfo` argument + * and sets them as attribute name/value pairs. + * + */ +class SpreadDirective extends Directive { + /** + * The update function that handles the attribute setting. + * + * @param part an object with an API to manage the element's DOM + * @returns the render function + */ + update(part: AttributePart, [attributesInfo]: DirectiveParameters) { + const { element } = part; + + // Removes old attributes that are no longer there + const oldAttributesInfo = attributesMapCache.get(part); + if (oldAttributesInfo) { + Object.keys(oldAttributesInfo).forEach((name) => { + if (!(name in attributesInfo)) { + element.removeAttribute(name); + } + }); + } + + // Adds new attributes + Object.keys(attributesInfo).forEach((name) => { + const value = attributesInfo[name]; + if ( + (!oldAttributesInfo || !Object.is(value, oldAttributesInfo[name])) && + typeof value !== 'undefined' + ) { + element.setAttribute(name, value); + } + }); + + // Updates the cache + attributesMapCache.set(part, attributesInfo); + + return this.render(attributesInfo); + } + + /** + * The rendering function that simply takes in the arguments to be used + * in the update() function. + * + * @param attributesInfo The key-value pair to be set as the attribute name/value pairs. + * @returns the attributes info + */ + render(attributesInfo: AttributesInfo) { + return attributesInfo; + } +} + +const spread = directive(SpreadDirective); + +export default spread; diff --git a/packages/web-components/src/globals/internal/collection-helpers.ts b/packages/web-components/src/globals/internal/collection-helpers.ts new file mode 100644 index 000000000000..c19f17397b54 --- /dev/null +++ b/packages/web-components/src/globals/internal/collection-helpers.ts @@ -0,0 +1,67 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @param a A DOM collection. + * @param predicate The callback function. + * @param [thisObject] The context object for the given callback function. + * @returns A new array with all elements where `predicate` returns truthy. + */ +export const filter = ( + a: NodeListOf | HTMLCollectionOf, + predicate: (search: Node, index?: number) => boolean, + thisObject?: any +) => Array.prototype.filter.call(a, predicate, thisObject); + +/** + * @param a A DOM collection. + * @param predicate The callback function. + * @param [thisObject] The context object for the given callback function. + * @returns The index of the first item in the given collection where `predicate` returns `true`. `-1` if no such item is found. + */ +export const findIndex = ( + a: NodeListOf | HTMLCollectionOf, + predicate: (search: Node, index?: number) => boolean, + thisObject?: any +) => Array.prototype.findIndex.call(a, predicate, thisObject); + +/** + * @param a A DOM collection. + * @param predicate The callback function. + * @param [thisObject] The context object for the given callback function. + * @returns The first item in the given collection where `predicate` returns `true`. `null` if no such item is found. + */ +export const find = ( + a: NodeListOf | HTMLCollectionOf, + predicate: (search: Node, index?: number) => boolean, + thisObject?: any +) => Array.prototype.find.call(a, predicate, thisObject); + +/** + * Walks through the given DOM collection and runs the given callback. + * + * @param a A DOM collection. + * @param predicate The callback function. + * @param [thisObject] The context object for the given callback function. + */ +export const forEach = ( + a: NodeListOf | HTMLCollectionOf, + predicate: (search: Element, index?: number) => void, + thisObject?: any +) => Array.prototype.forEach.call(a, predicate, thisObject); + +/** + * @param a A DOM collection. + * @param item An item in the DOM collection. + * @returns The index of the first occurence of the given item in the given collection. `-1` if no such item is found. + */ +export const indexOf = ( + a: NodeListOf | HTMLCollectionOf, + item: Node +) => Array.prototype.indexOf.call(a, item); diff --git a/packages/web-components/src/globals/internal/feature-flags.ts b/packages/web-components/src/globals/internal/feature-flags.ts new file mode 100644 index 000000000000..cb2cf5099a1e --- /dev/null +++ b/packages/web-components/src/globals/internal/feature-flags.ts @@ -0,0 +1,30 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * This file contains the list of the default values of compile-time feature flags. + */ + +/** + * This flag will determine if all feature flags should be enabled + * + * @type {boolean} + */ +export const CDS_FLAGS_ALL: boolean = + process!.env.CDS_FLAGS_ALL === 'true' || false; + +/** + * Enables experimental component + * + * @type {boolean} + */ +export const CDS_EXPERIEMENTAL_COMPONENT_NAME: boolean = + process!.env.CDS_EXPERIEMENTAL_COMPONENT_NAME === 'true' || + CDS_FLAGS_ALL || + false; diff --git a/packages/web-components/src/globals/internal/handle.ts b/packages/web-components/src/globals/internal/handle.ts new file mode 100644 index 000000000000..90681bc7ef79 --- /dev/null +++ b/packages/web-components/src/globals/internal/handle.ts @@ -0,0 +1,19 @@ +/** + * @license + * + * Copyright IBM Corp. 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * An object to keep track of things that can be cleaned up. + */ +export default interface Handle { + /** + * Releases the thing that this object is keeping track of. + * For example, if this `Handle` is keeping track of an event listener, this `release()` method removes the event listener. + */ + release(): null; +} diff --git a/packages/web-components/src/globals/internal/radio-group-manager.ts b/packages/web-components/src/globals/internal/radio-group-manager.ts new file mode 100644 index 000000000000..4f30785cba11 --- /dev/null +++ b/packages/web-components/src/globals/internal/radio-group-manager.ts @@ -0,0 +1,211 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * The navigation direction. + */ +export enum NAVIGATION_DIRECTION { + /** + * Navigating backward. + */ + BACKWARD = -1, + + /** + * Navigating forward. + */ + FORWARD = 1, +} + +export interface ManagedRadioButtonDelegate { + /** + * `true` if this radio button is selected. + */ + checked: boolean; + + /** + * The tab index. + */ + tabIndex: number; + + /** + * The name of the radio group. + */ + name: string; + + /** + * @param other A node to compare this radio button's DOM position in document with. + * @returns + * An integer value, the same format as `Node.compareDocumentPosition` does, + * whose bits represent the calling this radio button's relationship to the given node within the document. + */ + compareDocumentPosition(other: ManagedRadioButtonDelegate): number; + + /** + * Focuses on the radio button. + */ + focus(): void; +} + +type ManagedRadioButton = HTMLInputElement | ManagedRadioButtonDelegate; + +/** + * An object that manages radio groups in a document. + * There must be only one instance for one document. + */ +class RadioGroupManager { + /** + * Radio groups, keyed by their names. + */ + private _groups: { [name: string]: Set } = {}; + + private constructor(document: Document) { + (this.constructor as typeof RadioGroupManager)._instances.set( + document, + this + ); + } + + /** + * @param radio A radio button. + * @returns + * `true` if the given radio button should be focusable, which is either: + * - The radio button is selected + * - No radio button is selected and the radio button is first one in the radio group + */ + shouldBeFocusable(radio: ManagedRadioButton) { + if (radio.checked) { + return true; + } + const { name } = radio; + const group = this._groups[name]; + const hasSelectedItemInGroup = + group && Array.from(group).some((item) => item.checked); + if (hasSelectedItemInGroup) { + return false; + } + const isFirstInGroup = + !group || group.size === 1 || this.getSortedGroup(radio)[0] === radio; + return isFirstInGroup; + } + + /** + * @param radio A radio button. + * @returns The sorted radio group the given radio button is in. + */ + getSortedGroup(radio: ManagedRadioButton) { + const group = this._groups[radio.name]; + return ( + group && + Array.from(group).sort((lhs, rhs) => { + const comparisonResult = ( + lhs as ManagedRadioButtonDelegate + ).compareDocumentPosition(rhs as ManagedRadioButtonDelegate); + // eslint-disable-next-line no-bitwise + if ( + comparisonResult & Node.DOCUMENT_POSITION_FOLLOWING || + comparisonResult & Node.DOCUMENT_POSITION_CONTAINED_BY + ) { + return -1; + } + // eslint-disable-next-line no-bitwise + if ( + comparisonResult & Node.DOCUMENT_POSITION_PRECEDING || + comparisonResult & Node.DOCUMENT_POSITION_CONTAINS + ) { + return 1; + } + return 0; + }) + ); + } + + /** + * Manages a radio button. + * + * @param radio The radio button to manage. + * @returns This object. + */ + add(radio: ManagedRadioButton) { + const { name } = radio; + if (name) { + const groups = this._groups; + if (!groups[name]) { + groups[name] = new Set(); + } + groups[name].add(radio); + } + return this; + } + + /** + * Unmanages a radio button. + * + * @param radio The radio button to unmanage. + * @param name The old name of the radio button to unmanage. + * @returns `true` if `element` was actually managed. + */ + delete(radio: ManagedRadioButton, name: string = radio.name) { + const group = this._groups[name]; + return !group ? false : group.delete(radio); + } + + /** + * Selects or focuses on a radio button. + * + * @param radio The radio button to select. + * @param readOnly optional if radio button has readOnly. + */ + select(radio: ManagedRadioButton, readOnly?: boolean) { + const group = this._groups[radio.name]; + if (group) { + // Updates the state of the one being selected up-front to avoid the state of no radio button is selected + radio.checked = !readOnly || true; + radio.tabIndex = 0; + radio.focus(); + group.forEach((item) => { + if (radio !== item) { + item.checked = readOnly || false; + item.tabIndex = -1; + } + }); + } + } + + /** + * @param radio The currently selected radio button. + * @param direction The direction to navigate to. + * @returns The radio button that should be selected next. + */ + navigate(radio: ManagedRadioButton, direction: NAVIGATION_DIRECTION) { + const sortedGroup = this.getSortedGroup(radio); + let newIndex = sortedGroup.indexOf(radio) + direction; + if (newIndex < 0) { + newIndex = sortedGroup.length - 1; + } else if (newIndex >= sortedGroup.length) { + newIndex = 0; + } + return sortedGroup[newIndex]; + } + + /** + * `RadioGroupManager` instances associated with documents. + */ + private static _instances = new WeakMap(); + + /** + * @param document A document element. + * @returns The `RadioGroupManager` instance associated with the given document. + */ + static get(document: Document) { + const found = this._instances.get(document); + return found || new RadioGroupManager(document); + } +} + +export default RadioGroupManager; diff --git a/packages/web-components/src/globals/internal/storybook-cdn.ts b/packages/web-components/src/globals/internal/storybook-cdn.ts new file mode 100644 index 000000000000..c331b6a8c515 --- /dev/null +++ b/packages/web-components/src/globals/internal/storybook-cdn.ts @@ -0,0 +1,69 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import packageJson from '../../../package.json'; + +/* eslint-disable max-len */ + +/** + * + */ +/** + * Renders the component(s) script tag content and returns back the string + * + * @param {Array} components array of component names + * @param {string} tag tag folder + */ +function _renderScript(components, tag) { + let scripts = ''; + components.forEach((component) => { + scripts += `\n`; + }); + return scripts; +} + +/** + * This is the markdown block for JS via CDN + * + * @param {Array} components array of components to render + * @param components.components components to render + */ +export const cdnJs = ({ components }) => { + return ` +### JS (via CDN) + + > NOTE: Only one version of artifacts should be used. Mixing versions will cause rendering issues. + + \`\`\`html + // SPECIFIC VERSION (available starting v2.0.0) + ${_renderScript(components, `version/v${packageJson.version}`)} + \`\`\` + + #### Right-to-left (RTL) versions + + \`\`\`html + // SPECIFIC VERSION (available starting v2.0.0) + ${_renderScript(components, `version/v${packageJson.version}`)} + \`\`\` + `; +}; + +/** + * This is the markdown block for CSS via CDN + */ +export const cdnCss = () => { + return ` +### Carbon CDN style helpers (optional) + +There are optional CDN artifacts available that can assist with global Carbon +styles in lieu of including into your specific application bundle. + +[Click here to learn more](https://github.com/carbon-design-system/carbon-for-ibm-dotcom/blob/main/packages/web-components/docs/carbon-cdn-style-helpers.md)\n\n + `; +}; diff --git a/packages/web-components/src/globals/mixins/focus.ts b/packages/web-components/src/globals/mixins/focus.ts new file mode 100644 index 000000000000..a051a499eea5 --- /dev/null +++ b/packages/web-components/src/globals/mixins/focus.ts @@ -0,0 +1,38 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { selectorTabbable } from '../settings'; + +/** + * @param Base The base class. + * @returns A mix-in implementing `.focus()` method that focuses on the first focusable element in the shadow DOM. + */ +const FocusMixin = >(Base: T) => + class extends Base { + /** + * Focuses on the first focusable element in the shadow DOM. + */ + focus() { + // @ts-ignore: Until `delegatesFocus` is added to `ShadowRoot` definition + if (this.shadowRoot!.delegatesFocus) { + super.focus(); + } else { + const delegateTarget = + this.shadowRoot!.querySelector(selectorTabbable) || + this.querySelector(selectorTabbable); + if (delegateTarget) { + (delegateTarget as HTMLElement).focus(); + } else { + super.focus(); + } + } + } + }; + +export default FocusMixin; diff --git a/packages/web-components/src/globals/mixins/form.ts b/packages/web-components/src/globals/mixins/form.ts new file mode 100644 index 000000000000..e4711d7be6a5 --- /dev/null +++ b/packages/web-components/src/globals/mixins/form.ts @@ -0,0 +1,56 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import on from './on'; +import Handle from '../internal/handle'; + +/** + * @param Base The base class. + * @returns A mix-in to handle `formdata` event on the containing form. + */ +const FormMixin = >(Base: T) => { + /** + * A mix-in class to handle `formdata` event on the containing form. + */ + abstract class FormMixinImpl extends Base { + /** + * The handle for `formdata` event listener on the containing form. + * + * @private + */ + _hFormdata: Handle | null = null; // Not using TypeScript `private` due to: microsoft/TypeScript#17744 + + /** + * Handles `formdata` event. + * + * @param event The event. + */ + abstract _handleFormdata(event: Event): void; + + connectedCallback() { + // @ts-ignore + super.connectedCallback(); + const form = this.closest('form'); + if (form) { + this._hFormdata = on(form, 'formdata', this._handleFormdata.bind(this)); + } + } + + disconnectedCallback() { + if (this._hFormdata) { + this._hFormdata = this._hFormdata.release(); + } + // @ts-ignore + super.disconnectedCallback(); + } + } + return FormMixinImpl; +}; + +export default FormMixin; diff --git a/packages/web-components/src/globals/mixins/host-listener.ts b/packages/web-components/src/globals/mixins/host-listener.ts new file mode 100644 index 000000000000..41a9b244b298 --- /dev/null +++ b/packages/web-components/src/globals/mixins/host-listener.ts @@ -0,0 +1,97 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import on from './on'; +import Handle from '../internal/handle'; + +/** + * The format for the event name used by `@HostListener` decorator. + */ +const EVENT_NAME_FORMAT = + /^((document|window|parentRoot|shadowRoot):)?([\w-]+)$/; + +/** + * @param Base The base class. + * @returns A mix-in that sets up and cleans up event listeners defined by `@HostListener` decorator. + */ +const HostListenerMixin = >(Base: T) => { + /** + * A mix-in class that sets up and cleans up event listeners defined by `@HostListener` decorator. + */ + class HostListenerMixinImpl extends Base { + /** + * The list of handles managed by this mix-in. + * + * @private + */ + _handles: Set = new Set(); // Not using TypeScript `private` due to: microsoft/TypeScript#17744 + + connectedCallback() { + // @ts-ignore: Until `connectedCallback` is added to `HTMLElement` definition + super.connectedCallback(); + const hostListeners = (this.constructor as typeof HostListenerMixinImpl) + ._hostListeners; + Object.keys(hostListeners).forEach((listenerName) => { + Object.keys(hostListeners[listenerName]).forEach((type) => { + // Parses `document:click`/`window:click` format + const tokens = EVENT_NAME_FORMAT.exec(type); + if (!tokens) { + throw new Error(`Could not parse the event name: ${listenerName}`); + } + const [, , targetName, unprefixedType] = tokens; + const target: EventTarget = + { + document: this.ownerDocument, + window: this.ownerDocument!.defaultView, + parentRoot: this.getRootNode(), + shadowRoot: this.shadowRoot, + }[targetName] || this; + + const { options } = hostListeners[listenerName][type]; + + this._handles.add( + on( + target, + ((this.constructor as typeof Base)[unprefixedType] ?? + unprefixedType) as keyof HTMLElementEventMap, + this[listenerName], + options + ) + ); + }); + }); + } + + disconnectedCallback() { + this._handles.forEach((handle) => { + handle.release(); + this._handles.delete(handle); + }); + // @ts-ignore: Until `disconnectedCallback` is added to `HTMLElement` definition + super.disconnectedCallback(); + } + + /** + * The map, keyed by method name, of event listeners that should be attached to host element or host document. + * + * @private + */ + static _hostListeners: { + [listenerName: string]: { + [type: string]: { + options?: boolean | AddEventListenerOptions; + }; + }; + } = {}; // Not using TypeScript `private` due to: microsoft/TypeScript#17744 + } + + return HostListenerMixinImpl; +}; + +export default HostListenerMixin; diff --git a/packages/web-components/src/globals/mixins/on.ts b/packages/web-components/src/globals/mixins/on.ts new file mode 100644 index 000000000000..caea03ee23e9 --- /dev/null +++ b/packages/web-components/src/globals/mixins/on.ts @@ -0,0 +1,16 @@ +/** + * Copyright IBM Corp. 2016, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +export default function on(element: any, ...args: any) { + element.addEventListener(...args); + return { + release() { + element.removeEventListener(...args); + return null; + }, + }; +} diff --git a/packages/web-components/src/globals/mixins/validity.ts b/packages/web-components/src/globals/mixins/validity.ts new file mode 100644 index 000000000000..d6db8deefc65 --- /dev/null +++ b/packages/web-components/src/globals/mixins/validity.ts @@ -0,0 +1,126 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Form validation status. + */ +export enum VALIDATION_STATUS { + /** + * One indicating no validation error. + */ + NO_ERROR = '', + + /** + * One indicating missing required value. + */ + ERROR_REQUIRED = 'required', +} + +/** + * @param Base The base class. + * @returns A mix-in implementing `.setCustomValidity()` method. + */ +const ValidityMixin = >(Base: T) => { + abstract class ValidityMixinImpl extends Base { + // Not using TypeScript `protected` due to: microsoft/TypeScript#17744 + // Using `string` instead of `VALIDATION_STATUS` until we can require TypeScript 3.8 + /** + * @param state The form validation status. + * @returns The form validation error messages associated with the given status. + * @protected + */ + _getValidityMessage(state: string) { + return { + [VALIDATION_STATUS.NO_ERROR]: '', + [VALIDATION_STATUS.ERROR_REQUIRED]: this.requiredValidityMessage, + }[state]; + } + + // Not using TypeScript `protected` due to: microsoft/TypeScript#17744 + // Using `string` instead of `VALIDATION_STATUS` until we can require TypeScript 3.8 + /** + * Checks if the value meets the constraints. + * + * @returns `VALIDATION_STATUS.NO_ERROR` if the value meets the constraints. Some other values otherwise. + * @protected + */ + _testValidity(): string { + const { required, value } = this; + return required && !value + ? VALIDATION_STATUS.ERROR_REQUIRED + : VALIDATION_STATUS.NO_ERROR; + } + + /** + * `true` to show the UI of the invalid state. + */ + abstract invalid: boolean; + + /** + * `true` if the value is required. + */ + abstract required: boolean; + + /** + * The special validity message for `required`. + */ + abstract requiredValidityMessage: string; + + /** + * The validity message. + */ + abstract validityMessage: string; + + /** + * The value. + */ + abstract value: string; + + /** + * Checks if the value meets the constraints. + * Fires cancelable `invalid` event if it doesn't. + * + * @returns `true` if the value meets the constraints. `false` otherwise. + */ + checkValidity() { + const status = this._testValidity(); + if (status !== VALIDATION_STATUS.NO_ERROR) { + if ( + this.dispatchEvent( + new CustomEvent('invalid', { + bubbles: false, + cancelable: true, + composed: false, + }) + ) + ) { + this.invalid = true; + this.validityMessage = this._getValidityMessage(status) as string; + } + return false; + } + this.invalid = false; + this.validityMessage = ''; + return true; + } + + /** + * Sets the given custom validity message. + * + * @param validityMessage The custom validity message + */ + setCustomValidity(validityMessage: string) { + this.invalid = Boolean(validityMessage); + this.validityMessage = validityMessage; + } + } + return ValidityMixinImpl; +}; + +export default ValidityMixin; diff --git a/packages/web-components/src/globals/settings.ts b/packages/web-components/src/globals/settings.ts new file mode 100644 index 000000000000..1cbf9d8cc525 --- /dev/null +++ b/packages/web-components/src/globals/settings.ts @@ -0,0 +1,75 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const prefix = 'cds'; + +/** + * A selector selecting tabbable nodes. + * Borrowed from `carbon-angular`. tabbable === focusable. + */ +const selectorTabbable = ` + a[href], area[href], input:not([disabled]):not([tabindex='-1']), + button:not([disabled]):not([tabindex='-1']),select:not([disabled]):not([tabindex='-1']), + textarea:not([disabled]):not([tabindex='-1']), + iframe, object, embed, *[tabindex]:not([tabindex='-1']), *[contenteditable=true], + ${prefix}-accordion-item, + ${prefix}-button, + ${prefix}-breadcrumb-link, + ${prefix}-checkbox, + ${prefix}-code-snippet, + ${prefix}-combo-box, + ${prefix}-content-switcher-item, + ${prefix}-copy-button, + ${prefix}-table-header-row, + ${prefix}-table-row, + ${prefix}-table-toolbar-search, + ${prefix}-date-picker-input, + ${prefix}-dropdown, + ${prefix}-input, + ${prefix}-link, + ${prefix}-number-input, + ${prefix}-modal, + ${prefix}-modal-close-button, + ${prefix}-multi-select, + ${prefix}-inline-notification, + ${prefix}-toast-notification, + ${prefix}-overflow-menu, + ${prefix}-overflow-menu-item, + ${prefix}-page-sizes-select, + ${prefix}-pages-select, + ${prefix}-progress-step, + ${prefix}-radio-button, + ${prefix}-search, + ${prefix}-slider, + ${prefix}-slider-input, + ${prefix}-structured-list, + ${prefix}-tab, + ${prefix}-filter-tag, + ${prefix}-textarea, + ${prefix}-text-input, + ${prefix}-clickable-tile, + ${prefix}-expandable-tile, + ${prefix}-radio-tile, + ${prefix}-selectable-tile, + ${prefix}-toggle, + ${prefix}-tooltip, + ${prefix}-tooltip-definition, + ${prefix}-tooltip-icon, + ${prefix}-header-menu, + ${prefix}-header-menu-button, + ${prefix}-header-menu-item, + ${prefix}-header-name, + ${prefix}-header-nav-item, + ${prefix}-side-nav-link, + ${prefix}-side-nav-menu, + ${prefix}-side-nav-menu-item +`; + +// Because we're going to have a bunch of exports +export { prefix, selectorTabbable }; diff --git a/packages/web-components/src/globals/shared-enums.ts b/packages/web-components/src/globals/shared-enums.ts new file mode 100644 index 000000000000..5267780a8143 --- /dev/null +++ b/packages/web-components/src/globals/shared-enums.ts @@ -0,0 +1,23 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Color scheme for form elements. + */ +export enum FORM_ELEMENT_COLOR_SCHEME { + /** + * Regular color scheme. + */ + REGULAR = '', + + /** + * Light color scheme. + */ + LIGHT = 'light', +} diff --git a/packages/web-components/src/index.ts b/packages/web-components/src/index.ts new file mode 100644 index 000000000000..7d8135fd4c64 --- /dev/null +++ b/packages/web-components/src/index.ts @@ -0,0 +1,141 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +export { default as CDSAccordion } from './components/accordion/accordion'; +export { default as CDSAccordionItem } from './components/accordion/accordion-item'; +export { default as CDSAccordionSkeleton } from './components/accordion/accordion-skeleton'; +export { default as CDSAISkeletonIcon } from './components/ai-skeleton/ai-skeleton-icon'; +export { default as CDSAISkeletonPlaceholder } from './components/ai-skeleton/ai-skeleton-placeholder'; +export { default as CDSAISkeletonText } from './components/ai-skeleton/ai-skeleton-text'; +export { default as CDSButton } from './components/button/button'; +export { default as CDSButtonSkeleton } from './components/button/button-skeleton'; +export { default as CDSBreadcrumb } from './components/breadcrumb/breadcrumb'; +export { default as CDSBreadcrumbItem } from './components/breadcrumb/breadcrumb-item'; +export { default as CDSBreadcrumbLink } from './components/breadcrumb/breadcrumb-link'; +export { default as CDSChatButton } from './components/chat-button/chat-button'; +export { default as CDSCheckbox } from './components/checkbox/checkbox'; +export { default as CDSCodeSnippet } from './components/code-snippet/code-snippet'; +export { default as CDSCodeSnippetSkeleton } from './components/code-snippet/code-snippet-skeleton'; +export { default as CDSComboBox } from './components/combo-box/combo-box'; +export { default as CDSComboBoxItem } from './components/combo-box/combo-box-item'; +export { default as CDSContentSwitcher } from './components/content-switcher/content-switcher'; +export { default as CDSContentSwitcherItem } from './components/content-switcher/content-switcher-item'; +export { default as CDSCopyButton } from './components/copy-button/copy-button'; +export { default as CDSFileUploader } from './components/file-uploader/file-uploader'; +export { default as CDSFileUploaderButton } from './components/file-uploader/file-uploader-button'; +export { default as CDSFileUploaderDropContainer } from './components/file-uploader/file-uploader-drop-container'; +export { default as CDSFileUploaderItem } from './components/file-uploader/file-uploader-item'; +export { default as CDSFileUploaderSkeleton } from './components/file-uploader/file-uploader-skeleton'; +export { default as CDSTable } from './components/data-table/table'; +export { default as CDSTableBatchActions } from './components/data-table/table-batch-actions'; +export { default as CDSTableBody } from './components/data-table/table-body'; +export { default as CDSTableCell } from './components/data-table/table-cell'; +export { default as CDSTableCellContent } from './components/data-table/table-cell-content'; +export { default as CDSTableHead } from './components/data-table/table-head'; +export { default as CDSTableHeaderTitle } from './components/data-table/table-header-title'; +export { default as CDSTableHeadDescription } from './components/data-table/table-header-description'; +export { default as CDSTableHeaderCell } from './components/data-table/table-header-cell'; +export { default as CDSTableHeaderRow } from './components/data-table/table-header-row'; +export { default as CDSTableRow } from './components/data-table/table-row'; +export { default as CDSTableSkeleton } from './components/data-table/table-skeleton'; +export { default as CDSTableToolbarContent } from './components/data-table/table-toolbar-content'; +export { default as CDSTableToolbarSearch } from './components/data-table/table-toolbar-search'; +export { default as CDSDatePicker } from './components/date-picker/date-picker'; +export { default as CDSDatePickerInput } from './components/date-picker/date-picker-input'; +export { default as CDSDatePickerInputSkeleton } from './components/date-picker/date-picker-input-skeleton'; +export { default as CDSDropdown } from './components/dropdown/dropdown'; +export { default as CDSDropdownItem } from './components/dropdown/dropdown-item'; +export { default as CDSDropdownSkeleton } from './components/dropdown/dropdown-skeleton'; +export { default as CDSFormItem } from './components/form/form-item'; +export { default as CDSFormGroup } from './components/form-group/form-group'; +export { default as CDSIconButton } from './components/icon-button/icon-button'; +export { default as CDSTextInput } from './components/text-input/text-input'; +export { default as CDSTextInputSkeleton } from './components/text-input/text-input-skeleton'; +export { default as CDSInlineLoading } from './components/inline-loading/inline-loading'; +export { default as CDSLink } from './components/link/link'; +export { default as CDSListItem } from './components/list/list-item'; +export { default as CDSOrderedList } from './components/list/ordered-list'; +export { default as CDSUnorderedList } from './components/list/unordered-list'; +export { default as CDSLoading } from './components/loading/loading'; +export { default as CDSModal } from './components/modal/modal'; +export { default as CDSModalBody } from './components/modal/modal-body'; +export { default as CDSModalBodyContent } from './components/modal/modal-body-content'; +export { default as CDSModalCloseButton } from './components/modal/modal-close-button'; +export { default as CDSModalFooter } from './components/modal/modal-footer'; +export { default as CDSModalHeader } from './components/modal/modal-header'; +export { default as CDSModalHeading } from './components/modal/modal-heading'; +export { default as CDSModalLabel } from './components/modal/modal-label'; +export { default as CDSMultiSelect } from './components/multi-select/multi-select'; +export { default as CDSMultiSelectItem } from './components/multi-select/multi-select-item'; +export { default as CDSActionableNotification } from './components/notification/actionable-notification'; +export { default as CDSActionableNotificationButton } from './components/notification/actionable-notification-button'; +export { default as CDSInlineNotification } from './components/notification/inline-notification'; +export { default as CDSToastNotification } from './components/notification/toast-notification'; +export { default as CDSNumberInput } from './components/number-input/number-input'; +export { default as CDSNumberInputSkeleton } from './components/number-input/number-input-skeleton'; +export { default as CDSTextarea } from './components/textarea/textarea'; +export { default as CDSTextareaSkeleton } from './components/textarea/textarea-skeleton'; +export { default as CDSOverflowMenu } from './components/overflow-menu/overflow-menu'; +export { default as CDSOverflowMenuBody } from './components/overflow-menu/overflow-menu-body'; +export { default as CDSOverflowMenuItem } from './components/overflow-menu/overflow-menu-item'; +export { default as CDSPagination } from './components/pagination/pagination'; +export { default as CDSProgressBar } from './components/progress-bar/progress-bar'; +export { default as CDSProgressIndicator } from './components/progress-indicator/progress-indicator'; +export { default as CDSProgressIndicatorSkeleton } from './components/progress-indicator/progress-indicator-skeleton'; +export { default as CDSProgressStepSkeleton } from './components/progress-indicator/progress-step-skeleton'; +export { default as CDSProgressStep } from './components/progress-indicator/progress-step'; +export { default as CDSRadioButton } from './components/radio-button/radio-button'; +export { default as CDSRadioButtonGroup } from './components/radio-button/radio-button-group'; +export { default as CDSSearch } from './components/search/search'; +export { default as CDSSearchSkeleton } from './components/search/search-skeleton'; +export { default as CDSSkeletonIcon } from './components/skeleton-icon/skeleton-icon'; +export { default as CDSSkeletonPlaceholder } from './components/skeleton-placeholder/skeleton-placeholder'; +export { default as CDSSkeletonText } from './components/skeleton-text/skeleton-text'; +export { default as CDSSlider } from './components/slider/slider'; +export { default as CDSSliderInput } from './components/slider/slider-input'; +export { default as CDSSliderSkeleton } from './components/slider/slider-skeleton'; +export { default as CDSStructuredList } from './components/structured-list/structured-list'; +export { default as CDSStructuredListBody } from './components/structured-list/structured-list-body'; +export { default as CDSStructuredListHead } from './components/structured-list/structured-list-head'; +export { default as CDSStructuredListHeaderRow } from './components/structured-list/structured-list-header-row'; +export { default as CDSStructuredListRow } from './components/structured-list/structured-list-row'; +export { default as CDSStructuredListHeaderCellSkeleton } from './components/structured-list/structured-list-header-cell-skeleton'; +export { default as CDSTabs } from './components/tabs/tabs'; +export { default as CDSTab } from './components/tabs/tab'; +export { default as CDSTabsSkeleton } from './components/tabs/tabs-skeleton'; +export { default as CDSTabSkeleton } from './components/tabs/tab-skeleton'; +export { default as CDSTag } from './components/tag/tag'; +export { default as CDSSkipToContent } from './components/skip-to-content/skip-to-content'; +export { default as CDSTile } from './components/tile/tile'; +export { default as CDSClickableTile } from './components/tile/clickable-tile'; +export { default as CDSExpandableTile } from './components/tile/expandable-tile'; +export { default as CDSRadioTile } from './components/tile/radio-tile'; +export { default as CDSSelectableTile } from './components/tile/selectable-tile'; +export { default as CDSTileGroup } from './components/tile/tile-group'; +export { default as CDSToggle } from './components/toggle/toggle'; +export { default as CDSTooltip } from './components/tooltip/tooltip'; +export { default as CDSTooltipDefinition } from './components/toggle-tip/toggletip'; +export { default as CDSHeader } from './components/ui-shell/header'; +export { default as CDSHeaderMenu } from './components/ui-shell/header-menu'; +export { default as CDSHeaderMenuButton } from './components/ui-shell/header-menu-button'; +export { default as CDSHeaderMenuItem } from './components/ui-shell/header-menu-item'; +export { default as CDSHeaderName } from './components/ui-shell/header-name'; +export { default as CDSHeaderNav } from './components/ui-shell/header-nav'; +export { default as CDSHeaderNavItem } from './components/ui-shell/header-nav-item'; +export { default as CDSHeaderSideNavItems } from './components/ui-shell/header-side-nav-items'; +export { default as CDSHeaderPanel } from './components/ui-shell/header-panel'; +export { default as CDSSideNav } from './components/ui-shell/side-nav'; +export { default as CDSSideNavItems } from './components/ui-shell/side-nav-items'; +export { default as CDSSideNavLink } from './components/ui-shell/side-nav-link'; +export { default as CDSSideNavMenu } from './components/ui-shell/side-nav-menu'; +export { default as CDSSideNavMenuItem } from './components/ui-shell/side-nav-menu-item'; +export { default as CDSSwitcher } from './components/ui-shell/switcher'; +export { default as CDSSwitcherItem } from './components/ui-shell/switcher-item'; +export { default as CDSSwitcherDivider } from './components/ui-shell/switcher-divider'; +export { default as CDSStack } from './components/stack/stack'; diff --git a/packages/web-components/src/polyfills/element-closest.ts b/packages/web-components/src/polyfills/element-closest.ts new file mode 100644 index 000000000000..13c0207ec863 --- /dev/null +++ b/packages/web-components/src/polyfills/element-closest.ts @@ -0,0 +1,29 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +if (typeof Element.prototype.closest !== 'function') { + Element.prototype.closest = function closestElement(selector: string) { + const doc = this.ownerDocument; + for ( + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-this-alias + let traverse: Node | null = this; + traverse && traverse !== doc; + traverse = traverse.parentNode + ) { + if ( + traverse.nodeType === Node.ELEMENT_NODE && + (traverse as Element).matches(selector) + ) { + return traverse as Element; + } + } + return null; + }; +} diff --git a/packages/web-components/src/polyfills/element-matches.ts b/packages/web-components/src/polyfills/element-matches.ts new file mode 100644 index 000000000000..194a6a5b81a2 --- /dev/null +++ b/packages/web-components/src/polyfills/element-matches.ts @@ -0,0 +1,18 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const matchesFuncName = [ + 'matches', + 'webkitMatchesSelector', + 'msMatchesSelector', +].filter((name) => typeof Element.prototype[name] === 'function')[0]; + +if (matchesFuncName !== 'matches') { + Element.prototype.matches = Element.prototype[matchesFuncName]; +} diff --git a/packages/web-components/src/polyfills/index.ts b/packages/web-components/src/polyfills/index.ts new file mode 100644 index 000000000000..d285d1ad9609 --- /dev/null +++ b/packages/web-components/src/polyfills/index.ts @@ -0,0 +1,34 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +// NOTE: `Array.from()` and `Object.assign()` and event constructor are covered by `@webcomponents/webcomponents-platform` +// NOTE: The need of iterator (`for` ... `of` loop) support is not revealed by Storybook, +// but by testing `carbon-web-components-with-polyfills.js` stand-alone +import 'core-js/modules/es.array.find.js'; +import 'core-js/modules/es.math.sign.js'; +import 'core-js/modules/es.symbol.js'; +import 'core-js/modules/es.symbol.iterator.js'; +import 'core-js/modules/es.array.includes.js'; +import 'core-js/modules/es.array.iterator.js'; +import 'core-js/modules/es.object.is.js'; // For src/globals/directives/spread.ts +import 'core-js/modules/es.object.values.js'; +import 'core-js/modules/es.object.entries'; + +import ResizeObserver from '@juggle/resize-observer'; + +import './element-closest'; +import './element-matches'; +import './toggle-attribute'; +import './toggle-class'; + +import '@webcomponents/webcomponentsjs'; + +if (typeof ResizeObserver === 'undefined') { + (window as any).ResizeObserver = ResizeObserver; +} diff --git a/packages/web-components/src/polyfills/toggle-attribute.ts b/packages/web-components/src/polyfills/toggle-attribute.ts new file mode 100644 index 000000000000..a042ff8df7ad --- /dev/null +++ b/packages/web-components/src/polyfills/toggle-attribute.ts @@ -0,0 +1,26 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +if (!Element.prototype.toggleAttribute) { + Element.prototype.toggleAttribute = function toggleAttribute( + name: string, + force?: boolean + ) { + const oldState = Boolean(this.hasAttribute(name)); + const newState = typeof force !== 'undefined' ? Boolean(force) : !oldState; + if (oldState !== newState) { + if (newState) { + this.setAttribute(name, ''); + } else { + this.removeAttribute(name); + } + } + return newState; + }; +} diff --git a/packages/web-components/src/polyfills/toggle-class.ts b/packages/web-components/src/polyfills/toggle-class.ts new file mode 100644 index 000000000000..b49ec9c1c5be --- /dev/null +++ b/packages/web-components/src/polyfills/toggle-class.ts @@ -0,0 +1,28 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const missingNativeDOMTokenListToggleForce = (() => { + const elem = document.createElement('div'); + const randomClass = `_random_class_${Math.random().toString(36).slice(2)}`; + elem.classList.toggle(randomClass, false); + return elem.classList.contains(randomClass); +})(); +if (missingNativeDOMTokenListToggleForce) { + (() => { + const origToggle = DOMTokenList.prototype.toggle; + DOMTokenList.prototype.toggle = function toggleDOMTokenList( + name: string, + add: boolean + ) { + return arguments.length < 2 || this.contains(name) === !add + ? origToggle.call(this, name) + : add; + }; + })(); +} diff --git a/packages/web-components/src/typings/constructor.d.ts b/packages/web-components/src/typings/constructor.d.ts new file mode 100644 index 000000000000..0dce6c41b0e3 --- /dev/null +++ b/packages/web-components/src/typings/constructor.d.ts @@ -0,0 +1,13 @@ +/** + * @license + * + * Copyright IBM Corp. 2019 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Constructor type. Used for defining mix-ins. + */ +type Constructor = new (...args: any[]) => T; diff --git a/packages/web-components/src/typings/jsx-elements.d.ts b/packages/web-components/src/typings/jsx-elements.d.ts new file mode 100644 index 000000000000..c0b4ae202e1e --- /dev/null +++ b/packages/web-components/src/typings/jsx-elements.d.ts @@ -0,0 +1,127 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '..'; + +declare global { + namespace JSX { + interface IntrinsicElements { + 'cds-accordion': any; + 'cds-accordion-item': any; + 'cds-accordion-skeleton': any; + 'cds-button': any; + 'cds-breadcrumb': any; + 'cds-breadcrumb-item': any; + 'cds-breadcrumb-link': any; + 'cds-breadcrumb-overflow-menu': any; + 'cds-breadcrumb-skeleton': any; + 'cds-checkbox': any; + 'cds-checkbox-skeleton': any; + 'cds-code-snippet': any; + 'cds-combo-box': any; + 'cds-combo-box-item': any; + 'cds-content-switcher': any; + 'cds-content-switcher-item': any; + 'cds-copy-button': any; + 'cds-data-table': any; + 'cds-table': any; + 'cds-file-uploader': any; + 'cds-file-uploader-button': any; + 'cds-file-uploader-drop-container': any; + 'cds-file-uploader-item': any; + 'cds-file-uploader-skeleton': any; + 'cds-table-head': any; + 'cds-table-header-row': any; + 'cds-table-header-cell': any; + 'cds-table-body': any; + 'cds-table-row': any; + 'cds-table-cell': any; + 'cds-date-picker': any; + 'cds-date-picker-input': any; + 'cds-dropdown': any; + 'cds-dropdown-item': any; + 'cds-form-group': any; + 'cds-form-item': any; + 'cds-icon-button': any; + 'cds-text-input': any; + 'cds-inline-loading': any; + 'cds-link': any; + 'cds-ordered-list': any; + 'cds-unordered-list': any; + 'cds-layer': any; + 'cds-loading': any; + 'cds-modal': any; + 'cds-modal-body': any; + 'cds-modal-close-button': any; + 'cds-modal-footer': any; + 'cds-modal-header': any; + 'cds-modal-heading': any; + 'cds-modal-label': any; + 'cds-multi-select': any; + 'cds-multi-select-item': any; + 'cds-actionable-notification': any; + 'cds-actionable-notification-button': any; + 'cds-inline-notification': any; + 'cds-toast-notification': any; + 'cds-number-input': any; + 'cds-textarea': any; + 'cds-overflow-menu': any; + 'cds-overflow-menu-body': any; + 'cds-overflow-menu-item': any; + 'cds-pagination': any; + 'cds-page-sizes-select': any; + 'cds-pages-select': any; + 'cds-progress-bar': any; + 'cds-progress-indicator': any; + 'cds-progress-step': any; + 'cds-popover': any; + 'cds-popover-content': any; + 'cds-radio-button': any; + 'cds-radio-button-group': any; + 'cds-search': any; + 'cds-skeleton-placeholder': any; + 'cds-skeleton-text': any; + 'cds-slider': any; + 'cds-slider-input': any; + 'cds-stack': any; + 'cds-structured-list': any; + 'cds-structured-list-head': any; + 'cds-structured-list-header-row': any; + 'cds-structured-list-header-cell': any; + 'cds-structured-list-body': any; + 'cds-structured-list-row': any; + 'cds-structured-list-cell': any; + 'cds-tabs': any; + 'cds-tab': any; + 'cds-tag': any; + 'cds-tile': any; + 'cds-clickable-tile': any; + 'cds-selectable-tile': any; + 'cds-tooltip': any; + 'cds-tooltip-content': any; + 'cds-header': any; + 'cds-header-nav': any; + 'cds-header-nav-item': any; + 'cds-header-menu': any; + 'cds-header-menu-item': any; + 'cds-header-menu-button': any; + 'cds-header-name': any; + 'cds-header-panel': any; + 'cds-header-side-nav-items': any; + 'cds-switcher': any; + 'cds-switcher-divider': any; + 'cds-switcher-item': any; + 'cds-side-nav': any; + 'cds-side-nav-items': any; + 'cds-side-nav-menu': any; + 'cds-side-nav-menu-item': any; + 'cds-side-nav-link': any; + } + } +} diff --git a/packages/web-components/src/typings/resources.d.ts b/packages/web-components/src/typings/resources.d.ts new file mode 100644 index 000000000000..9d777be043da --- /dev/null +++ b/packages/web-components/src/typings/resources.d.ts @@ -0,0 +1,25 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +declare module '*.scss'; +declare module '*.scss?lit'; + +declare module '*.mdx' { + let MDXComponent: (props: any) => JSX.Element; + // @ts-ignore + export default { + parameters: { + docs: { + // @ts-ignore + container: JSX.Element, + page: MDXComponent, + }, + }, + }; +} diff --git a/packages/web-components/src/typings/vendor.d.ts b/packages/web-components/src/typings/vendor.d.ts new file mode 100644 index 000000000000..e82abc087aee --- /dev/null +++ b/packages/web-components/src/typings/vendor.d.ts @@ -0,0 +1,45 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +declare module 'carbon-components/es/globals/js/settings.js' { + const settings: { + /** + * The brand prefix. + */ + prefix: string; + }; + export default settings; +} + +declare module 'carbon-components/es/globals/js/misc/on.js' { + /** + * Adds an event listener function to the list of event listeners for the given event type on the given event target. + * + * @param target The target to add event listener on. + * @param type A case-sensitive string representing the event type to listen for. + * @param listener The event listener callback. + * @param options An options object that specifies characteristics about the event listener. + * @returns The handle to release the event listener. Its `release()` method removes the event listener. + */ + function on( + target: EventTarget, + type: K, + listener: (this: EventTarget, ev: HTMLElementEventMap[K]) => any, + options?: boolean | AddEventListenerOptions + ): // @ts-ignore + Handle; + function on( + target: EventTarget, + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions + ): // @ts-ignore + Handle; + export default on; +} diff --git a/packages/web-components/tasks/build-dist.js b/packages/web-components/tasks/build-dist.js new file mode 100644 index 000000000000..34b55f7eb95e --- /dev/null +++ b/packages/web-components/tasks/build-dist.js @@ -0,0 +1,164 @@ +/** + * @license + * + * Copyright IBM Corp. 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +import path from 'path'; +import { fileURLToPath } from 'url'; +import { rollup } from 'rollup'; +import autoprefixer from 'autoprefixer'; +import alias from '@rollup/plugin-alias'; +import commonjs from '@rollup/plugin-commonjs'; +import cssnano from 'cssnano'; +import fs from 'fs'; +import multiInput from 'rollup-plugin-multi-input'; +import postcss from 'postcss'; +import replace from '@rollup/plugin-replace'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import { promisify } from 'util'; +import terser from '@rollup/plugin-terser'; +import typescript from '@rollup/plugin-typescript'; +import carbonIcons from '../tools/rollup-plugin-dist-icons.js'; +import fixHostPseudo from '../tools/postcss-fix-host-pseudo.js'; +import license from '../tools/rollup-plugin-license.js'; +import litSCSS from '../tools/rollup-plugin-lit-scss.js'; + +const readFile = promisify(fs.readFile); +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +/** + * Gets all of the folders and returns out + * + * @param {string} dir Directory to check + * @returns {string[]} List of folders + * @private + */ +function _getFolders(dir) { + return fs + .readdirSync(dir) + .filter((file) => fs.statSync(path.join(dir, file)).isDirectory()); +} + +/** + * Builds all of the rollup bundles for all components + * + * @param {object} [options] The build options. + * @param {string} [options.mode=development] The build mode. + */ +async function buildDist() { + if (!fs.existsSync('dist')) { + fs.mkdirSync('dist'); + } + + const folders = _getFolders('src/components'); + + for (let i = folders.length - 1; i >= 0; i--) { + if (!fs.existsSync(`src/components/${folders[i]}/index.ts`)) { + folders.splice(i, 1); + } + } + + return rollup(getRollupConfig({ folders })) + .then((bundle) => { + bundle.write({ + format: 'es', + dir: 'dist', + banner: 'let process = { env: {} };', + }); + }) + .catch((err) => { + // eslint-disable-next-line no-console + console.error(err); + }); +} + +/** + * Generates the multi-input for the rollup config + * + * @param {Array} folders Package names as inputs + * @returns {{}} Object with inputs + * @private + */ +function _generateInputs(folders) { + const inputs = {}; + + folders.forEach((folder) => { + inputs[`${folder}.min`] = `src/components/${folder}/index.ts`; + }); + + return inputs; +} + +/** + * Sets the rollup configuration based on various settings + * + * @param {object} [options] The build options. + * @param {Array} [options.folders] Package names as inputs + * @returns {object} The Rollup config. + */ +function getRollupConfig({ folders = [] } = {}) { + const postCSSPlugins = [fixHostPseudo(), autoprefixer(), cssnano()]; + + const licenseOptions = { + whitelist: /^(carbon-components|@carbon*)$/i, + async licenseSelf() { + return readFile(path.resolve(__dirname, '../tools/license.js'), 'utf8'); + }, + }; + + return { + input: _generateInputs(folders), + plugins: [ + alias({ + entries: [{ find: /^(.*)\.scss\?lit$/, replacement: '$1.scss' }], + }), + multiInput(), + nodeResolve({ + browser: true, + mainFields: ['jsnext', 'module', 'main'], + dedupe: ['carbon-components'], + extensions: ['.js', '.ts'], + }), + commonjs({ + include: [/node_modules/], + sourceMap: true, + }), + carbonIcons(), + typescript({ + noEmitOnError: true, + declaration: false, + compilerOptions: { + rootDir: 'src', + outDir: 'dist', + }, + }), + litSCSS({ + includePaths: [ + path.resolve(__dirname, '../node_modules'), + path.resolve(__dirname, '../../../node_modules'), + ], + async preprocessor(contents, id) { + return (await postcss(postCSSPlugins).process(contents, { from: id })) + .css; + }, + }), + replace({ + 'process.env.NODE_ENV': 'production', + preventAssignment: true, + }), + terser(), + license(licenseOptions), + ], + }; +} + +buildDist().catch((error) => { + console.log(error); + process.exit(1); +}); diff --git a/packages/web-components/tasks/build.js b/packages/web-components/tasks/build.js new file mode 100644 index 000000000000..f04c3a97edbe --- /dev/null +++ b/packages/web-components/tasks/build.js @@ -0,0 +1,166 @@ +/** + * Copyright IBM Corp. 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +import { fileURLToPath } from 'url'; +import { globby } from 'globby'; +import { rollup } from 'rollup'; +import alias from '@rollup/plugin-alias'; +import autoprefixer from 'autoprefixer'; +import carbonIcons from '../tools/rollup-plugin-icons.js'; +import carbonIconPaths from '../tools/rollup-plugin-icon-paths.js'; +import commonjs from '@rollup/plugin-commonjs'; +import copy from 'rollup-plugin-copy'; +import cssnano from 'cssnano'; +import litSCSS from '../tools/rollup-plugin-lit-scss.js'; +import nodeResolve from '@rollup/plugin-node-resolve'; +import path from 'path'; +import postcss from 'postcss'; +import typescript from '@rollup/plugin-typescript'; + +import * as packageJson from '../package.json' assert { type: 'json' }; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +async function build() { + const esInputs = await globby([ + 'src/**/*.ts', + '!src/**/*.stories.ts', + '!src/**/*.d.ts', + '!src/globals/internal/storybook-cdn.ts', + '!src/polyfills', + ]); + + const libInputs = await globby([ + 'src/components/**/defs.ts', + 'src/globals/**/*.ts', + '!src/globals/decorators/**/*.ts', + '!src/globals/directives/**/*.ts', + '!src/globals/internal/**/*.ts', + '!src/globals/mixins/**/*.ts', + ]); + + const iconInput = await globby([ + 'node_modules/@carbon/icons/lib/**/*.js', + '!**/index.js', + ]); + + const entryPoint = { + rootDir: 'src', + outputDirectory: path.resolve(__dirname, '..'), + }; + + const formats = [ + { + type: 'esm', + directory: 'es', + }, + { + type: 'commonjs', + directory: 'lib', + }, + ]; + + for (const format of formats) { + const outputDirectory = path.join( + entryPoint.outputDirectory, + format.directory + ); + + const cwcInputConfig = getRollupConfig( + format.type === 'esm' ? esInputs : libInputs, + entryPoint.rootDir, + outputDirectory, + format.type === 'esm' ? iconInput : [] + ); + + const cwcBundle = await rollup(cwcInputConfig); + + await cwcBundle.write({ + dir: outputDirectory, + format: format.type, + preserveModules: true, + preserveModulesRoot: 'src', + banner, + exports: 'named', + sourcemap: true, + }); + } +} + +const banner = `/** + * Copyright IBM Corp. 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ +`; + +function getRollupConfig(input, rootDir, outDir, iconInput) { + return { + input, + // Mark dependencies listed in `package.json` as external so that they are + // not included in the output bundle. + external: [ + ...Object.keys(packageJson.default.dependencies), + ...Object.keys(packageJson.default.devDependencies), + ].map((name) => { + // Transform the name of each dependency into a regex so that imports from + // nested paths are correctly marked as external. + // + // Example: + // import 'module-name'; + // import 'module-name/path/to/nested/module'; + return new RegExp(`^${name}(/.*)?`); + }), + plugins: [ + alias({ + entries: [{ find: /^(.*)\.scss\?lit$/, replacement: '$1.scss' }], + }), + copy({ + targets: [{ src: 'src/components/**/*.scss', dest: 'scss' }], + flatten: false, + }), + nodeResolve({ + browser: true, + mainFields: ['jsnext', 'module', 'main'], + extensions: ['.js', '.ts'], + }), + commonjs({ + include: [/node_modules/], + }), + litSCSS({ + includePaths: [ + path.resolve(__dirname, '../node_modules'), + path.resolve(__dirname, '../../../node_modules'), + ], + async preprocessor(contents, id) { + return ( + await postcss([autoprefixer(), cssnano()]).process(contents, { + from: id, + }) + ).css; + }, + }), + carbonIcons(iconInput, banner), + typescript({ + noEmitOnError: true, + compilerOptions: { + rootDir, + outDir, + }, + }), + carbonIconPaths(), + ], + }; +} + +build().catch((error) => { + console.log(error); + process.exit(1); +}); diff --git a/packages/web-components/telemetry.yml b/packages/web-components/telemetry.yml new file mode 100644 index 000000000000..eb0688c9b6d3 --- /dev/null +++ b/packages/web-components/telemetry.yml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://unpkg.com/@ibm/telemetry-config-schema@v1/dist/config.schema.json +version: 1 +projectId: "8cf8b3b8-a121-47d3-9eec-e4bea0ff23f5" +endpoint: "https://collector-prod.1am6wm210aow.us-south.codeengine.appdomain.cloud/v1/metrics" +collect: + npm: + dependencies: null + jsx: + elements: {} \ No newline at end of file diff --git a/packages/web-components/tests/integration/build/angular_steps.js b/packages/web-components/tests/integration/build/angular_steps.js new file mode 100644 index 000000000000..4a625a24d0c9 --- /dev/null +++ b/packages/web-components/tests/integration/build/angular_steps.js @@ -0,0 +1,48 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const fs = require('fs-extra'); +const { setup: setupDevServer, teardown: teardownDevServer } = require('jest-dev-server'); +const exec = require('../exec'); +const replaceDependencies = require('../replace-dependencies'); + +const PORT = 8080; + +describe('Angular example', () => { + beforeAll(async () => { + const projectRoot = path.resolve(__dirname, '../../..'); + const src = path.resolve(projectRoot, 'examples/codesandbox/angular'); + const tmpDir = process.env.CCE_EXAMPLE_TMPDIR; + await fs.copy(src, `${tmpDir}/angular`); + await replaceDependencies([`${tmpDir}/angular/package.json`]); + await exec('yarn', ['install'], { cwd: `${tmpDir}/angular` }); + await setupDevServer({ + command: `cd ${tmpDir}/angular && yarn ng serve --port ${PORT}`, + launchTimeout: Number(process.env.LAUNCH_TIMEOUT), + port: PORT, + }); + await page.goto(`http://localhost:${PORT}`); + }, Number(process.env.LAUNCH_TIMEOUT)); + + it('should show a title', async () => { + await expect(page).toMatch('Hello World!'); + }); + + it('should have dropdown interactive', async () => { + await expect(page).toClick('cds-dropdown'); + await expect(page).toMatchElement('cds-dropdown[open]'); + await expect(page).toClick('cds-dropdown'); + await expect(page).toMatchElement('cds-dropdown:not([open])'); + }); + + afterAll(async () => { + await teardownDevServer(); + }); +}); diff --git a/packages/web-components/tests/integration/build/basic_steps.js b/packages/web-components/tests/integration/build/basic_steps.js new file mode 100644 index 000000000000..2235454e6b84 --- /dev/null +++ b/packages/web-components/tests/integration/build/basic_steps.js @@ -0,0 +1,48 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const fs = require('fs-extra'); +const { setup: setupDevServer, teardown: teardownDevServer } = require('jest-dev-server'); +const exec = require('../exec'); +const replaceDependencies = require('../replace-dependencies'); + +const PORT = 1234; + +describe('Basic example', () => { + beforeAll(async () => { + const projectRoot = path.resolve(__dirname, '../../..'); + const src = path.resolve(projectRoot, 'examples/codesandbox/basic'); + const tmpDir = process.env.CCE_EXAMPLE_TMPDIR; + await fs.copy(src, `${tmpDir}/basic`); + await replaceDependencies([`${tmpDir}/basic/package.json`]); + await exec('yarn', ['install'], { cwd: `${tmpDir}/basic` }); + await setupDevServer({ + command: `cd ${tmpDir}/basic && node ${path.resolve(__dirname, 'webpack-server.js')} --port=${PORT}`, + launchTimeout: Number(process.env.LAUNCH_TIMEOUT), + port: PORT, + }); + await page.goto(`http://localhost:${PORT}`); + }, Number(process.env.LAUNCH_TIMEOUT)); + + it('should show a title', async () => { + await expect(page).toMatch('Hello World!'); + }); + + it('should have dropdown interactive', async () => { + await expect(page).toClick('cds-dropdown'); + await expect(page).toMatchElement('cds-dropdown[open]'); + await expect(page).toClick('cds-dropdown'); + await expect(page).toMatchElement('cds-dropdown:not([open])'); + }); + + afterAll(async () => { + await teardownDevServer(); + }); +}); diff --git a/packages/web-components/tests/integration/build/custom-style_steps.js b/packages/web-components/tests/integration/build/custom-style_steps.js new file mode 100644 index 000000000000..67b2aa4a949c --- /dev/null +++ b/packages/web-components/tests/integration/build/custom-style_steps.js @@ -0,0 +1,49 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const fs = require('fs-extra'); +const { setup: setupDevServer, teardown: teardownDevServer } = require('jest-dev-server'); +const exec = require('../exec'); +const replaceDependencies = require('../replace-dependencies'); + +const PORT = 1236; + +describe('Custom style example with inherited component class', () => { + beforeAll(async () => { + const projectRoot = path.resolve(__dirname, '../../..'); + const src = path.resolve(projectRoot, 'examples/codesandbox/styling/custom-style'); + const tmpDir = process.env.CCE_EXAMPLE_TMPDIR; + await fs.copy(src, `${tmpDir}/custom-style`); + await replaceDependencies([`${tmpDir}/custom-style/package.json`]); + await exec('yarn', ['install'], { cwd: `${tmpDir}/custom-style` }); + await setupDevServer({ + command: `cd ${tmpDir}/custom-style && node ${path.resolve(__dirname, 'webpack-server.js')} --port=${PORT}`, + launchTimeout: Number(process.env.LAUNCH_TIMEOUT), + port: PORT, + }); + await page.goto(`http://localhost:${PORT}`); + }, Number(process.env.LAUNCH_TIMEOUT)); + + it('should show a title', async () => { + await expect(page).toMatch('Hello World!'); + }); + + it('should have dropdown with custom color', async () => { + const backgroundColorValue = await page.evaluate((dropdown) => { + const listBox = dropdown.shadowRoot.querySelector('.cds--list-box'); + return listBox.ownerDocument.defaultView.getComputedStyle(listBox).getPropertyValue('background-color'); + }, await expect(page).toMatchElement('my-dropdown')); + expect(backgroundColorValue).toEqual(expect.stringMatching(/rgb\(\s*255,\s*255,\s*255\s*\)/)); + }); + + afterAll(async () => { + await teardownDevServer(); + }); +}); diff --git a/packages/web-components/tests/integration/build/form-basic_steps.js b/packages/web-components/tests/integration/build/form-basic_steps.js new file mode 100644 index 000000000000..3a1d0606b0f4 --- /dev/null +++ b/packages/web-components/tests/integration/build/form-basic_steps.js @@ -0,0 +1,58 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const fs = require('fs-extra'); +const { setup: setupDevServer, teardown: teardownDevServer } = require('jest-dev-server'); +const exec = require('../exec'); +const replaceDependencies = require('../replace-dependencies'); + +const PORT = 1235; + +describe('Basic form example', () => { + beforeAll(async () => { + const projectRoot = path.resolve(__dirname, '../../..'); + const src = path.resolve(projectRoot, 'examples/codesandbox/form/basic'); + const tmpDir = process.env.CCE_EXAMPLE_TMPDIR; + await fs.copy(src, `${tmpDir}/form-basic`); + await replaceDependencies([`${tmpDir}/form-basic/package.json`]); + await exec('yarn', ['install'], { cwd: `${tmpDir}/form-basic` }); + await setupDevServer({ + command: `cd ${tmpDir}/form-basic && node ${path.resolve(__dirname, 'webpack-server.js')} --port=${PORT}`, + launchTimeout: Number(process.env.LAUNCH_TIMEOUT), + port: PORT, + }); + page.on('dialog', async (dialog) => { + const message = dialog.message(); + await dialog.dismiss(); + await page.evaluate((content) => { + document.body.insertAdjacentHTML('beforeend', `
      ${content}
      `); + }, message); + }); + await page.goto(`http://localhost:${PORT}`); + }, Number(process.env.LAUNCH_TIMEOUT)); + + it('should detect an invalid data', async () => { + await expect(page).toFill('cds-text-input[name="username"]', 'john'); + await expect(page).toFill('cds-text-input[name="password"]', 'foo'); + await expect(page).toClick('cds-button[kind="primary"]'); + await expect(page).toMatchElement('cds-text-input[name="password"][invalid]', { timeout: 2000 }); + }); + + it('should submit the data once all data is valid', async () => { + await expect(page).toFill('cds-text-input[name="username"]', 'john'); + await expect(page).toFill('cds-text-input[name="password"]', 'form'); + await expect(page).toClick('cds-button[kind="primary"]'); + await expect(page).toMatch('You submitted:', { timeout: 2000 }); + }); + + afterAll(async () => { + await teardownDevServer(); + }); +}); diff --git a/packages/web-components/tests/integration/build/jest-puppeteer.config.js b/packages/web-components/tests/integration/build/jest-puppeteer.config.js new file mode 100644 index 000000000000..616b0d3b8e93 --- /dev/null +++ b/packages/web-components/tests/integration/build/jest-puppeteer.config.js @@ -0,0 +1,14 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +module.exports = { + launch: { + headless: process.env.CI !== 'false', + }, +}; diff --git a/packages/web-components/tests/integration/build/jest.config.js b/packages/web-components/tests/integration/build/jest.config.js new file mode 100644 index 000000000000..c9d12545cb06 --- /dev/null +++ b/packages/web-components/tests/integration/build/jest.config.js @@ -0,0 +1,18 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +process.env.JEST_PUPPETEER_CONFIG = `${__dirname}/jest-puppeteer.config.js`; + +module.exports = { + globalSetup: './setup', + globalTeardown: 'jest-environment-puppeteer/teardown', + setupFilesAfterEnv: ['expect-puppeteer'], + testEnvironment: 'jest-environment-puppeteer', + testRegex: '.*_steps\\.js$', +}; diff --git a/packages/web-components/tests/integration/build/next_steps.js b/packages/web-components/tests/integration/build/next_steps.js new file mode 100644 index 000000000000..30ce081b80fa --- /dev/null +++ b/packages/web-components/tests/integration/build/next_steps.js @@ -0,0 +1,48 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const fs = require('fs-extra'); +const { setup: setupDevServer, teardown: teardownDevServer } = require('jest-dev-server'); +const exec = require('../exec'); +const replaceDependencies = require('../replace-dependencies'); + +const PORT = 3002; + +describe('Next example', () => { + beforeAll(async () => { + const projectRoot = path.resolve(__dirname, '../../..'); + const src = path.resolve(projectRoot, 'examples/codesandbox/next'); + const tmpDir = process.env.CCE_EXAMPLE_TMPDIR; + await fs.copy(src, `${tmpDir}/next`); + await replaceDependencies([`${tmpDir}/next/package.json`]); + await exec('yarn', ['install'], { cwd: `${tmpDir}/next` }); + await setupDevServer({ + command: `cd ${tmpDir}/next && cross-env NODE_OPTIONS="--max-old-space-size=8192" yarn start -p ${PORT}`, + launchTimeout: Number(process.env.LAUNCH_TIMEOUT), + port: PORT, + }); + await page.goto(`http://localhost:${PORT}`); + }, Number(process.env.LAUNCH_TIMEOUT)); + + it('should show a title', async () => { + await expect(page).toMatch('Hello World!'); + }); + + it('should have dropdown interactive', async () => { + await expect(page).toClick('cds-dropdown'); + await expect(page).toMatchElement('cds-dropdown[open]'); + await expect(page).toClick('cds-dropdown'); + await expect(page).toMatchElement('cds-dropdown:not([open])'); + }); + + afterAll(async () => { + await teardownDevServer(); + }); +}); diff --git a/packages/web-components/tests/integration/build/redux-form_steps.js b/packages/web-components/tests/integration/build/redux-form_steps.js new file mode 100644 index 000000000000..6bca6e53ea5d --- /dev/null +++ b/packages/web-components/tests/integration/build/redux-form_steps.js @@ -0,0 +1,58 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const fs = require('fs-extra'); +const { setup: setupDevServer, teardown: teardownDevServer } = require('jest-dev-server'); +const exec = require('../exec'); +const replaceDependencies = require('../replace-dependencies'); + +const PORT = 3001; + +describe('Redux-form example', () => { + beforeAll(async () => { + const projectRoot = path.resolve(__dirname, '../../..'); + const src = path.resolve(projectRoot, 'examples/codesandbox/form/redux-form'); + const tmpDir = process.env.CCE_EXAMPLE_TMPDIR; + await fs.copy(src, `${tmpDir}/redux-form`); + await replaceDependencies([`${tmpDir}/redux-form/package.json`]); + await exec('yarn', ['install'], { cwd: `${tmpDir}/redux-form` }); + await setupDevServer({ + command: `cd ${tmpDir}/redux-form && node ${path.resolve(__dirname, 'webpack-server.js')} --port=${PORT}`, + launchTimeout: Number(process.env.LAUNCH_TIMEOUT), + port: PORT, + }); + page.on('dialog', async (dialog) => { + const message = dialog.message(); + await dialog.dismiss(); + await page.evaluate((content) => { + document.body.insertAdjacentHTML('beforeend', `
      ${content}
      `); + }, message); + }); + await page.goto(`http://localhost:${PORT}`); + }, Number(process.env.LAUNCH_TIMEOUT)); + + it('should detect an invalid data', async () => { + await expect(page).toFill('cds-text-input[name="username"]', 'john'); + await expect(page).toFill('cds-text-input[name="password"]', 'foo'); + await expect(page).toClick('cds-button[kind="primary"]'); + await expect(page).toMatchElement('cds-text-input[name="password"][invalid]', { timeout: 2000 }); + }); + + it('should submit the data once all data is valid', async () => { + await expect(page).toFill('cds-text-input[name="username"]', 'john'); + await expect(page).toFill('cds-text-input[name="password"]', 'redux-form'); + await expect(page).toClick('cds-button[kind="primary"]'); + await expect(page).toMatch('You submitted:', { timeout: 2000 }); + }); + + afterAll(async () => { + await teardownDevServer(); + }); +}); diff --git a/packages/web-components/tests/integration/build/rtl_steps.js b/packages/web-components/tests/integration/build/rtl_steps.js new file mode 100644 index 000000000000..2d717fc0a084 --- /dev/null +++ b/packages/web-components/tests/integration/build/rtl_steps.js @@ -0,0 +1,52 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const fs = require('fs-extra'); +const { setup: setupDevServer, teardown: teardownDevServer } = require('jest-dev-server'); +const exec = require('../exec'); +const replaceDependencies = require('../replace-dependencies'); + +const PORT = 8083; + +describe('RTL example', () => { + beforeAll(async () => { + const projectRoot = path.resolve(__dirname, '../../..'); + const src = path.resolve(projectRoot, 'examples/codesandbox/rtl'); + const tmpDir = process.env.CCE_EXAMPLE_TMPDIR; + await fs.copy(src, `${tmpDir}/rtl`); + await replaceDependencies([`${tmpDir}/rtl/package.json`]); + await exec('yarn', ['install'], { cwd: `${tmpDir}/rtl` }); + await setupDevServer({ + command: `cd ${tmpDir}/rtl && yarn webpack-dev-server --mode=development --open=false --port=${PORT}`, + launchTimeout: Number(process.env.LAUNCH_TIMEOUT), + port: PORT, + }); + await page.setExtraHTTPHeaders({ + 'Accept-Language': 'ar', + }); + await page.goto(`http://localhost:${PORT}`); + }, Number(process.env.LAUNCH_TIMEOUT)); + + it('should show a title', async () => { + await expect(page).toMatch('Hello World!'); + }); + + it('should have RTL style applied', async () => { + const transformValue = await page.evaluate((slider) => { + const filledTrackContainer = slider.shadowRoot.querySelector('.cds-ce--slider__filled-track-container'); + return filledTrackContainer.ownerDocument.defaultView.getComputedStyle(filledTrackContainer).getPropertyValue('transform'); + }, await expect(page).toMatchElement('cds-slider')); + expect(transformValue).toEqual(expect.stringMatching(/matrix\( *-1/)); + }); + + afterAll(async () => { + await teardownDevServer(); + }); +}); diff --git a/packages/web-components/tests/integration/build/setup.js b/packages/web-components/tests/integration/build/setup.js new file mode 100644 index 000000000000..70d67446d566 --- /dev/null +++ b/packages/web-components/tests/integration/build/setup.js @@ -0,0 +1,51 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const { promisify } = require('util'); +const { exec } = require('child-process-promise'); +const { setup } = require('jest-environment-puppeteer'); +const { mkdir, track } = require('temp'); + +const packs = { + 'carbon-web-components': path.resolve(__dirname, '../../..'), +}; + +/** + * Puts the build artifacts in the given temporary directory + * and resolves dependencies in `package.json` to use such build artifacts. + * + * @param {string} tmpDir The temporary directory. + */ +async function setupPackages(tmpDir) { + const commands = Object.keys(packs).reduce((acc, pack) => { + acc.push(`cd ${packs[pack]} && yarn pack --filename ${tmpDir}/${pack}.tar.gz`); + return acc; + }, []); + // eslint-disable-next-line no-restricted-syntax + for (const command of commands) { + // eslint-disable-next-line no-await-in-loop + const { stdout, stderr } = await exec(command); + console.log(stdout); // eslint-disable-line no-console + console.error(stderr); // eslint-disable-line no-console + } +} + +module.exports = async (config) => { + if (!process.env.LAUNCH_TIMEOUT) { + process.env.LAUNCH_TIMEOUT = 120000; + } + const tmpDir = await promisify(mkdir)('cce-'); + process.env.CCE_EXAMPLE_TMPDIR = tmpDir; + process.env.NODE_OPTIONS = '--max-old-space-size=8192'; + process.env.YARN_CACHE_FOLDER = `${tmpDir}/.yarn-cache`; + track(); + await setup(config); + await setupPackages(tmpDir); +}; diff --git a/packages/web-components/tests/integration/build/theme-zoning_steps.js b/packages/web-components/tests/integration/build/theme-zoning_steps.js new file mode 100644 index 000000000000..6062a09157dc --- /dev/null +++ b/packages/web-components/tests/integration/build/theme-zoning_steps.js @@ -0,0 +1,45 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const fs = require('fs-extra'); +const { setup: setupDevServer, teardown: teardownDevServer } = require('jest-dev-server'); +const exec = require('../exec'); +const replaceDependencies = require('../replace-dependencies'); + +const PORT = 1237; + +describe('Custom style example with inherited component class', () => { + beforeAll(async () => { + const projectRoot = path.resolve(__dirname, '../../..'); + const src = path.resolve(projectRoot, 'examples/codesandbox/styling/theme-zoning'); + const tmpDir = process.env.CCE_EXAMPLE_TMPDIR; + await fs.copy(src, `${tmpDir}/theme-zoning`); + await replaceDependencies([`${tmpDir}/theme-zoning/package.json`]); + await exec('yarn', ['install'], { cwd: `${tmpDir}/theme-zoning` }); + await setupDevServer({ + command: `cd ${tmpDir}/theme-zoning && node ${path.resolve(__dirname, 'webpack-server.js')} --port=${PORT}`, + launchTimeout: Number(process.env.LAUNCH_TIMEOUT), + port: PORT, + }); + await page.goto(`http://localhost:${PORT}`); + }, Number(process.env.LAUNCH_TIMEOUT)); + + it('should have footer button with the color of zoned theme', async () => { + const backgroundColorValue = await page.evaluate((dropdown) => { + const listBox = dropdown.shadowRoot.querySelector('.cds--btn'); + return listBox.ownerDocument.defaultView.getComputedStyle(listBox).getPropertyValue('background-color'); + }, await expect(page).toMatchElement('footer cds-button')); + expect(backgroundColorValue).toEqual(expect.stringMatching(/rgb\(\s*111,\s*111,\s*111\s*\)/)); + }); + + afterAll(async () => { + await teardownDevServer(); + }); +}); diff --git a/packages/web-components/tests/integration/build/vue_steps.js b/packages/web-components/tests/integration/build/vue_steps.js new file mode 100644 index 000000000000..83b60bfd82e6 --- /dev/null +++ b/packages/web-components/tests/integration/build/vue_steps.js @@ -0,0 +1,48 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const fs = require('fs-extra'); +const { setup: setupDevServer, teardown: teardownDevServer } = require('jest-dev-server'); +const exec = require('../exec'); +const replaceDependencies = require('../replace-dependencies'); + +const PORT = 8082; + +describe('Basic example', () => { + beforeAll(async () => { + const projectRoot = path.resolve(__dirname, '../../..'); + const src = path.resolve(projectRoot, 'examples/codesandbox/vue'); + const tmpDir = process.env.CCE_EXAMPLE_TMPDIR; + await fs.copy(src, `${tmpDir}/vue`); + await replaceDependencies([`${tmpDir}/vue/package.json`]); + await exec('yarn', ['install'], { cwd: `${tmpDir}/vue` }); + await setupDevServer({ + command: `cd ${tmpDir}/vue && yarn serve --port ${PORT}`, + launchTimeout: Number(process.env.LAUNCH_TIMEOUT), + port: PORT, + }); + await page.goto(`http://localhost:${PORT}`); + }, Number(process.env.LAUNCH_TIMEOUT)); + + it('should show a title', async () => { + await expect(page).toMatch('Hello World!'); + }); + + it('should have dropdown interactive', async () => { + await expect(page).toClick('cds-dropdown'); + await expect(page).toMatchElement('cds-dropdown[open]'); + await expect(page).toClick('cds-dropdown'); + await expect(page).toMatchElement('cds-dropdown:not([open])'); + }); + + afterAll(async () => { + await teardownDevServer(); + }); +}); diff --git a/packages/web-components/tests/integration/build/webpack-server.js b/packages/web-components/tests/integration/build/webpack-server.js new file mode 100644 index 000000000000..32239d48bb12 --- /dev/null +++ b/packages/web-components/tests/integration/build/webpack-server.js @@ -0,0 +1,48 @@ +#!/usr/bin/env node + +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const path = require('path'); +const commander = require('commander'); +const webpack = require('webpack'); +const WebpackDevServer = require('webpack-dev-server'); + +async function makeWebpackServer(port) { + // eslint-disable-next-line global-require + const config = require(path.resolve(process.cwd(), 'webpack.config.js')); + return new Promise((resolve, reject) => { + const compiler = webpack(config); + const server = new WebpackDevServer(compiler, Object.assign(config.devServer || {}, { open: false })); + compiler.hooks.done.tap('webpack-server', () => { + server.listen(port, (error) => { + if (error) { + reject(error); + } else { + resolve(server); + } + }); + }); + compiler.hooks.failed.tap('webpack-server', (error) => { + reject(error); + }); + }); +} + +commander.option('-p, --port [port]', 'The port to use').parse(process.argv); + +makeWebpackServer(commander.port).then( + () => { + process.exit(0); + }, + (error) => { + console.error(error); // eslint-disable-line no-console + process.exit(1); + } +); diff --git a/packages/web-components/tests/integration/exec.js b/packages/web-components/tests/integration/exec.js new file mode 100644 index 000000000000..814fada4dfbd --- /dev/null +++ b/packages/web-components/tests/integration/exec.js @@ -0,0 +1,26 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const execa = require('execa'); + +/** + * Executes the given command. + * + * @param {string} command The command. + * @param {string[]} [args=[]] The arguments. + * @param {object} [options] The options. + */ +function exec(command, args = [], options) { + const promise = execa(command, args, options); + promise.stdout.pipe(process.stdout); + promise.stderr.pipe(process.stderr); + return promise; +} + +module.exports = exec; diff --git a/packages/web-components/tests/integration/replace-dependencies.js b/packages/web-components/tests/integration/replace-dependencies.js new file mode 100644 index 000000000000..73d05fad38ea --- /dev/null +++ b/packages/web-components/tests/integration/replace-dependencies.js @@ -0,0 +1,43 @@ +/** + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const fs = require('fs'); +const { promisify } = require('util'); + +const readFile = promisify(fs.readFile); +const writeFile = promisify(fs.writeFile); + +const deps = ['dependencies', 'peerDependencies', 'devDependencies']; +const packs = ['carbon-web-components']; + +/** + * Replaces `@carbon/ibmdotcom-*` dependencies in the given `package.json` files with the local directory references. + * + * @param {string[]} files The files. + */ +const replace = async (files) => { + await Promise.all( + files.map(async (file) => { + const contents = JSON.parse(await readFile(file)); + // eslint-disable-next-line no-restricted-syntax + for (const dep of deps) { + const item = contents[dep]; + if (item) { + // eslint-disable-next-line no-restricted-syntax + for (const pack of packs) { + if (item[pack]) { + item[pack] = `file:../${pack}.tar.gz`; + } + } + } + } + await writeFile(file, JSON.stringify(contents, null, 2)); + }) + ); +}; + +module.exports = replace; diff --git a/packages/web-components/tests/integration/ui/accordion_steps.js b/packages/web-components/tests/integration/ui/accordion_steps.js new file mode 100644 index 000000000000..56de18ed75b7 --- /dev/null +++ b/packages/web-components/tests/integration/ui/accordion_steps.js @@ -0,0 +1,33 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-accordion', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-accordion--default` + ); + }); + + it('should have accordion interactive', async () => { + await page.click('cds-accordion-item:nth-of-type(1) button'); + await expect(page).toHaveSelector( + 'cds-accordion-item:nth-of-type(1) #content', + { + state: 'visible', + } + ); + await page.click('cds-accordion-item:nth-of-type(1) button'); + await expect(page).toHaveSelector( + 'cds-accordion-item:nth-of-type(1) #content', + { + state: 'hidden', + } + ); + }); +}); diff --git a/packages/web-components/tests/integration/ui/checkbox_steps.js b/packages/web-components/tests/integration/ui/checkbox_steps.js new file mode 100644 index 000000000000..9eb2eef44738 --- /dev/null +++ b/packages/web-components/tests/integration/ui/checkbox_steps.js @@ -0,0 +1,30 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-checkbox', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-checkbox--default` + ); + }); + + it('should have checkbox interactive', async () => { + await page.click('cds-checkbox label'); + const backgroundColorValue = await page.evaluate( + (label) => + label.ownerDocument.defaultView + .getComputedStyle(label, '::before') + .getPropertyValue('background-color'), + await page.$('cds-checkbox label') + ); + expect(backgroundColorValue).toEqual( + expect.stringMatching(/rgb\(\s*22,\s*22,\s*22\s*\)/) + ); + }); +}); diff --git a/packages/web-components/tests/integration/ui/code-snippet_steps.js b/packages/web-components/tests/integration/ui/code-snippet_steps.js new file mode 100644 index 000000000000..4060089e6207 --- /dev/null +++ b/packages/web-components/tests/integration/ui/code-snippet_steps.js @@ -0,0 +1,27 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-code-snippet', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-code-snippet--multi-line` + ); + }); + + it('should have the expando interactive', async () => { + await page.click('cds-code-snippet button.cds--snippet-btn--expand'); + await expect(page).toHaveSelector( + 'cds-code-snippet .cds-ce--snippet-container--expanded' + ); + await page.click('cds-code-snippet button.cds--snippet-btn--expand'); + await expect(page).toHaveSelector( + 'cds-code-snippet :not(.cds-ce--snippet-container--expanded)' + ); + }); +}); diff --git a/packages/web-components/tests/integration/ui/combo-box_steps.js b/packages/web-components/tests/integration/ui/combo-box_steps.js new file mode 100644 index 000000000000..d32a6eb97ed1 --- /dev/null +++ b/packages/web-components/tests/integration/ui/combo-box_steps.js @@ -0,0 +1,27 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-combo-box', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-combo-box--default` + ); + }); + + it('should have combo box interactive', async () => { + await page.click('cds-combo-box .cds--list-box__field'); + await expect(page).toHaveSelector('cds-combo-box .cds--list-box__menu', { + state: 'visible', + }); + await page.click('cds-combo-box .cds--list-box__field'); + await expect(page).toHaveSelector('cds-combo-box .cds--list-box__menu', { + state: 'hidden', + }); + }); +}); diff --git a/packages/web-components/tests/integration/ui/content-switcher_steps.js b/packages/web-components/tests/integration/ui/content-switcher_steps.js new file mode 100644 index 000000000000..7d0ff2ed0e5a --- /dev/null +++ b/packages/web-components/tests/integration/ui/content-switcher_steps.js @@ -0,0 +1,23 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-content-switcher', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-content-switcher--default` + ); + }); + + it('should have content switcher interactive', async () => { + await page.click('cds-content-switcher-item[value="router"] button'); + await expect(page).toHaveSelector( + 'cds-content-switcher-item[value="router"] button[aria-selected="true"]' + ); + }); +}); diff --git a/packages/web-components/tests/integration/ui/data-table_steps.js b/packages/web-components/tests/integration/ui/data-table_steps.js new file mode 100644 index 000000000000..7fda9894b0b8 --- /dev/null +++ b/packages/web-components/tests/integration/ui/data-table_steps.js @@ -0,0 +1,31 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('data-table', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-data-table--expandable` + ); + }); + + it('should have the expando interactive', async () => { + await page.click('cds-table-expand-row:nth-of-type(1) button'); + await expect(page).toHaveSelector( + 'cds-table-expanded-row:nth-of-type(1) .cds--child-row-inner-container', + { + state: 'visible', + } + ); + await page.click('cds-table-expand-row:nth-of-type(1) button'); + await expect(page).toHaveSelector( + 'cds-table-expanded-row:nth-of-type(1) .cds--child-row-inner-container', + { state: 'hidden' } + ); + }); +}); diff --git a/packages/web-components/tests/integration/ui/dropdown_steps.js b/packages/web-components/tests/integration/ui/dropdown_steps.js new file mode 100644 index 000000000000..812c5d84041e --- /dev/null +++ b/packages/web-components/tests/integration/ui/dropdown_steps.js @@ -0,0 +1,27 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-dropdown', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-dropdown--default` + ); + }); + + it('should have dropdown interactive', async () => { + await page.click('cds-dropdown .cds--list-box__field'); + await expect(page).toHaveSelector('cds-dropdown .cds--list-box__menu', { + state: 'visible', + }); + await page.click('cds-dropdown .cds--list-box__field'); + await expect(page).toHaveSelector('cds-dropdown .cds--list-box__menu', { + state: 'hidden', + }); + }); +}); diff --git a/packages/web-components/tests/integration/ui/jest-playwright.config.js b/packages/web-components/tests/integration/ui/jest-playwright.config.js new file mode 100644 index 000000000000..a63b3a4d974b --- /dev/null +++ b/packages/web-components/tests/integration/ui/jest-playwright.config.js @@ -0,0 +1,15 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +module.exports = { + browser: process.env.CCE_UI_INTEGRATION_TEST_BROWSER, + launchBrowserApp: { + headless: process.env.CI !== 'false', + }, +}; diff --git a/packages/web-components/tests/integration/ui/jest.config.js b/packages/web-components/tests/integration/ui/jest.config.js new file mode 100644 index 000000000000..d480335c35ae --- /dev/null +++ b/packages/web-components/tests/integration/ui/jest.config.js @@ -0,0 +1,18 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +process.env.JEST_PLAYWRIGHT_CONFIG = `${__dirname}/jest-playwright.config.js`; + +module.exports = { + globalSetup: './setup', + globalTeardown: './teardown', + setupFilesAfterEnv: ['expect-playwright'], + testEnvironment: 'jest-playwright-preset', + testRegex: '.*_steps\\.js$', +}; diff --git a/packages/web-components/tests/integration/ui/modal_steps.js b/packages/web-components/tests/integration/ui/modal_steps.js new file mode 100644 index 000000000000..2eeb1bd1d0d0 --- /dev/null +++ b/packages/web-components/tests/integration/ui/modal_steps.js @@ -0,0 +1,23 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-modal', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-modal--default` + ); + }); + + it('should have modal closable', async () => { + await page.click('cds-modal-close-button button'); + await expect(page).toHaveSelector('cds-modal .cds--modal-container', { + state: 'hidden', + }); + }); +}); diff --git a/packages/web-components/tests/integration/ui/multi-select_steps.js b/packages/web-components/tests/integration/ui/multi-select_steps.js new file mode 100644 index 000000000000..f8d8f36ed83b --- /dev/null +++ b/packages/web-components/tests/integration/ui/multi-select_steps.js @@ -0,0 +1,27 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-multi-select', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-multi-select--default` + ); + }); + + it('should have multi select interactive', async () => { + await page.click('cds-multi-select .cds--list-box__field'); + await expect(page).toHaveSelector('cds-multi-select .cds--list-box__menu', { + state: 'visible', + }); + await page.click('cds-multi-select .cds--list-box__field'); + await expect(page).toHaveSelector('cds-multi-select .cds--list-box__menu', { + state: 'hidden', + }); + }); +}); diff --git a/packages/web-components/tests/integration/ui/notification_steps.js b/packages/web-components/tests/integration/ui/notification_steps.js new file mode 100644 index 000000000000..a678b723e279 --- /dev/null +++ b/packages/web-components/tests/integration/ui/notification_steps.js @@ -0,0 +1,42 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-inline-notification', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-notifications--inline` + ); + }); + + it('should have notification closable', async () => { + await page.click( + 'cds-inline-notification .cds--inline-notification__close-button' + ); + await expect(page).toHaveSelector('cds-inline-notification', { + state: 'hidden', + }); + }); +}); + +describe('cds-toast-notification', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-notifications--toast` + ); + }); + + it('should have notification closable', async () => { + await page.click( + 'cds-toast-notification .cds--toast-notification__close-button' + ); + await expect(page).toHaveSelector('cds-toast-notification', { + state: 'hidden', + }); + }); +}); diff --git a/packages/web-components/tests/integration/ui/overflow-menu_steps.js b/packages/web-components/tests/integration/ui/overflow-menu_steps.js new file mode 100644 index 000000000000..0a622dc8af66 --- /dev/null +++ b/packages/web-components/tests/integration/ui/overflow-menu_steps.js @@ -0,0 +1,27 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-overflow-menu', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-overflow-menu--default` + ); + }); + + it('should have overflow menu interactive', async () => { + await page.click('cds-overflow-menu'); + await expect(page).toHaveSelector('cds-overflow-menu-body', { + state: 'visible', + }); + await page.click('html'); + await expect(page).toHaveSelector('cds-overflow-menu-body', { + state: 'hidden', + }); + }); +}); diff --git a/packages/web-components/tests/integration/ui/setup.js b/packages/web-components/tests/integration/ui/setup.js new file mode 100644 index 000000000000..d9152151efb4 --- /dev/null +++ b/packages/web-components/tests/integration/ui/setup.js @@ -0,0 +1,36 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const { setup: setupDevServer } = require('jest-dev-server'); +const setup = require('jest-playwright-preset/setup'); +const isPortReachable = require('is-port-reachable'); + +module.exports = async (config) => { + if (!process.env.LAUNCH_TIMEOUT) { + process.env.LAUNCH_TIMEOUT = 120000; + } + if (!process.env.PORT) { + process.env.PORT = 9000; + } + await setup(config); + const isOpenAlready = await isPortReachable(Number(process.env.PORT), { + host: 'localhost', + }); + if (!isOpenAlready) { + await setupDevServer({ + command: `yarn http-server storybook-static -p ${process.env.PORT}`, + launchTimeout: Number(process.env.LAUNCH_TIMEOUT), + port: process.env.PORT, + }); + await isPortReachable(Number(process.env.PORT), { + host: 'localhost', + timeout: Number(process.env.LAUNCH_TIMEOUT), + }); + } +}; diff --git a/packages/web-components/tests/integration/ui/tabs_steps.js b/packages/web-components/tests/integration/ui/tabs_steps.js new file mode 100644 index 000000000000..c3ec5a35e658 --- /dev/null +++ b/packages/web-components/tests/integration/ui/tabs_steps.js @@ -0,0 +1,27 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-tabs', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-tabs--default` + ); + }); + + it('should have tabs interactive', async () => { + await page.click('cds-tab[value="router"] a'); + await expect(page).toHaveSelector('#panel-all', { state: 'hidden' }); + await expect(page).toHaveSelector('#panel-cloudFoundry', { + state: 'hidden', + }); + await expect(page).toHaveSelector('#panel-staging', { state: 'hidden' }); + await expect(page).toHaveSelector('#panel-dea', { state: 'hidden' }); + await expect(page).toHaveSelector('#panel-router', { state: 'visible' }); + }); +}); diff --git a/packages/web-components/tests/integration/ui/teardown.js b/packages/web-components/tests/integration/ui/teardown.js new file mode 100644 index 000000000000..2e4668efa57f --- /dev/null +++ b/packages/web-components/tests/integration/ui/teardown.js @@ -0,0 +1,16 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +const { teardown: teardownDevServer } = require('jest-dev-server'); +const teardown = require('jest-playwright-preset/teardown'); + +module.exports = async (config) => { + await teardown(config); + await teardownDevServer(); +}; diff --git a/packages/web-components/tests/integration/ui/tile_steps.js b/packages/web-components/tests/integration/ui/tile_steps.js new file mode 100644 index 000000000000..6c0126058f28 --- /dev/null +++ b/packages/web-components/tests/integration/ui/tile_steps.js @@ -0,0 +1,33 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-tile', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-tile--expandable` + ); + }); + + it('should have the expando interactive', async () => { + await page.click('cds-expandable-tile button'); + // Playwright's auto-wait-for-transitionend feature does not seems to work here, + // presubably because animation happens after EOM + await page.waitForFunction( + () => document.querySelector('cds-expandable-tile').offsetHeight > 300, + { polling: 'raf' } + ); + await page.click('cds-expandable-tile button'); + // Playwright's auto-wait-for-transitionend feature does not seems to work here, + // presubably because animation happens after EOM + await page.waitForFunction( + () => document.querySelector('cds-expandable-tile').offsetHeight < 300, + { polling: 'raf' } + ); + }); +}); diff --git a/packages/web-components/tests/integration/ui/tooltip_steps.js b/packages/web-components/tests/integration/ui/tooltip_steps.js new file mode 100644 index 000000000000..ae7e7ead4605 --- /dev/null +++ b/packages/web-components/tests/integration/ui/tooltip_steps.js @@ -0,0 +1,23 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +describe('cds-tooltip', () => { + beforeAll(async () => { + await page.goto( + `http://localhost:${process.env.PORT}/iframe.html?id=components-tooltip--default` + ); + }); + + it('should have overflow menu interactive', async () => { + await page.click('cds-tooltip'); + await expect(page).toHaveSelector('cds-tooltip-body', { state: 'visible' }); + await page.click('html'); + await expect(page).toHaveSelector('cds-tooltip-body', { state: 'hidden' }); + }); +}); diff --git a/packages/web-components/tests/karma-setup-renderroot.js b/packages/web-components/tests/karma-setup-renderroot.js new file mode 100644 index 000000000000..3da9eb34bee5 --- /dev/null +++ b/packages/web-components/tests/karma-setup-renderroot.js @@ -0,0 +1,20 @@ +/** + * @license + * + * Copyright IBM Corp. 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +document.head.insertAdjacentHTML( + 'afterBegin', + ` + + ` +); diff --git a/packages/web-components/tests/karma-test-shim.js b/packages/web-components/tests/karma-test-shim.js new file mode 100644 index 000000000000..0ca44c853e31 --- /dev/null +++ b/packages/web-components/tests/karma-test-shim.js @@ -0,0 +1,19 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +// For generating coverage report for untested files +const srcContext = require.context( + '../src/components', + true, + /^(?!.*story).*\.ts$/ +); +srcContext.keys().forEach(srcContext); + +const specContext = require.context('.', true, /_spec\.ts$/); +specContext.keys().forEach(specContext); diff --git a/packages/web-components/tests/karma.conf.js b/packages/web-components/tests/karma.conf.js new file mode 100644 index 000000000000..d79d20917427 --- /dev/null +++ b/packages/web-components/tests/karma.conf.js @@ -0,0 +1,233 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* eslint-disable global-require */ + +const path = require('path'); +const sass = require('sass'); + +function normalizeBrowser(browser) { + return ( + { + chrome: `Chrome${process.env.TRAVIS ? '_Travis' : ''}`, + firefox: 'Firefox', + }[browser.toLowerCase()] || browser + ); +} + +module.exports = function setupKarma(config) { + const { + browsers, + collectCoverage, + noPruneShapshot, + specs, + random, + updateSnapshot, + useExperimentalFeatures, + verbose, + } = config.customConfig; + + config.set({ + basePath: '..', + + browsers: (browsers.length > 0 ? browsers : ['ChromeHeadless']).map( + normalizeBrowser + ), + + frameworks: ['jasmine', 'snapshot'], + + client: { + jasmine: { + random: !!random, + }, + }, + + files: [ + 'src/polyfills/index.ts', + 'tests/utils/snapshot.js', + 'tests/snapshots/**/*.md', + 'tests/karma-setup-renderroot.js', + ].concat(specs.length > 0 ? specs : ['tests/karma-test-shim.js']), + + preprocessors: { + 'src/**/*.[jt]s': ['webpack', 'sourcemap'], // For generating coverage report for untested files + 'tests/karma-test-shim.js': ['webpack', 'sourcemap'], + 'tests/spec/**/*.ts': ['webpack', 'sourcemap'], + 'tests/utils/**/*.js': ['webpack', 'sourcemap'], + 'tests/snapshots/**/*.md': ['snapshot'], + }, + + webpack: { + mode: 'development', + devtool: 'inline-source-maps', + resolve: { + alias: { + // In our development environment (where `@carbon/web-components/es/icons` may not have been built yet), + // we load icons from `@carbon/icons` and use a Webpack loader to convert the icons to `lit-html` version + '@carbon/web-components/es/icons': '@carbon/icons/lib', + }, + extensions: ['.js', '.ts'], + }, + module: { + rules: [ + { + test: /@storybook[\\/]addon-/i, + use: 'null-loader', + }, + { + test: /@carbon[\\/]icons[\\/]/i, + use: [require.resolve('../tools/svg-result-carbon-icon-loader')], + }, + { + test: /\.ts$/, + use: [ + { + // Build note: Locking down `@babel/plugin-transform-typescript` to `~7.6.0` + // given `7.7` or later versions seems to have a problem with using decorator with fields without an initializer + loader: 'babel-loader', + options: { + configFile: path.resolve(__dirname, '..', '.babelrc'), + }, + }, + ], + }, + !collectCoverage + ? {} + : { + test: /\.[jt]s$/, + exclude: [ + __dirname, + path.resolve(__dirname, '../node_modules'), + ], + enforce: 'post', + use: { + loader: 'istanbul-instrumenter-loader', + options: { + esModules: true, + }, + }, + }, + { + test: /\.js$/, + include: [ + __dirname, + path.dirname(require.resolve('lit')), + path.dirname(require.resolve('@webcomponents/custom-elements')), + // `ShadyCSS` NPM package is missing its entry point file + path.dirname( + require.resolve('@webcomponents/shadycss/scoping-shim.min.js') + ), + path.dirname(require.resolve('@webcomponents/shadydom')), + path.resolve(__dirname, '..', 'src/polyfills'), + ], + use: { + loader: 'babel-loader', + options: { + configFile: path.resolve(__dirname, '..', '.babelrc'), + }, + }, + }, + { + test: /\.scss$/, + sideEffects: true, + use: [ + require.resolve('../tools/css-result-loader'), + { + loader: 'postcss-loader', + options: { + plugins: () => [ + require('autoprefixer')({ + overrideBrowserslist: ['last 1 version'], + }), + ], + }, + }, + { + loader: 'sass-loader', + options: { + additionalData: ` + $feature-flags: ( + grid: ${useExperimentalFeatures}, + ui-shell: true, + ); + `, + implementation: sass, + webpackImporter: false, + sassOptions: { + includePaths: [ + path.resolve(__dirname, '..', 'node_modules'), + path.resolve(__dirname, '../../../', 'node_modules'), + ], + }, + }, + }, + ], + }, + { + test: /\.mdx$/, + use: 'null-loader', + }, + ], + }, + }, + + webpackMiddleware: { + noInfo: !verbose, + }, + + customLaunchers: { + Chrome_Travis: { + base: 'ChromeHeadless', + flags: ['--no-sandbox'], + }, + }, + + plugins: [ + require('karma-jasmine'), + require('karma-spec-reporter'), + require('karma-sourcemap-loader'), + require('karma-coverage-istanbul-reporter'), + require('karma-webpack'), + require('karma-snapshot'), + require('karma-chrome-launcher'), + require('karma-firefox-launcher'), + ], + + reporters: ['spec', ...(!collectCoverage ? [] : ['coverage-istanbul'])], + + coverageIstanbulReporter: { + reports: ['html', 'text'], + dir: path.join(__dirname, 'coverage'), + combineBrowserReports: true, + fixWebpackSourcePaths: true, + verbose, + }, + + snapshot: { + prune: !noPruneShapshot, + update: updateSnapshot, + pathResolver(basePath, suiteName) { + return path.resolve(basePath, `tests/snapshots/${suiteName}.md`); + }, + }, + + port: 9876, + + colors: true, + + browserNoActivityTimeout: 60000, + + autoWatch: true, + autoWatchBatchDelay: 400, + + logLevel: verbose ? config.LOG_DEBUG : config.LOG_INFO, + + concurrency: Infinity, + }); +}; diff --git a/packages/web-components/tests/snapshots/cds-btn.md b/packages/web-components/tests/snapshots/cds-btn.md new file mode 100644 index 000000000000..f00ec2ed44b5 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-btn.md @@ -0,0 +1,92 @@ +# `cds-button` + +## `Misc attributes` + +#### `should render with minimum attributes for + +``` + +#### `should render with various attributes for + +``` + +#### `should render with minimum attributes for ` + +``` + + + + + + + +``` + +#### `should render with various attributes for ` + +``` + + + + + + + +``` + +#### `should render disabled state for ` + +``` +

      + + + + +

      + +``` diff --git a/packages/web-components/tests/snapshots/cds-button.md b/packages/web-components/tests/snapshots/cds-button.md new file mode 100644 index 000000000000..d078bbbd4a8a --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-button.md @@ -0,0 +1,88 @@ +# `cds-button` + +## `Misc attributes` + +#### `should render with minimum attributes for + +``` + +#### `should render with various attributes for + +``` + +#### `should render with minimum attributes for
      ` + +``` + + +``` + +#### `should render with various attributes for ` + +``` + + +``` + +#### `should render disabled state for ` + +``` + + +``` diff --git a/packages/web-components/tests/snapshots/cds-checkbox.md b/packages/web-components/tests/snapshots/cds-checkbox.md new file mode 100644 index 000000000000..f6b86f7823fa --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-checkbox.md @@ -0,0 +1,62 @@ +# `cds-checkbox` + +## `Rendering` + +#### `Should render with minimum attributes` + +``` + + + + +
      +
      + +``` + +#### `Should render with various attributes` + +``` + + + + +
      +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-code-snippet.md b/packages/web-components/tests/snapshots/cds-code-snippet.md new file mode 100644 index 000000000000..9bfa9aed7b30 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-code-snippet.md @@ -0,0 +1,173 @@ +# `cds-code-snippet` + +## `Rendering` + +#### `Should render with minimum attributes for single line mode` + +``` +
      +
      +    
      +      
      +      
      +    
      +  
      +
      +
      +
      + + Copy to Clipboard + + +``` + +#### `Should render with minimum attributes for multi line mode` + +``` +
      +
      +    
      +      
      +      
      +    
      +  
      +
      + + Copy to Clipboard + + +``` + +#### `Should render with minimum attributes for inline mode` + +``` + + + + + + + Copy to Clipboard + + + +``` + +#### `Should render with various attributes for single line mode` + +``` +
      +
      +    
      +      
      +      
      +    
      +  
      +
      +
      +
      + + Copy to Clipboard + + +``` + +#### `Should render with various attributes for multi line mode` + +``` +
      +
      +    
      +      
      +      
      +    
      +  
      +
      + + Copy to Clipboard + + +``` + +#### `Should render with various attributes for inline mode` + +``` + + + + + + + Copy to Clipboard + + + +``` + +## `Expand/collapse button in multi line mode` + +#### `Should render the expando` + +``` + +``` diff --git a/packages/web-components/tests/snapshots/cds-combo-box.md b/packages/web-components/tests/snapshots/cds-combo-box.md new file mode 100644 index 000000000000..adcf1d6e2473 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-combo-box.md @@ -0,0 +1,124 @@ +# `cds-combo-box` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + +
      + + + +
      + +
      +
      + +``` + +#### `should render with various attributes` + +``` + +
      + + + +
      +
      + + +
      +
      +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-copy-button.md b/packages/web-components/tests/snapshots/cds-copy-button.md new file mode 100644 index 000000000000..b572371ff5db --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-copy-button.md @@ -0,0 +1,31 @@ +# `cds-copy-button` + +## `Rendering` + +#### `Should render with minimum attributes` + +``` + + + + + +``` + +#### `Should render with various attributes` + +``` + + + + + +``` diff --git a/packages/web-components/tests/snapshots/cds-dropdown.md b/packages/web-components/tests/snapshots/cds-dropdown.md new file mode 100644 index 000000000000..9919699e485a --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-dropdown.md @@ -0,0 +1,130 @@ +# `cds-dropdown` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + +
      + + + +
      + +
      +
      + +``` + +#### `should render with various attributes` + +``` + +
      +
      + + +
      +
      +
      + + + +
      +
      + + helper-text-foo + +
      +
      +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-inline-loading.md b/packages/web-components/tests/snapshots/cds-inline-loading.md new file mode 100644 index 000000000000..bf8d920b5390 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-inline-loading.md @@ -0,0 +1,65 @@ +# `cds-inline-loading` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` +
      +
      +
      +
      +

      + + +

      + +``` + +#### `should render with unknown status` + +``` +

      + + +

      + +``` + +#### `should render with inactive status` + +``` +
      +
      +
      +
      +

      + + +

      + +``` + +#### `should render with finished status` + +``` +
      +
      +

      + + +

      + +``` + +#### `should render with error status` + +``` +
      +
      +

      + + +

      + +``` diff --git a/packages/web-components/tests/snapshots/cds-inline-notification.md b/packages/web-components/tests/snapshots/cds-inline-notification.md new file mode 100644 index 000000000000..e1b0da407e39 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-inline-notification.md @@ -0,0 +1,55 @@ +# `cds-inline-notification` + +## `Rendering titles` + +#### `Should render with minimum attributes` + +``` +
      +
      +

      + + +

      +
      + + +
      + + +
      +
      + + +``` + +#### `Should render with various attributes` + +``` +
      +
      +

      + title-foo + + +

      +
      + subtitle-foo + + +
      + + +
      +
      + + +``` diff --git a/packages/web-components/tests/snapshots/cds-input.md b/packages/web-components/tests/snapshots/cds-input.md new file mode 100644 index 000000000000..ee425c3e369c --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-input.md @@ -0,0 +1,46 @@ +# `cds-text-input` + +## `Rendering` + +#### `Should render with various attributes` + +``` + +
      + +
      +
      + + helper-text-foo + +
      +
      + + validity-message-foo + +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-link.md b/packages/web-components/tests/snapshots/cds-link.md new file mode 100644 index 000000000000..6419471fa7da --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-link.md @@ -0,0 +1,79 @@ +# `cds-link` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` +
      + + + + + +``` + +#### `should render with various attributes` + +``` + + + + + + +``` + +#### `should render disabled state` + +``` + + +

      +

      + +``` diff --git a/packages/web-components/tests/snapshots/cds-multi-select.md b/packages/web-components/tests/snapshots/cds-multi-select.md new file mode 100644 index 000000000000..ff208c68a7dd --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-multi-select.md @@ -0,0 +1,119 @@ +# `cds-multi-select` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + +
      + + + +
      + +
      +
      + +``` + +#### `should render with various attributes` + +``` + +
      + + + +
      +
      + + +
      +
      +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-number-input.md b/packages/web-components/tests/snapshots/cds-number-input.md new file mode 100644 index 000000000000..47c4630e878f --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-number-input.md @@ -0,0 +1,67 @@ +# `cds-number-input` + +## `Rendering` + +#### `Should render with various attributes` + +``` +
      + +
      + + + +
      + +
      +
      + +
      +
      +
      +
      +
      + + helper-text-foo + +
      + +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-pagination.md b/packages/web-components/tests/snapshots/cds-pagination.md new file mode 100644 index 000000000000..13e0b5ae4757 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-pagination.md @@ -0,0 +1,156 @@ +# `cds-pagination` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` +
      + + +
      +
      + + Item 1–10 + +
      +
      +
      +
      + + +
      + + +
      +
      + +``` + +#### `should render with various attributes` + +``` +
      + + +
      +
      + + 11–30 of 200 items + +
      +
      +
      +
      + + +
      + + +
      +
      + +``` + +#### `should render with minimum attributes` + +``` + +
      + +
      + + +``` + +#### `should render with minimum attributes` + +``` +
      + + +
      + + of 10 pages + + +``` diff --git a/packages/web-components/tests/snapshots/cds-progress-bar.md b/packages/web-components/tests/snapshots/cds-progress-bar.md new file mode 100644 index 000000000000..ece8006cbc23 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-progress-bar.md @@ -0,0 +1,67 @@ +# `cds-progress-bar` + +## `Rendering` + +#### `Should render with minimum attributes` + +``` +
      +
      + + +
      +
      +
      +
      +
      +
      + +``` + +#### `Should render with various attributes` + +``` +
      +
      + + Progress Bar label + +
      +
      +
      +
      +
      +
      + Optional helper text +
      + Loading +
      +
      +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-progress-step.md b/packages/web-components/tests/snapshots/cds-progress-step.md new file mode 100644 index 000000000000..c33ae54e7baf --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-progress-step.md @@ -0,0 +1,56 @@ +# `cds-progress-step` + +## `Rendering` + +#### `Should render with minimum attributes` + +``` +
      + +

      + First step +

      +
      + + + + +
      + +``` + +#### `Should render with various attributes` + +``` +
      + +

      + First step +

      +
      + +

      + secondary-label-text-foo +

      +
      + + +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-radio-button.md b/packages/web-components/tests/snapshots/cds-radio-button.md new file mode 100644 index 000000000000..0e830627ddf3 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-radio-button.md @@ -0,0 +1,54 @@ +# `cds-radio-button` + +## `Rendering` + +#### `Should render with minimum attributes` + +``` + + + +``` + +#### `Should render with various attributes` + +``` + + + +``` diff --git a/packages/web-components/tests/snapshots/cds-search.md b/packages/web-components/tests/snapshots/cds-search.md new file mode 100644 index 000000000000..c410e5761616 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-search.md @@ -0,0 +1,73 @@ +# `cds-search` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` +
      + + +
      + + + + +``` + +#### `should render with various attributes` + +``` +
      + + +
      + + + + +``` diff --git a/packages/web-components/tests/snapshots/cds-select.md b/packages/web-components/tests/snapshots/cds-select.md new file mode 100644 index 000000000000..09937739a6e6 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-select.md @@ -0,0 +1,224 @@ +# `cds-select` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` +
      + +
      + +
      +
      + +``` + +#### `should render with various attributes` + +``` +
      + +
      + +
      +
      + + helper-text-foo + +
      +
      + +``` + +#### `should render invalid state` + +``` +
      + +
      + +
      +
      + validity-message-foo +
      +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-slider.md b/packages/web-components/tests/snapshots/cds-slider.md new file mode 100644 index 000000000000..e42abedc7cdf --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-slider.md @@ -0,0 +1,110 @@ +# `cds-slider` + +## `Rendering` + +#### `Should render with minimum attributes` + +``` + +
      + + + 0 + + + + + + 100 + + + + +
      + +``` + +#### `Should render with various attributes` + +``` + +
      + + + 0 + + + + + + 100 + + + + +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-text-input.md b/packages/web-components/tests/snapshots/cds-text-input.md new file mode 100644 index 000000000000..6f52f1efec69 --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-text-input.md @@ -0,0 +1,30 @@ +# `cds-text-input` + +## `Rendering` + +#### `Should render with various attributes` + +``` +
      +
      +
      +
      +
      + +
      + +
      +
      + +``` diff --git a/packages/web-components/tests/snapshots/cds-textarea.md b/packages/web-components/tests/snapshots/cds-textarea.md new file mode 100644 index 000000000000..4ee4585162ce --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-textarea.md @@ -0,0 +1,41 @@ +# `cds-textarea` + +## `Rendering` + +#### `Should render with various attributes` + +``` +
      + +
      +
      + +
      +
      + + helper-text-foo + +
      + + +``` diff --git a/packages/web-components/tests/snapshots/cds-tile.md b/packages/web-components/tests/snapshots/cds-tile.md new file mode 100644 index 000000000000..fea835b92e1b --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-tile.md @@ -0,0 +1,305 @@ +# `cds-tile` + +## `cds-clickable-tile` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + + + + + +``` + +#### `should render with various attributes` + +``` + + + + + + +``` + +#### `should render disabled state` + +``` + + + + + + +``` + +## `cds-expandable-tile` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + +
      +
      + + +
      +
      + + +
      +
      + +``` + +#### `should render with various attributes` + +``` + +
      +
      + + +
      +
      + + +
      +
      + +``` + +## `cds-selectable-tile` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + + +``` + +#### `should render with various attributes` + +``` + + + +``` + +## `cds-radio-tile` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + +``` + +#### `should render with various attributes` + +``` + + +``` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + +``` + +#### `should render with various attributes` + +``` + + +``` diff --git a/packages/web-components/tests/snapshots/cds-toggle.md b/packages/web-components/tests/snapshots/cds-toggle.md new file mode 100644 index 000000000000..55beb3c0bb8f --- /dev/null +++ b/packages/web-components/tests/snapshots/cds-toggle.md @@ -0,0 +1,67 @@ +# `cds-toggle` + +## `Rendering` + +#### `Should render with minimum attributes` + +``` + + + +``` + +#### `Should render with various attributes` + +``` + + + +``` diff --git a/packages/web-components/tests/snapshots/data-table.md b/packages/web-components/tests/snapshots/data-table.md new file mode 100644 index 000000000000..7454ebc15b6f --- /dev/null +++ b/packages/web-components/tests/snapshots/data-table.md @@ -0,0 +1,273 @@ +# `data-table` + +## `cds-table-batch-action` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` +
      +

      + 0 item selected +

      +
      +
      + + + +
      + +``` + +#### `should render with various attributes` + +``` +
      +

      + 3 items selected +

      +
      +
      + + + +
      + +``` + +#### `should render non-plural selected rows count` + +``` +
      +

      + 1 item selected +

      +
      +
      + + + +
      + +``` + +## `cds-table-header-cell` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + + + + + + +``` + +#### `should render with various attributes` + +``` + + +``` + +## `cds-table-row` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + + +``` + +#### `should render with various attributes` + +``` +
      +
      + + + + +
      +
      + + + +``` + +## `cds-table-toolbar-search` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + +``` + +#### `should render with various attributes` + +``` + + +``` + +## `cds-table-expand-row` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` +
      + +
      + + +``` + +#### `should render with various attributes` + +``` +
      + +
      +
      + +
      + + + +
    + + +``` diff --git a/packages/web-components/tests/snapshots/file-uploader.md b/packages/web-components/tests/snapshots/file-uploader.md new file mode 100644 index 000000000000..dbd8428f7ddc --- /dev/null +++ b/packages/web-components/tests/snapshots/file-uploader.md @@ -0,0 +1,165 @@ +# `file-uploader` + +## `cds-file-uploader` + +## `Misc attributes` + +#### `should render with various attributes` + +``` +

    + + +

    +

    + + +

    + + +
    + + +
    + +``` + +## `cds-file-uploader-item` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` +

    + + +

    + + + + + + +``` + +#### `should render with various attributes` + +``` +

    + + +

    + + + + +
    +
    +
    + +
    + +``` + +#### `should render uploaded state` + +``` +

    + + +

    + + + + +``` + +#### `should render editing state` + +``` +

    + + +

    + + + + + +``` + +#### `should render editing state with various attributes` + +``` +

    + + +

    + + + +
    +
    +
    + +
    + +``` diff --git a/packages/web-components/tests/snapshots/ui-shell.md b/packages/web-components/tests/snapshots/ui-shell.md new file mode 100644 index 000000000000..83e61ae4c70e --- /dev/null +++ b/packages/web-components/tests/snapshots/ui-shell.md @@ -0,0 +1,443 @@ +# `ui-shell` + +## `cds-header-menu-button` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + +``` + +#### `should render with various attributes for inactive state` + +``` + + +``` + +#### `should render with various attributes for active state` + +``` + + +``` + +## `cds-header-menu` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + +
      + + +
    + +``` + +#### `should render with various attributes` + +``` + + trigger-content-foo + +
      + + +
    + +``` + +## `cds-header-name` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + + + + +``` + +#### `should render with various attributes` + +``` + + + prefix-foo + + + + + +``` + +## `cds-header-nav` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` +
    +
    +
      + + +
    + +``` + +#### `should render with various attributes` + +``` +
    +
    +
      + + +
    + +``` + +## `cds-header-nav-item` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + + + + + + +``` + +#### `should render with various attributes` + +``` + + + + + + + +``` + +## `cds-side-nav-link` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + + + + + + + +``` + +#### `should render with various attributes` + +``` + +
    + + +
    + + + + +
    + +``` + +## `cds-side-nav-menu` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + +
      + + +
    + +``` + +#### `should render with various attributes` + +``` + +
      + + +
    + +``` + +#### `should support collapsing side nav menu upon parent side nav is collapsed as rail` + +``` + +
      + + +
    + +``` + +## `cds-side-nav-menu-item` + +## `Misc attributes` + +#### `should render with minimum attributes` + +``` + + + + + + + +``` + +#### `should render with various attributes` + +``` + + + + + + + +``` diff --git a/packages/web-components/tests/spec/accordion_spec.ts b/packages/web-components/tests/spec/accordion_spec.ts new file mode 100644 index 000000000000..8c0a786d1dd6 --- /dev/null +++ b/packages/web-components/tests/spec/accordion_spec.ts @@ -0,0 +1,65 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render } from 'lit'; +import EventManager from '../utils/event-manager'; +import CDSAccordionItem from '../../src/components/accordion/accordion-item'; +import { Default } from '../../src/components/accordion/accordion-story'; + +const template = () => Default(); + +describe('cds-accordion', function () { + describe('Toggling', function () { + let item: CDSAccordionItem | null; + const events = new EventManager(); + + beforeEach(async function () { + render(template(), document.body); + await Promise.resolve(); + item = document.body.querySelector('cds-accordion-item'); + }); + + it('Should open and close the item', async function () { + item!.shadowRoot!.querySelector('button')!.click(); + await Promise.resolve(); + expect(item!.open).toBe(true); + + item!.shadowRoot!.querySelector('button')!.click(); + await Promise.resolve(); + expect(item!.open).toBe(false); + }); + + it('Should fire cds-accordion-item-beingtoggled/cds-accordion-item-toggled events upon opening', async function () { + const spyBeforeToggle = jasmine.createSpy('before toggle'); + const spyAfterToggle = jasmine.createSpy('after toggle'); + events.on(item!, 'cds-accordion-item-beingtoggled', spyBeforeToggle); + events.on(item!, 'cds-accordion-item-toggled', spyAfterToggle); + item!.shadowRoot!.querySelector('button')!.click(); + await Promise.resolve(); + expect(spyBeforeToggle).toHaveBeenCalled(); + expect(spyAfterToggle).toHaveBeenCalled(); + }); + + it('Should support preventing modal from being opened upon user gesture', async function () { + const spyAfterToggle = jasmine.createSpy('after toggle'); + events.on(item!, 'cds-accordion-item-beingtoggled', (event) => { + event.preventDefault(); + }); + events.on(item!, 'cds-accordion-item-toggled', spyAfterToggle); + item!.shadowRoot!.querySelector('button')!.click(); + await Promise.resolve(); + expect(spyAfterToggle).not.toHaveBeenCalled(); + }); + + afterEach(async function () { + await render(undefined!, document.body); + events.reset(); + }); + }); +}); diff --git a/packages/web-components/tests/spec/button_spec.ts b/packages/web-components/tests/spec/button_spec.ts new file mode 100644 index 000000000000..81237c4696b5 --- /dev/null +++ b/packages/web-components/tests/spec/button_spec.ts @@ -0,0 +1,170 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render } from 'lit'; +import { BUTTON_KIND } from '../../src/components/button/button'; +import { Default } from '../../src/components/button/button.stories'; + +const template = (props?) => + Default({ + 'cds-button': props, + }); + +describe('cds-button', function () { + describe('Changing button type', function () { + let elem: HTMLElement | null; + + beforeEach(async function () { + elem = document.body.appendChild(document.createElement('cds-button')); + await Promise.resolve(); + }); + + it('should choose the right template for default type', function () { + expect(elem!.shadowRoot!.querySelectorAll('button.cds--btn').length).toBe( + 1 + ); + }); + + it('should choose the right template for link type', async function () { + elem!.setAttribute('href', 'about:blank'); + await Promise.resolve(); + expect(elem!.shadowRoot!.querySelectorAll('a.cds--btn').length).toBe(1); + }); + + afterEach(function () { + if (elem && elem.parentNode) { + elem.parentNode.removeChild(elem); + elem = null; + } + }); + }); + + describe('Changing attributes', function () { + let elem: HTMLElement | null; + + beforeAll(function () { + elem = document.body.appendChild(document.createElement('cds-button')); + }); + + it('should deactivate when disabled attribute is set', async function () { + elem!.setAttribute('disabled', ''); + await Promise.resolve(); + expect( + elem!.shadowRoot!.querySelectorAll('.cds--btn--disabled').length + ).toBe(1); + }); + + it('should make it small when small attribute is set', async function () { + elem!.setAttribute('size', 'sm'); + await Promise.resolve(); + expect(elem!.shadowRoot!.querySelectorAll('.cds--btn--sm').length).toBe( + 1 + ); + }); + + it('should allow user to select button type', async function () { + elem!.setAttribute('kind', BUTTON_KIND.GHOST); + await Promise.resolve(); + expect( + elem!.shadowRoot!.querySelectorAll('.cds--btn--ghost').length + ).toBe(1); + }); + + afterAll(function () { + if (elem && elem.parentNode) { + elem.parentNode.removeChild(elem); + elem = null; + } + }); + }); + + describe('Misc attributes', function () { + it('should render with minimum attributes for '; + const input = elem!.querySelector('input'); + const button = elem!.querySelector('button'); + spyOn(input!, 'focus'); + spyOn(button!, 'focus'); + (elem as unknown as CDSModal).open = true; + await Promise.resolve(); // For triggering the update cycle of `` + await Promise.resolve(); // `update()` in `` waits for child nodes' update cycles to run + expect(input!.focus).not.toHaveBeenCalled(); + expect(button!.focus).toHaveBeenCalled(); + }); + + it('Should support using primary button in footer as the primary focus element', async function () { + spyOn(CDSModal as any, '_delay').and.callFake(() => {}); + elem!.innerHTML = + ''; + const input = elem!.querySelector('input'); + const button = elem!.querySelector('cds-button'); + spyOn(input!, 'focus'); + spyOn(button as HTMLButtonElement, 'focus'); + (elem as unknown as CDSModal).open = true; + await Promise.resolve(); // For triggering the update cycle of `` + await Promise.resolve(); // `update()` in `` waits for child nodes' update cycles to run + expect(input!.focus).not.toHaveBeenCalled(); + expect((button as HTMLButtonElement).focus).toHaveBeenCalled(); + }); + + it('Should have closing modal do nothing if already visible', async function () { + elem!.innerHTML = ''; + const spyBeforeClosed = jasmine.createSpy('before closed'); + events.on(elem!, 'cds-modal-beingclosed', spyBeforeClosed); + (elem!.querySelector('cds-modal-close-button') as HTMLElement).click(); + await Promise.resolve(); + expect(spyBeforeClosed).not.toHaveBeenCalled(); + }); + + it('Should fire cds-modal-beingclosed/cds-modal-closed events upon hiding', async function () { + elem!.innerHTML = ''; + (elem as CDSModal).open = true; + await Promise.resolve(); + const spyBeforeClosed = jasmine.createSpy('before closed'); + const spyAfterClosed = jasmine.createSpy('after closed'); + events.on(elem!, 'cds-modal-beingclosed', spyBeforeClosed); + events.on(elem!, 'cds-modal-closed', spyAfterClosed); + (elem!.querySelector('cds-modal-close-button') as HTMLElement).click(); + await Promise.resolve(); + expect(spyBeforeClosed).toHaveBeenCalled(); + expect(spyAfterClosed).toHaveBeenCalled(); + }); + + it('Should focus on the launcher button upon hiding', async function () { + elem = document.body.appendChild(document.createElement('div')); + const button = elem.appendChild(document.createElement('button')); + button.focus(); + spyOn(button, 'focus'); + const modal = elem.appendChild(document.createElement('cds-modal')); + await Promise.resolve(); // Wait for initial render + (modal as CDSModal).open = true; + await Promise.resolve(); + (modal as CDSModal).open = false; + await Promise.resolve(); + expect(button.focus).toHaveBeenCalled(); + }); + + it('Should support preventing modal from being closed upon user gesture', async function () { + elem!.innerHTML = ''; + (elem as CDSModal).open = true; + await Promise.resolve(); + const spyAfterClosed = jasmine.createSpy('after closed'); + events.on(elem!, 'cds-modal-beingclosed', (event) => { + event.preventDefault(); + }); + events.on(elem!, 'cds-modal-closed', spyAfterClosed); + (elem!.querySelector('cds-modal-close-button') as HTMLElement).click(); + await Promise.resolve(); + expect(spyAfterClosed).not.toHaveBeenCalled(); + }); + + afterEach(function () { + elem!.parentNode!.removeChild(elem!); + }); + }); + + describe('The various close actions', function () { + let elem: HTMLElement | null; + const events = new EventManager(); + + beforeEach(async function () { + elem = document.body.appendChild(document.createElement('cds-modal')); + await Promise.resolve(); // Wait for initial render + }); + + it('Should handle the ESC key to close the modal', async function () { + (elem as CDSModal).open = true; + await Promise.resolve(); + const spyBeforeClosed = jasmine.createSpy('before closed'); + const spyAfterClosed = jasmine.createSpy('after closed'); + events.on(elem!, 'cds-modal-beingclosed', spyBeforeClosed); + events.on(elem!, 'cds-modal-closed', spyAfterClosed); + elem!.ownerDocument!.body.dispatchEvent( + Object.assign(new CustomEvent('keydown', { bubbles: true }), { + key: 'Escape', + }) + ); + await Promise.resolve(); + expect((elem as CDSModal).open).toBeFalsy(); + expect(spyBeforeClosed).toHaveBeenCalled(); + expect(spyAfterClosed).toHaveBeenCalled(); + const eventDataBeforeClosed = spyBeforeClosed.calls.argsFor(0)[0].detail; + const eventDataAfterClosed = spyAfterClosed.calls.argsFor(0)[0].detail; + expect(eventDataBeforeClosed.triggeredBy).toBe(elem!.ownerDocument!.body); + expect(eventDataAfterClosed.triggeredBy).toBe(elem!.ownerDocument!.body); + }); + + it('Should handle the IE-specific ESC key to close the modal', async function () { + (elem as CDSModal).open = true; + await Promise.resolve(); + const spyBeforeClosed = jasmine.createSpy('before closed'); + const spyAfterClosed = jasmine.createSpy('after closed'); + events.on(elem!, 'cds-modal-beingclosed', spyBeforeClosed); + events.on(elem!, 'cds-modal-closed', spyAfterClosed); + elem!.ownerDocument!.body.dispatchEvent( + Object.assign(new CustomEvent('keydown', { bubbles: true }), { + key: 'Esc', + }) + ); + await Promise.resolve(); + expect((elem as CDSModal).open).toBeFalsy(); + expect(spyBeforeClosed).toHaveBeenCalled(); + expect(spyAfterClosed).toHaveBeenCalled(); + const eventDataBeforeClosed = spyBeforeClosed.calls.argsFor(0)[0].detail; + const eventDataAfterClosed = spyAfterClosed.calls.argsFor(0)[0].detail; + expect(eventDataBeforeClosed.triggeredBy).toBe(elem!.ownerDocument!.body); + expect(eventDataAfterClosed.triggeredBy).toBe(elem!.ownerDocument!.body); + }); + + it('Should handle any elements with data-modal-close attribute to close the modal', async function () { + elem!.innerHTML = ''; + (elem as CDSModal).open = true; + await Promise.resolve(); + const spyBeforeClosed = jasmine.createSpy('before closed'); + const spyAfterClosed = jasmine.createSpy('after closed'); + events.on(elem!, 'cds-modal-beingclosed', spyBeforeClosed); + events.on(elem!, 'cds-modal-closed', spyAfterClosed); + const closeButton = elem!.querySelector('button') as HTMLElement; + closeButton.click(); + await Promise.resolve(); + expect((elem as CDSModal).open).toBeFalsy(); + expect(spyBeforeClosed).toHaveBeenCalled(); + expect(spyAfterClosed).toHaveBeenCalled(); + const eventDataBeforeClosed = spyBeforeClosed.calls.argsFor(0)[0].detail; + const eventDataAfterClosed = spyAfterClosed.calls.argsFor(0)[0].detail; + expect(eventDataBeforeClosed.triggeredBy).toBe(closeButton); + expect(eventDataAfterClosed.triggeredBy).toBe(closeButton); + }); + + it('Should handle any click outside the modal element to close the modal', async function () { + (elem as CDSModal).open = true; + await Promise.resolve(); + const spyBeforeClosed = jasmine.createSpy('before closed'); + const spyAfterClosed = jasmine.createSpy('after closed'); + events.on(elem!, 'cds-modal-beingclosed', spyBeforeClosed); + events.on(elem!, 'cds-modal-closed', spyAfterClosed); + elem!.dispatchEvent(new CustomEvent('click', { bubbles: true })); + await Promise.resolve(); + expect((elem as CDSModal).open).toBeFalsy(); + expect(spyBeforeClosed).toHaveBeenCalled(); + expect(spyAfterClosed).toHaveBeenCalled(); + const eventDataBeforeHidden = spyBeforeClosed.calls.argsFor(0)[0].detail; + const eventDataAfterHidden = spyAfterClosed.calls.argsFor(0)[0].detail; + expect(eventDataBeforeHidden.triggeredBy).toBe(elem); + expect(eventDataAfterHidden.triggeredBy).toBe(elem); + }); + + afterEach(function () { + elem!.parentNode!.removeChild(elem!); + }); + }); + + describe('Wrapping focus while modal is open', function () { + let elem: HTMLElement | null; + let buttonBefore: HTMLButtonElement | null; + let buttonAfter: HTMLButtonElement | null; + + if (!document.hasFocus()) { + return; + } + + beforeEach(async function () { + elem = document.body.appendChild(document.createElement('cds-modal')); + elem!.innerHTML = ''; + buttonBefore = document.body.insertBefore( + document.createElement('button'), + document.body.firstChild + ); + buttonAfter = document.body.appendChild(document.createElement('button')); + await Promise.resolve(); // Wait for initial render + }); + + it('Should support forward focus-wrap', async function () { + spyOn(CDSModal as any, '_delay').and.callFake(() => {}); + (elem as CDSModal).open = true; + await Promise.resolve(); + buttonAfter!.focus(); + expect(document.activeElement).toBe(elem!.querySelectorAll('input')[0]); + }); + + it('Should support backward focus-wrap', async function () { + spyOn(CDSModal as any, '_delay').and.callFake(() => {}); + (elem as CDSModal).open = true; + await Promise.resolve(); + buttonBefore!.focus(); + expect(document.activeElement).toBe(elem!.querySelectorAll('input')[1]); + }); + + afterEach(function () { + elem!.parentNode!.removeChild(elem!); + }); + }); +}); diff --git a/packages/web-components/tests/spec/multi-select_spec.ts b/packages/web-components/tests/spec/multi-select_spec.ts new file mode 100644 index 000000000000..c26831c931f3 --- /dev/null +++ b/packages/web-components/tests/spec/multi-select_spec.ts @@ -0,0 +1,414 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render } from 'lit'; +import EventManager from '../utils/event-manager'; + +import CDSMultiSelect from '../../src/components/multi-select/multi-select'; +import CDSMultiSelectItem from '../../src/components/multi-select/multi-select-item'; +import { Playground } from '../../src/components/multi-select/multi-select-story'; + +const template = (props?) => + Playground({ + 'cds-multi-select': props, + }); + +describe('cds-multi-select', function () { + const events = new EventManager(); + + describe('Misc attributes', function () { + it('should render with minimum attributes', async function () { + render(template(), document.body); + await Promise.resolve(); + expect( + document.body.querySelector('cds-multi-select' as any) + ).toMatchSnapshot({ + mode: 'shadow', + }); + }); + + it('should render with various attributes', async function () { + render( + template({ + clearSelectionLabel: 'clear-selection-label-foo', + disabled: true, + invalid: true, + light: true, + helperText: 'helper-text-foo', + labelText: 'label-text-foo', + open: true, + toggleLabelClosed: 'toggle-label-closed-foo', + toggleLabelOpen: 'toggle-label-open-foo', + type: 'inline', + triggerContent: 'trigger-content-foo', + validityMessage: 'validity-message-foo', + value: 'staging', + }), + document.body + ); + await Promise.resolve(); + expect( + document.body.querySelector('cds-multi-select' as any) + ).toMatchSnapshot({ + mode: 'shadow', + }); + }); + }); + + describe('Toggling', function () { + let elem: Element; + let itemNode: Element; + + beforeEach(async function () { + render(template(), document.body); + await Promise.resolve(); + elem = document.body.querySelector('cds-multi-select')!; + itemNode = elem.querySelector('cds-multi-select-item')!; + }); + + it('should add "open" stateful modifier class', async function () { + const inner = elem.shadowRoot!.querySelector('div[role="listbox"]'); + (inner as HTMLElement).click(); + await Promise.resolve(); + expect(inner!.classList.contains('cds--list-box--expanded')).toBe(true); + }); + + it('should remove "open" stateful modifier class (closed default state)', async function () { + (elem as CDSMultiSelect).open = true; + await Promise.resolve(); + const inner = elem.shadowRoot!.querySelector('div[role="listbox"]'); + (inner as HTMLElement).click(); + await Promise.resolve(); + expect(inner!.classList.contains('cds--list-box--expanded')).toBe(false); + }); + + it('should always close multi-select when clicking document', async function () { + (elem as CDSMultiSelect).open = true; + await Promise.resolve(); + elem.dispatchEvent(new CustomEvent('focusout')); + await Promise.resolve(); + const inner = elem.shadowRoot!.querySelector('div[role="listbox"]'); + expect(inner!.classList.contains('cds--list-box--expanded')).toBe(false); + }); + + it('should keep multi-select open when clicking on an item', async function () { + (elem as CDSMultiSelect).open = true; + await Promise.resolve(); + (itemNode as HTMLElement).click(); + await Promise.resolve(); + const inner = elem.shadowRoot!.querySelector('div[role="listbox"]'); + expect(inner!.classList.contains('cds--list-box--expanded')).toBe(true); + }); + + it('should provide a way to cancel opening', async function () { + events.on(elem, 'cds-multi-select-beingtoggled', (event: CustomEvent) => { + event.preventDefault(); + }); + const inner = elem.shadowRoot!.querySelector('div[role="listbox"]'); + (inner as HTMLElement).click(); + await Promise.resolve(); + expect(inner!.classList.contains('cds--list-box--expanded')).toBe(false); + }); + + it('should provide a way to cancel closing', async function () { + (elem as CDSMultiSelect).open = true; + await Promise.resolve(); + events.on(elem, 'cds-multi-select-beingtoggled', (event: CustomEvent) => { + event.preventDefault(); + }); + const inner = elem.shadowRoot!.querySelector('div[role="listbox"]'); + (inner as HTMLElement).click(); + await Promise.resolve(); + expect(inner!.classList.contains('cds--list-box--expanded')).toBe(true); + }); + }); + + describe('Selecting items', function () { + let elem: Element; + let itemNodes: NodeListOf; + + beforeEach(async function () { + render(template({ open: true, value: 'all' }), document.body); + await Promise.resolve(); + elem = document.body.querySelector('cds-multi-select')!; + itemNodes = elem.querySelectorAll('cds-multi-select-item'); + }); + + xit('should add/remove "selected" modifier class', async function () { + ( + document.body.querySelector( + 'cds-multi-select-item[value="staging"]' + ) as HTMLElement + ).click(); + await Promise.resolve(); + expect(itemNodes[0].hasAttribute('selected')).toBe(true); + expect(itemNodes[1].hasAttribute('selected')).toBe(false); + expect(itemNodes[2].hasAttribute('selected')).toBe(true); + expect(itemNodes[3].hasAttribute('selected')).toBe(false); + expect(itemNodes[4].hasAttribute('selected')).toBe(false); + }); + + xit('should update selection count', async function () { + ( + document.body.querySelector( + 'cds-multi-select-item[value="staging"]' + ) as HTMLElement + ).click(); + await Promise.resolve(); + expect( + elem + .shadowRoot!.querySelector('.cds--list-box__selection--multi')! + .textContent!.trim() + ).toBe('2'); + ( + document.body.querySelector( + 'cds-multi-select-item[value="staging"]' + ) as HTMLElement + ).click(); + await Promise.resolve(); + ( + document.body.querySelector( + 'cds-multi-select-item[value="all"]' + ) as HTMLElement + ).click(); + await Promise.resolve(); + expect( + elem.shadowRoot!.querySelector('.cds--list-box__selection--multi') + ).toBeNull(); + }); + + xit('should update value', async function () { + ( + document.body.querySelector( + 'cds-multi-select-item[value="staging"]' + ) as HTMLElement + ).click(); + await Promise.resolve(); + expect((elem as CDSMultiSelect).value).toBe('all,staging'); + ( + document.body.querySelector( + 'cds-multi-select-item[value="staging"]' + ) as HTMLElement + ).click(); + await Promise.resolve(); + ( + document.body.querySelector( + 'cds-multi-select-item[value="all"]' + ) as HTMLElement + ).click(); + await Promise.resolve(); + expect((elem as CDSMultiSelect).value).toBe(''); + }); + + xit('should support selecting an item with space key', async function () { + const event = Object.assign( + new CustomEvent('keypress', { bubbles: true }), + { key: ' ' } + ); + ( + document.body.querySelector( + 'cds-multi-select-item[value="staging"]' + ) as CDSMultiSelectItem + ).highlighted = true; + await Promise.resolve(); + elem.shadowRoot!.querySelector('.cds--list-box')!.dispatchEvent(event); + await Promise.resolve(); + expect(itemNodes[0].hasAttribute('selected')).toBe(true); + expect(itemNodes[1].hasAttribute('selected')).toBe(false); + expect(itemNodes[2].hasAttribute('selected')).toBe(true); + expect(itemNodes[3].hasAttribute('selected')).toBe(false); + expect(itemNodes[4].hasAttribute('selected')).toBe(false); + }); + + xit('should support selecting an item with enter key', async function () { + const event = Object.assign( + new CustomEvent('keypress', { bubbles: true }), + { key: 'Enter' } + ); + ( + document.body.querySelector( + 'cds-multi-select-item[value="staging"]' + ) as CDSMultiSelectItem + ).highlighted = true; + await Promise.resolve(); + elem.shadowRoot!.querySelector('.cds--list-box')!.dispatchEvent(event); + await Promise.resolve(); + expect(itemNodes[0].hasAttribute('selected')).toBe(true); + expect(itemNodes[1].hasAttribute('selected')).toBe(false); + expect(itemNodes[2].hasAttribute('selected')).toBe(true); + expect(itemNodes[3].hasAttribute('selected')).toBe(false); + expect(itemNodes[4].hasAttribute('selected')).toBe(false); + }); + + xit('should provide a way to switch item with a value', async function () { + (elem as CDSMultiSelect).value = 'staging'; + await Promise.resolve(); // Update cycle for `` + await Promise.resolve(); // Update cycle for `` + expect(itemNodes[0].hasAttribute('selected')).toBe(false); + expect(itemNodes[1].hasAttribute('selected')).toBe(false); + expect(itemNodes[2].hasAttribute('selected')).toBe(true); + expect(itemNodes[3].hasAttribute('selected')).toBe(false); + expect(itemNodes[4].hasAttribute('selected')).toBe(false); + expect( + elem + .shadowRoot!.querySelector('.cds--list-box__selection--multi')! + .textContent!.trim() + ).toBe('1'); + }); + + xit('should provide a way to cancel switching item', async function () { + events.on( + elem, + 'cds-multi-select-beingselected', + (event: CustomEvent) => { + expect(event.detail.item).toBe( + document.body.querySelector( + 'cds-multi-select-item[value="staging"]' + ) + ); + event.preventDefault(); + } + ); + ( + document.body.querySelector( + 'cds-multi-select-item[value="staging"]' + ) as HTMLElement + ).click(); + await Promise.resolve(); + expect(itemNodes[0].hasAttribute('selected')).toBe(true); + expect(itemNodes[1].hasAttribute('selected')).toBe(false); + expect(itemNodes[2].hasAttribute('selected')).toBe(false); + expect(itemNodes[3].hasAttribute('selected')).toBe(false); + expect(itemNodes[4].hasAttribute('selected')).toBe(false); + expect((elem as CDSMultiSelect).value).toBe('all'); + }); + + it('should reflect the added child to the selection', async function () { + const itemNode = document.createElement('cds-multi-select-item'); + (itemNode as unknown as CDSMultiSelectItem).value = 'value-added'; + elem.appendChild(itemNode); + (elem as CDSMultiSelect).value = 'value-added'; + try { + expect((elem as CDSMultiSelect).value).toBe('value-added'); + } finally { + itemNode.parentNode!.removeChild(itemNode); + } + }); + }); + + describe('Clearing selection', function () { + let elem: Element; + let itemNodes: NodeListOf; + + beforeEach(async function () { + render(template({ open: true, value: 'all' }), document.body); + await Promise.resolve(); + elem = document.body.querySelector('cds-multi-select')!; + itemNodes = elem.querySelectorAll('cds-multi-select-item'); + }); + + xit('should support clicking X button for clearing selection', async function () { + elem + .shadowRoot!.querySelector('.cds--list-box__selection--multi svg')! + .dispatchEvent(new CustomEvent('click', { bubbles: true })); + await Promise.resolve(); + expect(itemNodes[0].hasAttribute('selected')).toBe(false); + expect(itemNodes[1].hasAttribute('selected')).toBe(false); + expect(itemNodes[2].hasAttribute('selected')).toBe(false); + expect(itemNodes[3].hasAttribute('selected')).toBe(false); + expect(itemNodes[4].hasAttribute('selected')).toBe(false); + await Promise.resolve(); + expect((elem as CDSMultiSelect).value).toBe(''); + expect( + elem.shadowRoot!.querySelector('.cds--list-box__selection--multi') + ).toBeNull(); + }); + + xit('should support space key on X button for clearing selection', async function () { + const trigger = elem.shadowRoot!.querySelector( + '.cds--list-box__field' + ) as HTMLElement; + spyOn(trigger!, 'focus'); + elem + .shadowRoot!.querySelector('.cds--list-box__selection--multi svg')! + .dispatchEvent( + Object.assign(new CustomEvent('keypress', { bubbles: true }), { + key: ' ', + }) + ); + await Promise.resolve(); + expect(itemNodes[0].hasAttribute('selected')).toBe(false); + expect(itemNodes[1].hasAttribute('selected')).toBe(false); + expect(itemNodes[2].hasAttribute('selected')).toBe(false); + expect(itemNodes[3].hasAttribute('selected')).toBe(false); + expect(itemNodes[4].hasAttribute('selected')).toBe(false); + expect((elem as CDSMultiSelect).value).toBe(''); + expect( + elem.shadowRoot!.querySelector('.cds--list-box__selection--multi') + ).toBeNull(); + expect(trigger!.focus).toHaveBeenCalledTimes(1); + }); + + xit('should support enter key on X button for clearing selection', async function () { + const trigger = elem.shadowRoot!.querySelector( + '.cds--list-box__field' + ) as HTMLElement; + spyOn(trigger!, 'focus'); + elem + .shadowRoot!.querySelector('.cds--list-box__selection--multi svg')! + .dispatchEvent( + Object.assign(new CustomEvent('keypress', { bubbles: true }), { + key: 'Enter', + }) + ); + await Promise.resolve(); + expect(itemNodes[0].hasAttribute('selected')).toBe(false); + expect(itemNodes[1].hasAttribute('selected')).toBe(false); + expect(itemNodes[2].hasAttribute('selected')).toBe(false); + expect(itemNodes[3].hasAttribute('selected')).toBe(false); + expect(itemNodes[4].hasAttribute('selected')).toBe(false); + expect((elem as CDSMultiSelect).value).toBe(''); + expect( + elem.shadowRoot!.querySelector('.cds--list-box__selection--multi') + ).toBeNull(); + expect(trigger!.focus).toHaveBeenCalledTimes(1); + }); + }); + + describe('Keyboard navigation', function () { + let elem: Element; + + beforeEach(async function () { + render(template({ open: true, value: 'all' }), document.body); + await Promise.resolve(); + elem = document.body.querySelector('cds-multi-select')!; + }); + + xit('should support arrow key to move focus out of the close button', async function () { + const trigger = elem.shadowRoot!.querySelector( + '.cds--list-box__field' + ) as HTMLElement; + spyOn(trigger!, 'focus'); + elem + .shadowRoot!.querySelector('.cds--list-box__selection--multi')! + .dispatchEvent( + Object.assign(new CustomEvent('keydown', { bubbles: true }), { + key: 'ArrowDown', + }) + ); + await Promise.resolve(); + expect(trigger!.focus).toHaveBeenCalledTimes(1); + }); + }); + + afterEach(async function () { + events.reset(); + await render(undefined!, document.body); + }); +}); diff --git a/packages/web-components/tests/spec/notification_spec.ts b/packages/web-components/tests/spec/notification_spec.ts new file mode 100644 index 000000000000..90a0b4a1bb87 --- /dev/null +++ b/packages/web-components/tests/spec/notification_spec.ts @@ -0,0 +1,105 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render } from 'lit'; +import CDSInlineNotification, { + NOTIFICATION_KIND, +} from '../../src/components/notification/inline-notification'; +import { Playground } from '../../src/components/notification/inline-notification-story'; + +const inlineTemplate = (props?) => + Playground({ + 'cds-inline-notification': props, + }); + +describe('cds-inline-notification', function () { + describe('Rendering titles', function () { + it('Should render with minimum attributes', async function () { + render(inlineTemplate(), document.body); + await Promise.resolve(); + expect( + document.body.querySelector('cds-inline-notification' as any) + ).toMatchSnapshot({ mode: 'shadow' }); + }); + + it('Should render with various attributes', async function () { + render( + inlineTemplate({ + closeButtonLabel: 'close-button-label-foo', + hideCloseButton: true, + iconLabel: 'icon-label-foo', + kind: NOTIFICATION_KIND.INFO, + open: false, + subtitle: 'subtitle-foo', + title: 'title-foo', + }), + document.body + ); + await Promise.resolve(); + expect( + document.body.querySelector('cds-inline-notification' as any) + ).toMatchSnapshot({ mode: 'shadow' }); + }); + }); + + describe('Closing', function () { + let notification: CDSInlineNotification | null; + + beforeEach(async function () { + render(inlineTemplate(), document.body); + await Promise.resolve(); + notification = document.body.querySelector('cds-inline-notification'); + }); + + it('Should support closing', async function () { + expect(notification!.open).toBe(true); + notification!.shadowRoot!.querySelector('button')!.click(); + await Promise.resolve(); + expect(notification!.open).toBe(false); + }); + }); + + describe('Timeout', function () { + const timeout = 100; + + let notification; + + beforeEach(async function () { + const initializeTimerCloseEvent = (CDSInlineNotification.prototype as any) + ._handleUserOrTimerInitiatedClose; + spyOn( + CDSInlineNotification.prototype as any, + '_initializeTimeout' + ).and.callFake(function () { + // TODO: See if we can get around TS2683 + // @ts-ignore + initializeTimerCloseEvent.call(this); + }); + render( + inlineTemplate({ + timeout, + open: false, + }), + document.body + ); + await Promise.resolve(); + notification = document.body.querySelector('cds-inline-notification'); + }); + + it('Should support closing after the timeout', async function () { + notification.open = true; + await Promise.resolve(); + expect(notification!.open).toBe(false); + }); + }); + + afterEach(async function () { + await render(undefined!, document.body); + }); +}); diff --git a/packages/web-components/tests/spec/number-input_spec.ts b/packages/web-components/tests/spec/number-input_spec.ts new file mode 100644 index 000000000000..ebe4e3d19ee4 --- /dev/null +++ b/packages/web-components/tests/spec/number-input_spec.ts @@ -0,0 +1,296 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html, render } from 'lit'; +import EventManager from '../utils/event-manager'; + +import CDSNumberInput from '../../src/components/number-input/number-input'; +import { Playground } from '../../src/components/number-input/number-input-story'; + +/** + * @param formData A `FormData` instance. + * @returns The given `formData` converted to a classic key-value pair. + */ +const getValues = (formData: FormData) => { + const values = {}; + // eslint-disable-next-line no-restricted-syntax + for (const [key, value] of formData.entries()) { + values[key] = value; + } + return values; +}; + +const template = (props?) => + Playground({ + 'cds-number-input': props, + }); + +describe('cds-number-input', function () { + const events = new EventManager(); + + describe('Rendering', function () { + it('Should render with various attributes', async function () { + render( + template({ + autocomplete: 'on', + autofocus: true, + disabled: true, + helperText: 'helper-text-foo', + labelText: 'label-text-foo', + name: 'name-foo', + pattern: 'pattern-foo', + placeholder: 'placeholder-foo', + readonly: true, + required: true, + validityMessage: 'validity-message-foo', + value: '50', + step: '1', + max: '200', + min: '-100', + }), + document.body + ); + await Promise.resolve(); + expect( + document.body.querySelector('cds-number-input' as any) + ).toMatchSnapshot({ + mode: 'shadow', + }); + }); + }); + + // most of this describe is borrowed from the input tests + describe('Event-based form participation', function () { + xit('Should respond to `formdata` event', async function () { + render( + html` +
    + ${template({ + name: 'name-foo', + value: '50', + })} +
    + `, + document.body + ); + await Promise.resolve(); + const formData = new FormData(); + const event = new CustomEvent('formdata', { + bubbles: true, + cancelable: false, + composed: false, + }); + (event as any).formData = formData; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const form = document.querySelector('form'); + form!.dispatchEvent(event); + expect(getValues(formData)).toEqual({ 'name-foo': '50' }); + }); + + it('Should not respond to `formdata` event if disabled', async function () { + render( + html` +
    + ${template({ + disabled: true, + name: 'name-foo', + value: '50', + })} +
    + `, + document.body + ); + await Promise.resolve(); + const formData = new FormData(); + const event = new CustomEvent('formdata', { + bubbles: true, + cancelable: false, + composed: false, + }); + (event as any).formData = formData; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const form = document.querySelector('form'); + form!.dispatchEvent(event); + expect(getValues(formData)).toEqual({}); + }); + }); + + // most of this describe is borrowed from the input tests + describe('Form validation', function () { + let elem: Element; + + beforeEach(async function () { + render(template(), document.body); + await Promise.resolve(); + elem = document.body.querySelector('cds-number-input')!; + }); + + // This test is skipped for now since there seems to be a bug somewhere in the test stack. + // Running the same code manually in a browser works as expected. + // Given that the rest of the test suit passes it seems reasonable that it's an issue + // with this specific test case + // eslint-disable-next-line + xit('should support checking if required value exists', async function () { + const input = elem as CDSNumberInput; + input.value = null as any; + input.required = true; + const spyInvalid = jasmine.createSpy('invalid'); + events.on(input, 'invalid', spyInvalid); + expect(input.checkValidity()).toBe(false); + expect(spyInvalid).toHaveBeenCalled(); + expect(input.invalid).toBe(true); + expect(input.validityMessage).toBe('Please fill out this field.'); + input.value = '50'; + await Promise.resolve(); + expect(input.checkValidity()).toBe(true); + expect(input.invalid).toBe(false); + expect(input.validityMessage).toBe(''); + }); + + it('should support canceling required check', async function () { + const input = elem as CDSNumberInput; + input.required = true; + events.on(input, 'invalid', (event) => { + event.preventDefault(); + }); + expect(input.checkValidity()).toBe(false); + expect(input.invalid).toBe(false); + expect(input.validityMessage).toBe(''); + }); + + it('should treat empty custom validity message as not invalid', async function () { + const input = elem as CDSNumberInput; + input.setCustomValidity(''); + expect(input.invalid).toBe(false); + expect(input.validityMessage).toBe(''); + }); + + it('should treat non-empty custom validity message as invalid', async function () { + const input = elem as CDSNumberInput; + input.setCustomValidity('validity-message-foo'); + expect(input.invalid).toBe(true); + expect(input.validityMessage).toBe('validity-message-foo'); + }); + + xit('should warn if a value less than the min', async function () { + const input = elem as CDSNumberInput; + input.min = '50'; + input.value = '0'; + await Promise.resolve(); + expect(input.checkValidity()).toBe(false); + }); + + xit('should warn if a value is greater than the max', async function () { + const input = elem as CDSNumberInput; + input.max = '50'; + input.value = '51'; + await Promise.resolve(); + expect(input.checkValidity()).toBe(false); + }); + }); + + describe('Number input specific functionality', function () { + let elem: Element; + + beforeEach(async function () { + render(template(), document.body); + await Promise.resolve(); + elem = document.body.querySelector('cds-number-input')!; + }); + + it('should increment values', async function () { + const input = elem as CDSNumberInput; + const initialValue = Number(input.value); + const stepSize = Number(input.step); + input.stepUp(); + expect(Number(input.value)).toEqual(initialValue + stepSize); + }); + + it('should decrement values', async function () { + const input = elem as CDSNumberInput; + const initialValue = Number(input.value); + const stepSize = Number(input.step); + input.stepDown(); + expect(Number(input.value)).toEqual(initialValue - stepSize); + }); + + it('should increment values upon user gesture', async function () { + const input = elem as CDSNumberInput; + const initialValue = Number(input.value); + const stepSize = Number(input.step); + const spyInput = jasmine.createSpy('input'); + events.on(elem, 'cds-number-input', spyInput); + (elem.shadowRoot!.querySelector('button.up-icon') as HTMLElement).click(); + expect(Number(input.value)).toEqual(initialValue + stepSize); + expect(Number(spyInput.calls.argsFor(0)[0].detail.value)).toBe( + initialValue + stepSize + ); + }); + + it('should decrement values upon user gesture', async function () { + const input = elem as CDSNumberInput; + const initialValue = Number(input.value); + const stepSize = Number(input.step); + const spyInput = jasmine.createSpy('input'); + events.on(elem, 'cds-number-input', spyInput); + ( + elem.shadowRoot!.querySelector('button.down-icon') as HTMLElement + ).click(); + expect(Number(input.value)).toEqual(initialValue - stepSize); + expect(Number(spyInput.calls.argsFor(0)[0].detail.value)).toBe( + initialValue - stepSize + ); + }); + + it('should increment values by the step amount', async function () { + const input = elem as CDSNumberInput; + const initialValue = Number(input.value); + input.step = '50'; + await Promise.resolve(); // wait for the value to apply + const stepSize = Number(input.step); + input.stepUp(); + await Promise.resolve(); // wait for the value to apply + expect(Number(input.value)).toEqual(initialValue + stepSize); + }); + + it('should decrement values by the step amount', async function () { + const input = elem as CDSNumberInput; + const initialValue = Number(input.value); + input.step = '50'; + await Promise.resolve(); // wait for the value to apply + const stepSize = Number(input.step); + input.stepDown(); + await Promise.resolve(); // wait for the value to apply + expect(Number(input.value)).toEqual(initialValue - stepSize); + }); + + it('should not step past the max value', async function () { + const input = elem as CDSNumberInput; + input.max = '50'; + input.value = '50'; + await Promise.resolve(); + input.stepUp(); + await Promise.resolve(); + expect(Number(input.value)).toEqual(50); + }); + + it('should not step below the min value', async function () { + const input = elem as CDSNumberInput; + input.min = '50'; + input.value = '50'; + await Promise.resolve(); + input.stepDown(); + await Promise.resolve(); + expect(Number(input.value)).toEqual(50); + }); + }); + + afterEach(async function () { + events.reset(); + await render(undefined!, document.body); + }); +}); diff --git a/packages/web-components/tests/spec/overflow-menu_spec.ts b/packages/web-components/tests/spec/overflow-menu_spec.ts new file mode 100644 index 000000000000..0f20d42e7264 --- /dev/null +++ b/packages/web-components/tests/spec/overflow-menu_spec.ts @@ -0,0 +1,151 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render } from 'lit'; + +import CDSOverflowMenu from '../../src/components/overflow-menu/overflow-menu'; +import { Playground } from '../../src/components/overflow-menu/overflow-menu.stories'; + +const template = (props?) => + Playground({ + 'cds-overflow-menu': props, + }); + +describe('cds-overflow-menu', function () { + describe('Missing menu body', function () { + let elem: Element; + + beforeEach(async function () { + render(template({ hasBody: false }), document.body); + await Promise.resolve(); + document.querySelector('cds-overflow-menu')!.innerHTML = ''; + elem = document.body.querySelector('cds-overflow-menu')!; + }); + + it('Should be tolerant of missing menu body', async function () { + (elem as HTMLElement).click(); + await Promise.resolve(); + expect((elem as CDSOverflowMenu).open).toBe(true); + + (elem as HTMLElement).click(); + await Promise.resolve(); + expect((elem as CDSOverflowMenu).open).toBe(false); + }); + + afterEach(function () { + render(template({ hasContent: false }), document.body); + }); + }); + + xdescribe('Toggling', function () { + let elem: Element; + let bodyNode: Element; + + beforeEach(async function () { + render(template(), document.body); + await Promise.resolve(); + elem = document.body.querySelector('cds-overflow-menu')!; + bodyNode = elem.querySelector('cds-overflow-menu-body')!; + }); + + it('should add "open" stateful property by clicking', async function () { + (elem as HTMLElement).click(); + await Promise.resolve(); + expect((elem as CDSOverflowMenu).open).toBe(true); + }); + + it('should remove "open" stateful property (closed default state) by clicking', async function () { + (elem as CDSOverflowMenu).open = true; + await Promise.resolve(); + (elem as HTMLElement).click(); + await Promise.resolve(); + expect((elem as CDSOverflowMenu).open).toBe(false); + }); + + xit('should focus on the menu body when the menu is opened by clicking on the trigger button', async function () { + spyOn(bodyNode as HTMLElement, 'focus'); + (elem as HTMLElement).click(); + await Promise.resolve(); // For updating `` + await Promise.resolve(); // For updating `` + expect((bodyNode as HTMLElement).focus).toHaveBeenCalled(); + }); + + it('should add "open" stateful property by space key', async function () { + elem.dispatchEvent( + Object.assign(new CustomEvent('keydown', { bubbles: true }), { + key: ' ', + }) + ); + await Promise.resolve(); + expect((elem as CDSOverflowMenu).open).toBe(true); + }); + + it('should remove "open" stateful property (closed default state) by space key', async function () { + (elem as CDSOverflowMenu).open = true; + await Promise.resolve(); + elem.dispatchEvent( + Object.assign(new CustomEvent('keydown', { bubbles: true }), { + key: 'Enter', + }) + ); + await Promise.resolve(); + expect((elem as CDSOverflowMenu).open).toBe(false); + }); + + xit('should focus on the menu body when the menu is opened by space key on the trigger button', async function () { + spyOn(bodyNode as HTMLElement, 'focus'); + elem.dispatchEvent( + Object.assign(new CustomEvent('keydown', { bubbles: true }), { + key: ' ', + }) + ); + await Promise.resolve(); // For updating `` + await Promise.resolve(); // For updating `` + expect((bodyNode as HTMLElement).focus).toHaveBeenCalled(); + }); + + it('should add "open" stateful property by enter key', async function () { + elem.dispatchEvent( + Object.assign(new CustomEvent('keydown', { bubbles: true }), { + key: 'Enter', + }) + ); + await Promise.resolve(); + expect((elem as CDSOverflowMenu).open).toBe(true); + }); + + it('should remove "open" stateful property (closed default state) by enter key', async function () { + (elem as CDSOverflowMenu).open = true; + await Promise.resolve(); + elem.dispatchEvent( + Object.assign(new CustomEvent('keydown', { bubbles: true }), { + key: 'Enter', + }) + ); + await Promise.resolve(); + expect((elem as CDSOverflowMenu).open).toBe(false); + }); + + xit('should focus on the menu body when the menu is opened by enter key on the trigger button', async function () { + spyOn(bodyNode as HTMLElement, 'focus'); + elem.dispatchEvent( + Object.assign(new CustomEvent('keydown', { bubbles: true }), { + key: 'Enter', + }) + ); + await Promise.resolve(); // For updating `` + await Promise.resolve(); // For updating `` + expect((bodyNode as HTMLElement).focus).toHaveBeenCalled(); + }); + }); + + afterEach(async function () { + await render(undefined!, document.body); + }); +}); diff --git a/packages/web-components/tests/spec/pagination_spec.ts b/packages/web-components/tests/spec/pagination_spec.ts new file mode 100644 index 000000000000..a0a822361dc1 --- /dev/null +++ b/packages/web-components/tests/spec/pagination_spec.ts @@ -0,0 +1,413 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render } from 'lit'; +import EventManager from '../utils/event-manager'; +import CDSPagination from '../../src/components/pagination/pagination'; +import { Playground } from '../../src/components/pagination/pagination-story'; +import CDSSelect from '../../src/components/select/select'; + +const template = (props?) => + Playground({ + 'cds-pagination': props, + }); + +xdescribe('cds-pagination', function () { + const events = new EventManager(); + + describe('Misc attributes', function () { + it('should render with minimum attributes', async function () { + render(template(), document.body); + await Promise.resolve(); + expect( + document.body.querySelector('cds-pagination' as any) + ).toMatchSnapshot({ + mode: 'shadow', + }); + }); + + it('should render with various attributes', async function () { + render( + template({ + pageSize: 20, + start: 10, + totalItems: 200, + }), + document.body + ); + await Promise.resolve(); + expect( + document.body.querySelector('cds-pagination' as any) + ).toMatchSnapshot({ + mode: 'shadow', + }); + }); + + it('should render with minimum attributes', async function () { + render(template(), document.body); + await Promise.resolve(); // Update cycle for `` + await Promise.resolve(); // Update cycle for `` + expect( + document.body.querySelector('cds-page-sizes-select' as any) + ).toMatchSnapshot({ mode: 'shadow' }); + }); + + it('should render with minimum attributes', async function () { + render(template({ totalItems: 100 }), document.body); + await Promise.resolve(); // Update cycle for `` + await Promise.resolve(); // Update cycle for `` + expect( + document.body.querySelector('cds-pages-select' as any) + ).toMatchSnapshot({ + mode: 'shadow', + }); + }); + }); + + describe('Rendering status text', function () { + it('should handle plural for total row count', async function () { + render( + template({ + pageSize: 1, + start: 0, + totalItems: 1, + }), + document.body + ); + await Promise.resolve(); + const textContentNode = document.body + .querySelector('cds-pagination')! + .shadowRoot!.querySelector('.cds--pagination__text'); + expect(textContentNode!.textContent!.trim()).toBe('1–1 of 1 item'); + }); + + it('should render page range without total rows for infinite row count', async function () { + render( + template({ + pageSize: 20, + start: 10, + totalItems: null, + }), + document.body + ); + await Promise.resolve(); + const textContentNode = document.body + .querySelector('cds-pagination')! + .shadowRoot!.querySelector('.cds--pagination__text'); + expect(textContentNode!.textContent!.trim()).toBe('Item 11–30'); + }); + + it('should render only the start at the last page for infinite row count', async function () { + render( + template({ + atLastPage: true, + pageSize: 20, + start: 30, + totalItems: null, + }), + document.body + ); + await Promise.resolve(); + const textContentNode = document.body + .querySelector('cds-pagination')! + .shadowRoot!.querySelector('.cds--pagination__text'); + expect(textContentNode!.textContent!.trim()).toBe('Item 31–'); + }); + }); + + describe('Propagating changes', function () { + it('should propagate `pageSize` property to ``', async function () { + render(template(), document.body); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + paginationNode.pageSize = 20; + await Promise.resolve(); + const pageSizesSelectNode = paginationNode.shadowRoot?.querySelector( + 'cds-select' + ) as CDSSelect; + expect(pageSizesSelectNode.value).toBe('20'); + }); + + it('should propagate the current page to ``', async function () { + render(template({ totalItems: 100 }), document.body); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + paginationNode.pageSize = 5; + paginationNode.start = 21; + await Promise.resolve(); + const pagesSelectNode = paginationNode.shadowRoot?.querySelector( + '#pages-select' + ) as CDSSelect; + expect(pagesSelectNode.value).toBe('4'); + }); + + it('should propagate the total pages to ``', async function () { + render(template({ totalItems: 100 }), document.body); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + paginationNode.pageSize = 5; + paginationNode.totalItems = 21; + await Promise.resolve(); + expect(paginationNode.totalItems).toBe(5); + }); + + it('should handle change in page size at non-first page', async function () { + // This test case hits the following issue if we don't apply the workaround: + // https://github.com/Polymer/lit-html/issues/1052 + render( + template({ + pageSize: 10, + start: 190, + totalItems: 200, + }), + document.body + ); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + paginationNode.pageSize = 5; + await Promise.resolve(); // Update in `` + await Promise.resolve(); // Update in `` + const pagesSelectNode = paginationNode.shadowRoot?.querySelector( + '#pages-select' + ) as CDSSelect; + expect(pagesSelectNode.shadowRoot!.querySelector('select')!.value).toBe( + '38' + ); + }); + }); + + describe('Handling user gestures', function () { + it('should support prev button', async function () { + let newStart; + render( + template({ + pageSize: 10, + start: 20, + }), + document.body + ); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + events.on( + paginationNode, + 'cds-pagination-changed-current', + (event: CustomEvent) => { + newStart = event.detail.start; + } + ); + paginationNode.shadowRoot!.querySelectorAll('button')[0].click(); + expect(paginationNode.start).toBe(10); + expect(newStart).toBe(10); + }); + + it('should ensure the start position will not be negative by hitting prev button', async function () { + let newStart; + render( + template({ + pageSize: 10, + start: 5, + }), + document.body + ); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + events.on( + paginationNode, + 'cds-pagination-changed-current', + (event: CustomEvent) => { + newStart = event.detail.start; + } + ); + paginationNode.shadowRoot!.querySelectorAll('button')[0].click(); + expect(paginationNode.start).toBe(0); + expect(newStart).toBe(0); + }); + + it('should ensure prev button will not be in effect at the first page even if it is not disabled', async function () { + render( + template({ + pageSize: 10, + start: 0, + }), + document.body + ); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + const spyChanged = jasmine.createSpy('changed'); + events.on(paginationNode, 'cds-pagination-changed-current', spyChanged); + // Prev button should be disabled when `start` indicates that we are at the first page, + // but we ensure nothing happens even if the button is enabled + paginationNode.shadowRoot!.querySelectorAll('button')[0].disabled = false; + paginationNode.shadowRoot!.querySelectorAll('button')[0].click(); + expect(paginationNode.start).toBe(0); + expect(spyChanged).not.toHaveBeenCalled(); + }); + + it('should support next button', async function () { + let newStart; + render( + template({ + pageSize: 10, + start: 20, + }), + document.body + ); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + events.on( + paginationNode, + 'cds-pagination-changed-current', + (event: CustomEvent) => { + newStart = event.detail.start; + } + ); + paginationNode.shadowRoot!.querySelectorAll('button')[1].click(); + expect(paginationNode.start).toBe(30); + expect(newStart).toBe(30); + }); + + it('should ensure the start position will not exceed the total size by hitting next button', async function () { + render( + template({ + pageSize: 10, + start: 20, + totalItems: 30, + }), + document.body + ); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + const spyChanged = jasmine.createSpy('changed'); + events.on(paginationNode, 'cds-pagination-changed-current', spyChanged); + // Next button should be disabled when `start` indicates that we are at the last page, + // but we ensure nothing happens even if the button is enabled + paginationNode.shadowRoot!.querySelectorAll('button')[1].disabled = false; + paginationNode.shadowRoot!.querySelectorAll('button')[1].click(); + expect(paginationNode.start).toBe(20); + expect(spyChanged).not.toHaveBeenCalled(); + }); + + it('should support next button at the last page', async function () { + render( + template({ + pageSize: 10, + start: 25, + totalItems: 30, + }), + document.body + ); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + const spyChanged = jasmine.createSpy('changed'); + events.on(paginationNode, 'cds-pagination-changed-current', spyChanged); + // Next button should be disabled when `start` indicates that we are at the last page, + // but we ensure nothing happens even if the button is enabled + paginationNode.shadowRoot!.querySelectorAll('button')[1].disabled = false; + paginationNode.shadowRoot!.querySelectorAll('button')[1].click(); + expect(paginationNode.start).toBe(25); + expect(spyChanged).not.toHaveBeenCalled(); + }); + + it('should support next button for infinite row count', async function () { + let newStart; + render( + template({ + pageSize: 10, + start: 25, + totalItems: null, + }), + document.body + ); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + events.on( + paginationNode, + 'cds-pagination-changed-current', + (event: CustomEvent) => { + newStart = event.detail.start; + } + ); + paginationNode.shadowRoot!.querySelectorAll('button')[1].click(); + expect(paginationNode.start).toBe(35); + expect(newStart).toBe(35); + }); + + it('should support user-initiated change in page size', async function () { + render(template({ totalItems: 100 }), document.body); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + const pagesSelectNode = paginationNode.shadowRoot?.querySelector( + '#pages-select' + ) as CDSSelect; + pagesSelectNode.dispatchEvent( + new CustomEvent('cds-select-selected', { + bubbles: true, + detail: { value: 5 }, + }) + ); + expect(paginationNode.pageSize).toBe(5); + }); + + it('should support user-initiated change in current page', async function () { + let newStart; + render(template({ pageSize: 10, totalItems: 100 }), document.body); + await Promise.resolve(); + const paginationNode = document.body.querySelector( + 'cds-pagination' + ) as CDSPagination; + events.on( + paginationNode, + 'cds-pagination-changed-current', + (event: CustomEvent) => { + newStart = event.detail.start; + } + ); + const pagesSelectNode = paginationNode.shadowRoot?.querySelector( + '#pages-select' + ) as CDSSelect; + pagesSelectNode.dispatchEvent( + new CustomEvent('cds-select-selected', { + bubbles: true, + detail: { value: 3 }, + }) + ); + expect(paginationNode.start).toBe(30); + expect(newStart).toBe(30); + }); + }); + + afterEach(async function () { + await render(undefined!, document.body); + events.reset(); + }); +}); diff --git a/packages/web-components/tests/spec/progress-bar_spec.ts b/packages/web-components/tests/spec/progress-bar_spec.ts new file mode 100644 index 000000000000..21a78c2e2c20 --- /dev/null +++ b/packages/web-components/tests/spec/progress-bar_spec.ts @@ -0,0 +1,49 @@ +/** + * @license + * + * Copyright IBM Corp. 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render } from 'lit'; +import { Playground } from '../../src/components/progress-bar/progress-bar-story'; + +const template = (props?) => + Playground({ + 'cds-progress-bar': props, + }); + +describe('cds-progress-bar', function () { + describe('Rendering', function () { + it('Should render with minimum attributes', async function () { + render(template(), document.body); + await Promise.resolve(); + expect( + document.body.querySelector('cds-progress-bar' as any) + ).toMatchSnapshot({ + mode: 'shadow', + }); + }); + + it('Should render with various attributes', async function () { + render( + template({ + label: 'Progress Bar label', + helperText: 'Optional helper text', + value: 50, + }), + document.body + ); + await Promise.resolve(); + expect( + document.body.querySelector('cds-progress-bar[value="50"]' as any) + ).toMatchSnapshot({ mode: 'shadow' }); + }); + + afterEach(async function () { + await render(undefined!, document.body); + }); + }); +}); diff --git a/packages/web-components/tests/spec/progress-indicator_spec.ts b/packages/web-components/tests/spec/progress-indicator_spec.ts new file mode 100644 index 000000000000..4c891f97ffdb --- /dev/null +++ b/packages/web-components/tests/spec/progress-indicator_spec.ts @@ -0,0 +1,54 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render } from 'lit'; +import { PROGRESS_STEP_STAT } from '../../src/components/progress-indicator/progress-step'; +import { Playground } from '../../src/components/progress-indicator/progress-indicator-story'; + +const template = (props?) => + Playground({ + 'cds-progress-step': props, + }); + +describe('cds-progress-step', function () { + describe('Rendering', function () { + it('Should render with minimum attributes', async function () { + render(template(), document.body); + await Promise.resolve(); + expect( + document.body.querySelector('cds-progress-step' as any) + ).toMatchSnapshot({ + mode: 'shadow', + }); + }); + + it('Should render with various attributes', async function () { + render( + template({ + disabled: true, + iconLabel: 'icon-label-foo', + labelText: 'label-text-foo', + secondaryLabelText: 'secondary-label-text-foo', + state: PROGRESS_STEP_STAT.COMPLETE, + }), + document.body + ); + await Promise.resolve(); + expect( + document.body.querySelector( + 'cds-progress-step[state="complete"]' as any + ) + ).toMatchSnapshot({ mode: 'shadow' }); + }); + + afterEach(async function () { + await render(undefined!, document.body); + }); + }); +}); diff --git a/packages/web-components/tests/spec/radio-button_spec.ts b/packages/web-components/tests/spec/radio-button_spec.ts new file mode 100644 index 000000000000..dbc91702a5cc --- /dev/null +++ b/packages/web-components/tests/spec/radio-button_spec.ts @@ -0,0 +1,447 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html, render } from 'lit'; +import CDSRadioButtonGroup, { + RADIO_BUTTON_ORIENTATION, +} from '../../src/components/radio-button/radio-button-group'; +import { RADIO_BUTTON_LABEL_POSITION } from '../../src/components/radio-button/radio-button'; +import { Playground } from '../../src/components/radio-button/radio-button-story'; + +/** + * @param formData A `FormData` instance. + * @returns The given `formData` converted to a classic key-value pair. + */ +const getValues = (formData: FormData) => { + const values = {}; + // eslint-disable-next-line no-restricted-syntax + for (const [key, value] of formData.entries()) { + values[key] = value; + } + return values; +}; + +const template = (props?) => + Playground({ + 'cds-radio-button-group': props, + }); + +xdescribe('cds-radio-button', function () { + describe('Rendering', function () { + it('Should render with minimum attributes', async function () { + render(template(), document.body); + await Promise.resolve(); + expect( + document.body.querySelector('cds-radio-button[value="staging"]' as any) + ).toMatchSnapshot({ mode: 'shadow' }); + }); + + it('Should render with various attributes', async function () { + render( + template({ + 'cds-radio-button-group': { + disabled: true, + labelPosition: RADIO_BUTTON_LABEL_POSITION.LEFT, + name: 'name-foo', + orientation: RADIO_BUTTON_ORIENTATION.VERTICAL, + value: 'staging', + }, + 'cds-radio-button': { + hideLabel: true, + labelText: 'label-text-foo', + }, + }), + document.body + ); + await Promise.resolve(); + expect( + document.body.querySelector('cds-radio-button[value="staging"]' as any) + ).toMatchSnapshot({ mode: 'shadow' }); + }); + }); + + describe('Communication between and ', function () { + it('Should propagate disabled', async function () { + render( + template({ 'cds-radio-button-group': { disabled: true } }), + document.body + ); + await Promise.resolve(); + expect( + Array.prototype.every.call( + document.body.querySelectorAll('cds-radio-button'), + (radio) => radio.disabled + ) + ).toBe(true); + }); + + it('Should propagate labelPosition', async function () { + render( + template({ + 'cds-radio-button-group': { + labelPosition: RADIO_BUTTON_LABEL_POSITION.LEFT, + }, + }), + document.body + ); + await Promise.resolve(); + expect( + Array.prototype.every.call( + document.body.querySelectorAll('cds-radio-button'), + (radio) => radio.labelPosition === RADIO_BUTTON_LABEL_POSITION.LEFT + ) + ).toBe(true); + }); + + it('Should propagate orientation', async function () { + render( + template({ + 'cds-radio-button-group': { + orientation: RADIO_BUTTON_ORIENTATION.VERTICAL, + }, + }), + document.body + ); + await Promise.resolve(); + expect( + Array.prototype.every.call( + document.body.querySelectorAll('cds-radio-button'), + (radio) => radio.orientation === RADIO_BUTTON_ORIENTATION.VERTICAL + ) + ).toBe(true); + }); + + it('Should propagate name', async function () { + render( + template({ + 'cds-radio-button-group': { name: 'name-foo' }, + }), + document.body + ); + await Promise.resolve(); + expect( + Array.prototype.every.call( + document.body.querySelectorAll('cds-radio-button'), + (radio) => radio.name === 'name-foo' + ) + ).toBe(true); + }); + + it('Should select that matches the given value', async function () { + render( + template({ + 'cds-radio-button-group': { value: 'staging' }, + }), + document.body + ); + await Promise.resolve(); + expect( + Array.prototype.map.call( + document.body.querySelectorAll('cds-radio-button'), + (radio) => radio.checked + ) + ).toEqual([false, false, true]); + }); + + it('Should update the value upon clicking ', async function () { + render( + template({ + 'cds-radio-button-group': { name: 'name-foo' }, + }), + document.body + ); + await Promise.resolve(); + ( + document.body.querySelector( + 'cds-radio-button[value="staging"]' + ) as HTMLElement + ).click(); + expect( + ( + document.body.querySelector( + 'cds-radio-button-group' + ) as CDSRadioButtonGroup + ).value + ).toBe('staging'); + }); + + it('Should update the value upon space key on ', async function () { + render( + template({ + 'cds-radio-button-group': { name: 'name-foo' }, + }), + document.body + ); + await Promise.resolve(); + const event = new CustomEvent('keydown', { + bubbles: true, + composed: true, + }); + const radioBaz = document.body.querySelector( + 'cds-radio-button[value="staging"]' + ); + (radioBaz as HTMLElement).dispatchEvent( + Object.assign(event, { key: ' ' }) + ); + expect( + ( + document.body.querySelector( + 'cds-radio-button-group' + ) as CDSRadioButtonGroup + ).value + ).toBe('staging'); + }); + + it('Should update the value upon enter key on ', async function () { + render( + template({ + 'cds-radio-button-group': { name: 'name-foo' }, + }), + document.body + ); + await Promise.resolve(); + const event = new CustomEvent('keydown', { + bubbles: true, + composed: true, + }); + const radioBaz = document.body.querySelector( + 'cds-radio-button[value="staging"]' + ); + (radioBaz as HTMLElement).dispatchEvent( + Object.assign(event, { key: 'Enter' }) + ); + expect( + ( + document.body.querySelector( + 'cds-radio-button-group' + ) as CDSRadioButtonGroup + ).value + ).toBe('staging'); + }); + }); + + describe('Keyboard navigation', function () { + it('Should use left/right key for navigation in horizontal mode', async function () { + render( + template({ + 'cds-radio-button-group': { + orientation: RADIO_BUTTON_ORIENTATION.HORIZONTAL, + name: 'name-foo', + }, + }), + document.body + ); + await Promise.resolve(); + const radioFoo = document.body.querySelector( + 'cds-radio-button[value="all"]' + ) as HTMLElement; + radioFoo.focus(); + const event = new CustomEvent('keydown', { + bubbles: true, + composed: true, + }); + radioFoo.dispatchEvent(Object.assign(event, { key: 'ArrowRight' })); + expect( + ( + document.body.querySelector( + 'cds-radio-button-group' + ) as CDSRadioButtonGroup + ).value + ).toBe('cloudFoundry'); + expect( + Array.prototype.map.call( + document.body.querySelectorAll('cds-radio-button'), + (radio) => radio.shadowRoot.querySelector('input').tabIndex + ) + ).toEqual([-1, 0, -1]); + const radioBar = document.body.querySelector( + 'cds-radio-button[value="cloudFoundry"]' + ) as HTMLElement; + radioBar.dispatchEvent(Object.assign(event, { key: 'ArrowLeft' })); + expect( + ( + document.body.querySelector( + 'cds-radio-button-group' + ) as CDSRadioButtonGroup + ).value + ).toBe('all'); + expect( + Array.prototype.map.call( + document.body.querySelectorAll('cds-radio-button'), + (radio) => radio.shadowRoot.querySelector('input').tabIndex + ) + ).toEqual([0, -1, -1]); + }); + + it('Should use up/down key for navigation in vertical mode', async function () { + render( + template({ + 'cds-radio-button-group': { + orientation: RADIO_BUTTON_ORIENTATION.VERTICAL, + name: 'name-foo', + }, + }), + document.body + ); + await Promise.resolve(); + const radioFoo = document.body.querySelector( + 'cds-radio-button[value="all"]' + ) as HTMLElement; + radioFoo.focus(); + const event = new CustomEvent('keydown', { + bubbles: true, + composed: true, + }); + radioFoo.dispatchEvent(Object.assign(event, { key: 'ArrowDown' })); + expect( + ( + document.body.querySelector( + 'cds-radio-button-group' + ) as CDSRadioButtonGroup + ).value + ).toBe('cloudFoundry'); + expect( + Array.prototype.map.call( + document.body.querySelectorAll('cds-radio-button'), + (radio) => radio.shadowRoot.querySelector('input').tabIndex + ) + ).toEqual([-1, 0, -1]); + const radioBar = document.body.querySelector( + 'cds-radio-button[value="cloudFoundry"]' + ) as HTMLElement; + radioBar.dispatchEvent(Object.assign(event, { key: 'ArrowUp' })); + expect( + ( + document.body.querySelector( + 'cds-radio-button-group' + ) as CDSRadioButtonGroup + ).value + ).toBe('all'); + expect( + Array.prototype.map.call( + document.body.querySelectorAll('cds-radio-button'), + (radio) => radio.shadowRoot.querySelector('input').tabIndex + ) + ).toEqual([0, -1, -1]); + }); + }); + + describe('Event-based form participation', function () { + it('Should respond to `formdata` event', async function () { + render( + html` +
    + ${template({ + 'cds-radio-button-group': { + name: 'name-foo', + value: 'staging', + }, + })} +
    + `, + document.body + ); + await Promise.resolve(); + const formData = new FormData(); + const event = new CustomEvent('formdata', { + bubbles: true, + cancelable: false, + composed: false, + }); + (event as any).formData = formData; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const form = document.querySelector('form'); + form!.dispatchEvent(event); + expect(getValues(formData)).toEqual({ 'name-foo': 'staging' }); + }); + + it('Should not respond to `formdata` event if form item name is not specified', async function () { + render( + html` +
    + ${template({ + 'cds-radio-button-group': { + value: 'staging', + }, + })} +
    + `, + document.body + ); + await Promise.resolve(); + const formData = new FormData(); + const event = new CustomEvent('formdata', { + bubbles: true, + cancelable: false, + composed: false, + }); + (event as any).formData = formData; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const form = document.querySelector('form'); + form!.dispatchEvent(event); + expect(getValues(formData)).toEqual({}); + }); + + it('Should not respond to `formdata` event if no item is selected', async function () { + render( + html` +
    + ${template({ + 'cds-radio-button-group': { + name: 'name-foo', + }, + })} +
    + `, + document.body + ); + await Promise.resolve(); + const formData = new FormData(); + const event = new CustomEvent('formdata', { + bubbles: true, + cancelable: false, + composed: false, + }); + (event as any).formData = formData; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const form = document.querySelector('form'); + form!.dispatchEvent(event); + expect(getValues(formData)).toEqual({}); + }); + + it('Should not respond to `formdata` event if disabled', async function () { + render( + html` +
    + ${template({ + 'cds-radio-button-group': { + disabled: true, + name: 'name-foo', + }, + })} +
    + `, + document.body + ); + await Promise.resolve(); + const formData = new FormData(); + const event = new CustomEvent('formdata', { + bubbles: true, + cancelable: false, + composed: false, + }); + (event as any).formData = formData; // TODO: Wait for `FormDataEvent` being available in `lib.dom.d.ts` + const form = document.querySelector('form'); + form!.dispatchEvent(event); + expect(getValues(formData)).toEqual({}); + }); + }); + + afterEach(async function () { + render(undefined!, document.body); + await Promise.resolve(); + }); +}); diff --git a/packages/web-components/tests/spec/search_spec.ts b/packages/web-components/tests/spec/search_spec.ts new file mode 100644 index 000000000000..5686b44c7a51 --- /dev/null +++ b/packages/web-components/tests/spec/search_spec.ts @@ -0,0 +1,106 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render } from 'lit'; +import EventManager from '../utils/event-manager'; +import { INPUT_SIZE } from '../../src/components/text-input/text-input'; +import CDSSearch from '../../src/components/search/search'; +import { Playground } from '../../src/components/search/search-story'; + +const template = (props?) => + Playground({ + 'cds-search': props, + }); + +describe('cds-search', function () { + const events = new EventManager(); + + describe('Misc attributes', function () { + it('should render with minimum attributes', async function () { + render(template(), document.body); + await Promise.resolve(); + expect(document.body.querySelector('cds-search' as any)).toMatchSnapshot({ + mode: 'shadow', + }); + }); + + it('should render with various attributes', async function () { + render( + template({ + closeButtonAssistiveText: 'close-button-assistive-text-foo', + disabled: true, + labelText: 'label-text-foo', + name: 'name-foo', + placeholder: 'placeholder-foo', + size: INPUT_SIZE.EXTRA_LARGE, + type: 'submit', + value: 'value-foo', + }), + document.body + ); + await Promise.resolve(); + expect(document.body.querySelector('cds-search' as any)).toMatchSnapshot({ + mode: 'shadow', + }); + }); + }); + + describe('Typing in the search box', function () { + it('should reflect the value', async function () { + render(template({ value: 'value-foo' }), document.body); + await Promise.resolve(); + const search = document.body.querySelector('cds-search'); + const inputNode = search!.shadowRoot!.querySelector('input'); + inputNode!.value = 'value-bar'; + inputNode!.dispatchEvent(new CustomEvent('input', { bubbles: true })); + expect((search as CDSSearch).value).toBe('value-bar'); + }); + + it('Should fire cds-search-input event upon typing', async function () { + render(template({ value: 'value-foo' }), document.body); + await Promise.resolve(); + const search = document.body.querySelector('cds-search'); + const spyBeforeClear = jasmine.createSpy('before clear'); + events.on(search!, 'cds-search-input', spyBeforeClear); + const inputNode = search!.shadowRoot!.querySelector('input'); + inputNode!.value = 'value-bar'; + inputNode!.dispatchEvent(new CustomEvent('input', { bubbles: true })); + await Promise.resolve(); + expect(spyBeforeClear).toHaveBeenCalled(); + expect(spyBeforeClear.calls.argsFor(0)[0].detail.value).toBe('value-bar'); + }); + }); + + describe('Clearing the input', function () { + it('should clear the value', async function () { + render(template({ value: 'value-foo' }), document.body); + await Promise.resolve(); + const search = document.body.querySelector('cds-search'); + search!.shadowRoot!.querySelector('button')!.click(); + expect((search as CDSSearch).value).toBe(''); + }); + + it('Should fire cds-search-input event upon clearing', async function () { + render(template({ value: 'value-foo' }), document.body); + await Promise.resolve(); + const search = document.body.querySelector('cds-search'); + const spyBeforeClear = jasmine.createSpy('before clear'); + events.on(search!, 'cds-search-input', spyBeforeClear); + search!.shadowRoot!.querySelector('button')!.click(); + await Promise.resolve(); + expect(spyBeforeClear).toHaveBeenCalled(); + expect(spyBeforeClear.calls.argsFor(0)[0].detail.value).toBe(''); + }); + }); + + afterEach(async function () { + await render(undefined!, document.body); + events.reset(); + }); +}); diff --git a/packages/web-components/tests/spec/select_spec.ts b/packages/web-components/tests/spec/select_spec.ts new file mode 100644 index 000000000000..3447ba4ccbca --- /dev/null +++ b/packages/web-components/tests/spec/select_spec.ts @@ -0,0 +1,370 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2024 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html, render } from 'lit'; +import EventManager from '../utils/event-manager'; +import { INPUT_SIZE } from '../../src/components/text-input/text-input'; +import CDSSelect from '../../src/components/select/select'; +import CDSSelectItem from '../../src/components/select/select-item'; +import CDSSelectItemGroup from '../../src/components/select/select-item-group'; +import { Playground } from '../../src/components/select/select-story'; + +/** + * @param formData A `FormData` instance. + * @returns The given `formData` converted to a classic key-value pair. + */ +const getValues = (formData: FormData) => { + const values = {}; + // eslint-disable-next-line no-restricted-syntax + for (const [key, value] of formData.entries()) { + values[key] = value; + } + return values; +}; + +const template = (props?) => + Playground({ + 'cds-select': props, + }); + +xdescribe('cds-select', function () { + const events = new EventManager(); + + describe('Misc attributes', function () { + it('should render with minimum attributes', async function () { + render(template(), document.body); + await Promise.resolve(); + expect(document.body.querySelector('cds-select' as any)).toMatchSnapshot({ + mode: 'shadow', + }); + }); + + it('should render with various attributes', async function () { + render( + template({ + autofocus: true, + disabled: true, + helperText: 'helper-text-foo', + labelText: 'label-text-foo', + name: 'name-foo', + placeholder: 'placeholder-foo', + size: INPUT_SIZE.EXTRA_LARGE, + value: 'staging', + }), + document.body + ); + await Promise.resolve(); + expect(document.body.querySelector('cds-select' as any)).toMatchSnapshot({ + mode: 'shadow', + }); + }); + + it('should render invalid state', async function () { + render( + template({ + helperText: 'helper-text-foo', // `invalidText` should take precedence + invalid: true, + invalidText: 'validity-message-foo', + }), + document.body + ); + await Promise.resolve(); + expect(document.body.querySelector('cds-select' as any)).toMatchSnapshot({ + mode: 'shadow', + }); + }); + }); + + describe('Changing child ``s + const option = elem!.shadowRoot!.querySelector( + 'optgroup[label="label-foo"]' + ) as HTMLOptGroupElement; + expect(option.disabled).toBe(true); + expect(option.label).toBe('label-foo'); + }); + + it('should support changing a property of an option group', async function () { + render(template(), document.body); + await Promise.resolve(); + const itemGroup = document.body.querySelector( + 'cds-select-item-group[label="Category 2"]' + ); + (itemGroup as CDSSelectItemGroup).disabled = true; + await Promise.resolve(); // Let `MutationObserver` run + await Promise.resolve(); // Update cycle of rendering new child ``s + const elem = document.body.querySelector('cds-select'); + const option = elem!.shadowRoot!.querySelector( + 'optgroup[label="Category 2"]' + ) as HTMLOptGroupElement; + expect(option.disabled).toBe(true); + }); + + it('should support removing an option group', async function () { + render(template(), document.body); + await Promise.resolve(); + const itemGroup = document.body.querySelector( + 'cds-select-item-group[label="Category 2"]' + ); + itemGroup!.parentNode!.removeChild(itemGroup!); + await Promise.resolve(); // Let `MutationObserver` run + await Promise.resolve(); // Update cycle of rendering new child ``s + const elem = document.body.querySelector('cds-select'); + expect( + elem!.shadowRoot!.querySelector('optgroup[label="Category 2"]') + ).toBeNull(); + }); + }); + + describe('Properties', function () { + it('should support querying the `