diff --git a/.bazelignore b/.bazelignore deleted file mode 100644 index 71df476de1d1..000000000000 --- a/.bazelignore +++ /dev/null @@ -1,34 +0,0 @@ -dist -node_modules - -docs/node_modules - -integration/harness-e2e-cli/.angular -integration/harness-e2e-cli/node_modules -integration/ng-update-v13/.angular -integration/ng-update-v13/node_modules -integration/ng-add/.angular -integration/ng-add/node_modules -integration/ng-add-standalone/.angular -integration/ng-add-standalone/node_modules -integration/yarn-pnp-compat/.angular -integration/yarn-pnp-compat/.yarn/cache -integration/yarn-pnp-compat/.yarn/unplugged -integration/yarn-pnp-compat/.yarn/install-state.gz -integration/yarn-pnp-compat/node_modules -integration/node_modules - -src/aria/node_modules -src/cdk-experimental/node_modules -src/cdk/node_modules -src/components-examples/node_modules -src/dev-app/node_modules -src/e2e-app/node_modules -src/google-maps/node_modules -src/material-date-fns-adapter/node_modules -src/material-experimental/node_modules -src/material-luxon-adapter/node_modules -src/material-moment-adapter/node_modules -src/material/node_modules -src/universal-app/node_modules -src/youtube-player/node_modules diff --git a/.bazelrc b/.bazelrc index 43276f982a31..4e5992ce6d0b 100644 --- a/.bazelrc +++ b/.bazelrc @@ -63,11 +63,7 @@ build:release --stamp build:snapshot-build --workspace_status_command="pnpm -s ng-dev:stamp --mode=snapshot" build:snapshot-build --stamp - -################################## -# Always enable Ivy compilation # -################################## -build --define=angular_ivy_enabled=True +build:snapshot-build --//:enable_snapshot_adev_assets ################################ # Remote Execution Setup # diff --git a/.bazelversion b/.bazelversion index e81e85b81044..e7fdef7e2e63 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -7.6.2 +8.4.2 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index ae11ddfd8e48..000000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,14 +0,0 @@ -* @angular/components-googlers - -/.circleci/ @angular/dev-infra-components -/.husky/ @angular/dev-infra-components -/.ng-dev/ @angular/dev-infra-components -/.vscode/ @angular/dev-infra-components -/scripts/ @angular/dev-infra-components -/test/ @angular/dev-infra-components - -/.github/ @angular/dev-infra-components -/.github/CODEOWNERS @angular/dev-infra-components @andrewseguin @jelbourn -/.github/ISSUE_TEMPLATE/** @angular/components-googlers - -/tools/ @angular/dev-infra-components diff --git a/.github/workflows/assistant-to-the-branch-manager.yml b/.github/workflows/assistant-to-the-branch-manager.yml index 7fc107f4320e..a23d524eecbf 100644 --- a/.github/workflows/assistant-to-the-branch-manager.yml +++ b/.github/workflows/assistant-to-the-branch-manager.yml @@ -13,9 +13,9 @@ jobs: assistant_to_the_branch_manager: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false - - uses: angular/dev-infra/github-actions/branch-manager@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: angular/dev-infra/github-actions/branch-manager@dd5658bd720370542913e23b21d80450bac94b60 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/ci.material-aio.yml b/.github/workflows/ci.material-aio.yml index dddf12c0ee2f..7b95c3edbf64 100644 --- a/.github/workflows/ci.material-aio.yml +++ b/.github/workflows/ci.material-aio.yml @@ -21,11 +21,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Execute Build @@ -35,11 +35,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Execute Tests @@ -56,11 +56,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Execute Lighthouse Audit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5843558fd0b..830272aea5cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,19 +21,21 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile + # TODO: Remove --ignore_all_rc_files flag once a repository can be loaded in bazelrc during info + # commands again. See https://github.com/bazelbuild/bazel/issues/25145 for more context. - name: Checking package externals run: | bazel build //:package_externals - pnpm check-package-externals $(bazel info bazel-bin)/package_externals.json + pnpm check-package-externals $(bazel --ignore_all_rc_files info bazel-bin)/package_externals.json - name: Checking entry-points configuration run: | bazel build //:entry_points_manifest - pnpm check-entry-point-setup $(bazel info bazel-bin)/entry_points_manifest.json - - name: Check OWNERS file - run: pnpm ownerslint + pnpm check-entry-point-setup $(bazel --ignore_all_rc_files info bazel-bin)/entry_points_manifest.json + - name: Validate pull approve configuration + run: pnpm ng-dev pullapprove verify - name: Check for component id collisions run: pnpm detect-component-id-collisions - name: Check style lint @@ -47,11 +49,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -63,11 +65,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -79,11 +81,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -96,11 +98,11 @@ jobs: runs-on: ubuntu-latest-16core steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -112,11 +114,11 @@ jobs: runs-on: ubuntu-latest-16core steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Install node modules @@ -128,15 +130,15 @@ jobs: runs-on: ubuntu-latest-4core steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - - name: Build and Verify Release Output - run: pnpm build-and-check-release-output + - name: Build Snapshots + run: pnpm build-snapshots - name: Verify tooling setup run: pnpm check-tooling-setup - name: Build Docs Content @@ -152,15 +154,15 @@ jobs: runs-on: ubuntu-latest-4core steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 # See: https://github.com/puppeteer/puppeteer/pull/13196 and # https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md. - name: Disable AppArmor run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Build and Verify Release Output @@ -183,12 +185,12 @@ jobs: CI_RUNNER_NUMBER: ${{ github.run_id }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Browserstack Variables - uses: angular/dev-infra/github-actions/browserstack@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/browserstack@dd5658bd720370542913e23b21d80450bac94b60 - name: Run tests on Browserstack run: ./scripts/circleci/run-browserstack-tests.sh diff --git a/.github/workflows/deploy-dev-app-main-push.yml b/.github/workflows/deploy-dev-app-main-push.yml index 6937d12b6fd5..8dc0daa48815 100644 --- a/.github/workflows/deploy-dev-app-main-push.yml +++ b/.github/workflows/deploy-dev-app-main-push.yml @@ -17,11 +17,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile diff --git a/.github/workflows/dev-infra.yml b/.github/workflows/dev-infra.yml index edae341d2c88..bc2cc0810af3 100644 --- a/.github/workflows/dev-infra.yml +++ b/.github/workflows/dev-infra.yml @@ -11,14 +11,14 @@ jobs: labels: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/pull-request-labeling@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: angular/dev-infra/github-actions/pull-request-labeling@dd5658bd720370542913e23b21d80450bac94b60 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} post_approval_changes: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/post-approval-changes@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: angular/dev-infra/github-actions/post-approval-changes@dd5658bd720370542913e23b21d80450bac94b60 with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.github/workflows/docs-preview-build.yml b/.github/workflows/docs-preview-build.yml index 6b9694c48947..f6ee479afa0b 100644 --- a/.github/workflows/docs-preview-build.yml +++ b/.github/workflows/docs-preview-build.yml @@ -21,16 +21,16 @@ jobs: (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'docs: preview')) steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Build docs site run: pnpm bazel build //docs:build.production - - uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@dd5658bd720370542913e23b21d80450bac94b60 with: workflow-artifact-name: 'docs-preview' pull-number: '${{github.event.pull_request.number}}' diff --git a/.github/workflows/docs-preview-deploy.yml b/.github/workflows/docs-preview-deploy.yml index 7c44157d7999..c879b7e5dd9c 100644 --- a/.github/workflows/docs-preview-deploy.yml +++ b/.github/workflows/docs-preview-deploy.yml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: token: '${{secrets.GITHUB_TOKEN}}' @@ -40,7 +40,7 @@ jobs: npx -y firebase-tools@latest target:clear --config docs/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting mat-aio npx -y firebase-tools@latest target:apply --config docs/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting mat-aio ${{env.PREVIEW_SITE}} - - uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@dd5658bd720370542913e23b21d80450bac94b60 with: github-token: '${{secrets.GITHUB_TOKEN}}' workflow-artifact-name: 'docs-preview' diff --git a/.github/workflows/google-internal-tests.yml b/.github/workflows/google-internal-tests.yml index fdb85ad6234c..903da827a844 100644 --- a/.github/workflows/google-internal-tests.yml +++ b/.github/workflows/google-internal-tests.yml @@ -12,8 +12,8 @@ jobs: trigger: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: angular/dev-infra/github-actions/google-internal-tests@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: angular/dev-infra/github-actions/google-internal-tests@dd5658bd720370542913e23b21d80450bac94b60 with: run-tests-guide-url: http://go/angular-material-presubmit github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr.material-aio.yml b/.github/workflows/pr.material-aio.yml index 17f473e21370..c1ba80ddc51f 100644 --- a/.github/workflows/pr.material-aio.yml +++ b/.github/workflows/pr.material-aio.yml @@ -19,11 +19,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Execute Build @@ -33,11 +33,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Execute Tests @@ -54,11 +54,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Execute Lighthouse Audit diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 94be2853a713..473b6494302e 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -19,19 +19,21 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile + # TODO: Remove --ignore_all_rc_files flag once a repository can be loaded in bazelrc during info + # commands again. See https://github.com/bazelbuild/bazel/issues/25145 for more context. - name: Checking package externals run: | bazel build //:package_externals - pnpm check-package-externals $(bazel info bazel-bin)/package_externals.json + pnpm check-package-externals $(bazel --ignore_all_rc_files info bazel-bin)/package_externals.json - name: Checking entry-points configuration run: | bazel build //:entry_points_manifest - pnpm check-entry-point-setup $(bazel info bazel-bin)/entry_points_manifest.json - - name: Check OWNERS file - run: pnpm ownerslint + pnpm check-entry-point-setup $(bazel --ignore_all_rc_files info bazel-bin)/entry_points_manifest.json + - name: Validate pull approve configuration + run: pnpm ng-dev pullapprove verify - name: Check for component id collisions run: pnpm detect-component-id-collisions - name: Check style lint @@ -43,7 +45,7 @@ jobs: - name: Check code format run: pnpm ng-dev format changed --check ${{ github.event.pull_request.base.sha }} - name: Check Package Licenses - uses: angular/dev-infra/github-actions/linting/licenses@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/linting/licenses@dd5658bd720370542913e23b21d80450bac94b60 # Commit message check is last intentionally, because the caretaker can fix it # during merge, while other lint failures have to be resolved by the PR author. - name: Check commit message @@ -53,11 +55,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Check API Goldens @@ -67,11 +69,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Run e2e tests @@ -81,11 +83,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Run integration tests @@ -95,11 +97,11 @@ jobs: runs-on: ubuntu-latest-16core steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Run tests @@ -109,11 +111,11 @@ jobs: runs-on: ubuntu-latest-16core steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Run tests @@ -123,11 +125,11 @@ jobs: runs-on: ubuntu-latest-4core steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 - name: Install node modules run: pnpm install --frozen-lockfile - name: Build and Verify Release Output @@ -150,15 +152,15 @@ jobs: CI_RUNNER_NUMBER: ${{ github.run_id }} steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 with: # Checking out the pull request commit is intended here as we need to run the changed code tests. ref: ${{ github.event.pull_request.head.sha }} - name: Install node modules run: pnpm install --frozen-lockfile - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Browserstack Variables - uses: angular/dev-infra/github-actions/browserstack@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/browserstack@dd5658bd720370542913e23b21d80450bac94b60 - name: Run tests on Browserstack run: ./scripts/circleci/run-browserstack-tests.sh diff --git a/.github/workflows/preview-build-dev-app.yml b/.github/workflows/preview-build-dev-app.yml index fdb29ea489a7..fdaa11c782c9 100644 --- a/.github/workflows/preview-build-dev-app.yml +++ b/.github/workflows/preview-build-dev-app.yml @@ -23,16 +23,16 @@ jobs: (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'dev-app preview')) steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 # Build the web package - run: bazel build //src/dev-app:web_package --symlink_prefix=dist/ - - uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@dd5658bd720370542913e23b21d80450bac94b60 with: workflow-artifact-name: 'dev-app' pull-number: '${{github.event.pull_request.number}}' diff --git a/.github/workflows/preview-deploy-dev-app.yml b/.github/workflows/preview-deploy-dev-app.yml index ec7426d82272..e4bfb5a65404 100644 --- a/.github/workflows/preview-deploy-dev-app.yml +++ b/.github/workflows/preview-deploy-dev-app.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Configure Firebase deploy target run: | @@ -33,7 +33,7 @@ jobs: npx -y firebase-tools@latest target:clear --project ${{env.PREVIEW_PROJECT}} hosting dev-app npx -y firebase-tools@latest target:apply --project ${{env.PREVIEW_PROJECT}} hosting dev-app ${{env.PREVIEW_SITE}} - - uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@c584c3565b71c7a8cda81d55bb14e3e66ef934da + - uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@dd5658bd720370542913e23b21d80450bac94b60 with: github-token: '${{secrets.GITHUB_TOKEN}}' workflow-artifact-name: 'dev-app' diff --git a/.github/workflows/scheduled-ci.yml b/.github/workflows/scheduled-ci.yml index 39843b6c1888..be6f3d20bae4 100644 --- a/.github/workflows/scheduled-ci.yml +++ b/.github/workflows/scheduled-ci.yml @@ -19,11 +19,11 @@ jobs: runs-on: ubuntu-latest-4core steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Setting up Angular snapshot builds @@ -39,11 +39,11 @@ jobs: runs-on: ubuntu-latest-4core steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel - uses: angular/dev-infra/github-actions/bazel/setup@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/setup@dd5658bd720370542913e23b21d80450bac94b60 - name: Setup Bazel RBE - uses: angular/dev-infra/github-actions/bazel/configure-remote@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/bazel/configure-remote@dd5658bd720370542913e23b21d80450bac94b60 with: google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }} - name: Setting up Angular snapshot builds @@ -61,7 +61,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Initialize environment - uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c584c3565b71c7a8cda81d55bb14e3e66ef934da + uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@dd5658bd720370542913e23b21d80450bac94b60 # See: https://github.com/puppeteer/puppeteer/pull/13196 and # https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md. - name: Disable AppArmor diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index b5189ed3b724..29fffaf77ae2 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -25,7 +25,7 @@ jobs: steps: - name: 'Checkout code' - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false @@ -47,6 +47,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@16140ae1a102900babc80a33c44059580f687047 # v4.30.9 + uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 with: sarif_file: results.sarif diff --git a/.ng-dev/commit-message.mts b/.ng-dev/commit-message.mts index 6fe1a9f509eb..c868f0e0b1d4 100644 --- a/.ng-dev/commit-message.mts +++ b/.ng-dev/commit-message.mts @@ -14,11 +14,9 @@ export const commitMessage: CommitMessageConfig = { 'aria/grid', 'aria/listbox', 'aria/menu', - 'aria/radio-group', 'aria/tabs', 'aria/toolbar', 'aria/tree', - 'aria/ui-patterns', 'cdk-experimental/column-resize', 'cdk-experimental/popover-edit', 'cdk-experimental/scrolling', diff --git a/.ng-dev/format.mts b/.ng-dev/format.mts index 0e182edbe38f..0bdad7235d37 100644 --- a/.ng-dev/format.mts +++ b/.ng-dev/format.mts @@ -6,7 +6,5 @@ import {FormatConfig} from '@angular/ng-dev'; */ export const format: FormatConfig = { buildifier: true, - prettier: { - matchers: ['**/*.{js,ts,mts,mjs,json}'], - }, + prettier: true, }; diff --git a/.ng-dev/github.mts b/.ng-dev/github.mts index 382a66b0de32..e8d7aeb223ad 100644 --- a/.ng-dev/github.mts +++ b/.ng-dev/github.mts @@ -8,5 +8,5 @@ export const github: GithubConfig = { owner: 'angular', name: 'components', mainBranchName: 'main', - useNgDevAuthService: true, + mergeMode: 'team-only', }; diff --git a/.ng-dev/google-sync-config.json b/.ng-dev/google-sync-config.json index c8fdea37cb24..a35504343075 100644 --- a/.ng-dev/google-sync-config.json +++ b/.ng-dev/google-sync-config.json @@ -28,6 +28,7 @@ "src/**/*spec.ts", "src/cdk/schematics/**/*", "src/cdk/testing/private/**/*", + "src/cdk/private/inner-html.ts", "src/material/schematics/**/*", "src/material/schematics/ng-generate/theme-color/**/*.bazel", "src/material/schematics/ng-generate/theme-color/index_bundled.d.ts", diff --git a/.nvmrc b/.nvmrc index aa50a62f2194..5767036af0e2 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22.21.0 +22.21.1 diff --git a/.prettierignore b/.prettierignore index 7021d3c7a734..f1c8888a1df3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -13,3 +13,7 @@ src/material/schematics/ng-update/test-cases/**/*_input.ts src/material/schematics/ng-update/test-cases/**/*_expected_output.ts pnpm-lock.yaml + + +# TODO: Enable formatting on markdown files +**/*.md diff --git a/.pullapprove.yml b/.pullapprove.yml new file mode 100644 index 000000000000..4412922eade7 --- /dev/null +++ b/.pullapprove.yml @@ -0,0 +1,107 @@ +version: 3 + +# Add users here if they're temporarily unavailable. +#availability: +# users_unavailable: [] + +# Meta field that goes unused by PullApprove to allow for defining aliases to be +# used throughout the config. +meta: + no-groups-above-this-active: &no-groups-above-this-active len(groups.active.exclude("components-team")) == 0 + + defaults: &defaults + reviews: + # Authors provide their approval implicitly, this approval allows for a reviewer + # from a group not to need a review specifically for an area of the repository + # they own. This is coupled with the `required-minimum-review` group which requires + # that all PRs are reviewed by at least one team member who is not the author of + # the PR. + author_value: 1 + +# turn on 'draft' support +# https://docs.pullapprove.com/config/github-api-version/ +# https://developer.github.com/v3/previews/#draft-pull-requests +github_api_version: 'shadow-cat-preview' + +# https://docs.pullapprove.com/config/overrides/ +# Note that overrides are processed in order. +overrides: + # For PRs which are still being worked on, either still in draft mode or indicated through WIP in + # title or label, PullApprove stays in a pending state until its ready for review. + - if: "draft or 'WIP' in title or 'PR state: WIP' in labels" + status: pending + explanation: 'Waiting to send reviews as PR is WIP' + # Disable PullApprove on specific PRs by adding the `PullApprove: disable` label + - if: "'PullApprove: disable' in labels" + status: success + explanation: "PullApprove skipped because of 'PullApprove: disable' label" + # If no file matching based groups are active, report this pull request as failing. Most likely, + # the PR author would need to update the PullApprove config, or create new group. + - if: len(groups.active) == 0 + status: failure + explanation: 'At least one group must match this PR. Please update an existing review group, or create a new group.' + +groups: + components-infra: + <<: *defaults + conditions: + - author not in ["angular-robot"] + - > + contains_any_globs(files, [ + '.bazel_fix_commands.json', + 'REPO.bazel', + '.bazelrc', + '.bazelversion', + '.firebaserc', + '.git-blame-ignore-revs', + '.gitignore', + '.npmrc', + '.nvmrc', + '.pullapprove.yml', + 'firebase.json', + 'LICENSE', + 'renovate.json', + 'tsconfig.json', + '.github/**/{*,.*}', + '.husky/**/{*,.*}', + '.ng-dev/**/{*,.*}', + '.vscode/**/{*,.*}', + 'scripts/**/{*,.*}', + 'test/**/{*,.*}', + 'tools/**/{*,.*}', + ]) + reviews: + request: 1 # Request at least one review + required: 1 # Require that all PRs have approval from at least one of the users in the group + author_value: 0 # The author of the PR cannot provide an approval for themself + reviewers: + users: + - crisbeto + - devversion + - andrewseguin + - josephperrott + + components-team: + <<: *defaults + conditions: + - *no-groups-above-this-active + - > + contains_any_globs(files, [ + '**/{.*,*}/**', + '**/{.*,*}', + ]) + reviews: + request: 2 # Request at least two reviews + required: 1 # Require that all PRs have approval from at least one of the users in the group + author_value: 0 # The author of the PR cannot provide an approval for themself + reviewers: + users: + - adolgachev + - crisbeto + - mmalerba + - andrewseguin + - wagnermaciel + - tjshiu + - ok7sai + - ~devversion + - ~josephperrott diff --git a/BUILD.bazel b/BUILD.bazel index 3e21ad52e5cc..63731bd19408 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,3 +1,4 @@ +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") load("@devinfra//bazel/validation:defs.bzl", "validate_ts_version_matching") load("@npm//:defs.bzl", "npm_link_all_packages") load("//:pkg-externals.bzl", "PKG_EXTERNALS") @@ -43,3 +44,15 @@ validate_ts_version_matching( module_lock_file = "MODULE.bazel.lock", package_json = "package.json", ) + +bool_flag( + name = "enable_snapshot_adev_assets", + build_setting_default = False, +) + +config_setting( + name = "snapshot_adev_assets", + flag_values = { + ":enable_snapshot_adev_assets": "true", + }, +) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09ad4fe5843b..ab89bc4247cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,233 +1,96 @@ - -# 20.2.10 "aleutite-anchovy" (2025-10-22) -### material -| Commit | Type | Description | -| -- | -- | -- | -| [b2cd596d3](https://github.com/angular/components/commit/b2cd596d315585c1f8b895c64230b49aecd3e6f8) | fix | **core:** differentiate container colors in m2 ([#32076](https://github.com/angular/components/pull/32076)) | + +# 21.0.5 "plastic-deer" (2025-12-18) - -# 21.0.0-next.9 "plastic-fork" (2025-10-15) -## Breaking Changes -### cdk -- * `TestElement` implementations need to provide a `setContenteditableValue`. -### material + +# 21.0.4 "lego lion" (2025-12-17) +### aria | Commit | Type | Description | | -- | -- | -- | -| [71d590796c](https://github.com/angular/components/commit/71d590796c8c29a198fefa31864c06ddfd334738) | feat | **sort:** add content projection slot for custom icon ([#32016](https://github.com/angular/components/pull/32016)) | -| [85f596b3c3](https://github.com/angular/components/commit/85f596b3c32d22541c3825da3479b67832a2f4da) | feat | **table:** add harness for "no data" row ([#32075](https://github.com/angular/components/pull/32075)) | -| [ff9059d8d1](https://github.com/angular/components/commit/ff9059d8d14b82a465481e51f01582caf6d83b6c) | fix | **checkbox:** use GrayText for disabled colors in high contrast mode ([#32066](https://github.com/angular/components/pull/32066)) | -| [5f12b26ab3](https://github.com/angular/components/commit/5f12b26ab3abad9acb2a3d008100d06e0fb63ab5) | fix | **snack-bar:** add max height for snack bar ([#32000](https://github.com/angular/components/pull/32000)) | -| [7dfabca03d](https://github.com/angular/components/commit/7dfabca03d14729926b708e4c86d913bc5b8f735) | fix | **timepicker:** add interface for timepicker input ([#32050](https://github.com/angular/components/pull/32050)) | +| [fb2726c7e0](https://github.com/angular/components/commit/fb2726c7e0fe5d4a4a98713b4bcdb30e6fe8d45e) | fix | **tabs:** disabled tab selection | ### cdk | Commit | Type | Description | | -- | -- | -- | -| [544438c865](https://github.com/angular/components/commit/544438c865532b30005ef7d03606fc4be4818a39) | fix | **testing:** make setContenteditableValue required ([#32058](https://github.com/angular/components/pull/32058)) | - - - - -# 20.2.9 "plastic-spoon" (2025-10-15) -### material -| Commit | Type | Description | -| -- | -- | -- | -| [af3b961214](https://github.com/angular/components/commit/af3b9612145ed20a3290f773e4fbf51206804145) | fix | **checkbox:** use GrayText for disabled colors in high contrast mode ([#32066](https://github.com/angular/components/pull/32066)) | -| [a90abb0a77](https://github.com/angular/components/commit/a90abb0a77b77b0ec5188582a1ea4d587508da5e) | fix | **snack-bar:** add max height for snack bar ([#32000](https://github.com/angular/components/pull/32000)) | - - - - -# 21.0.0-next.8 "osmium-summit" (2025-10-08) - - - - -# 21.0.0-next.7 "selenium-summit" (2025-10-08) -### cdk -| Commit | Type | Description | -| -- | -- | -- | -| [82cd076bf](https://github.com/angular/components/commit/82cd076bfb3084e258f8e20af6cac570349822ce) | feat | **overlay:** Allow passing separate X and Y values for the viewportMargin ([#29563](https://github.com/angular/components/pull/29563)) | -### material -| Commit | Type | Description | -| -- | -- | -- | -| [527fc3718](https://github.com/angular/components/commit/527fc3718326fe0f0fd32a4e7c6130627d0e9cce) | feat | **bottom-sheet:** add injector to MatBottomSheetConfig ([#31965](https://github.com/angular/components/pull/31965)) | -| [3665b433e](https://github.com/angular/components/commit/3665b433ea3c30c0ad612ee717cde67d5b73e103) | fix | **datepicker:** error due to synchronous change detection | -| [2d5942cb0](https://github.com/angular/components/commit/2d5942cb0fe86f9c3d26b1925b1d4390cfc6613b) | fix | **datepicker:** make date filter nullable ([#31980](https://github.com/angular/components/pull/31980)) | -| [05d71e53a](https://github.com/angular/components/commit/05d71e53a16f7cdb19b96e208601a64e1389fa8a) | fix | **menu:** fix divider color property ([#31815](https://github.com/angular/components/pull/31815)) | -| [c848d24db](https://github.com/angular/components/commit/c848d24dbb9bc468b47b107ae6a82ce32ded8502) | fix | **timepicker:** assign form control value before emitting events ([#31981](https://github.com/angular/components/pull/31981)) | -### material-date-fns-adapter -| Commit | Type | Description | -| -- | -- | -- | -| [b61d8841a](https://github.com/angular/components/commit/b61d8841ad70cced4ca6098bd0187d68ac00e486) | fix | parse time string containing only hours ([#31978](https://github.com/angular/components/pull/31978)) | - - - - -# 20.2.8 "strontium-summit" (2025-10-08) +| [4d2a7169ee](https://github.com/angular/components/commit/4d2a7169ee8b0df0cf7dead1a2034737d4d71748) | fix | **testing:** Skip task tracking if zone patches aren't present ([#32544](https://github.com/angular/components/pull/32544)) | ### material | Commit | Type | Description | | -- | -- | -- | -| [6d61babe7](https://github.com/angular/components/commit/6d61babe77a6a6f0c464b498ee773561b795663f) | fix | **datepicker:** error due to synchronous change detection | -| [e43dcabd0](https://github.com/angular/components/commit/e43dcabd005239a380ffef50cfea374b24a67735) | fix | **datepicker:** make date filter nullable ([#31980](https://github.com/angular/components/pull/31980)) | -| [f30c1c6c3](https://github.com/angular/components/commit/f30c1c6c3f6490ddf21ba668d4065c4d5f89f26f) | fix | **radio:** Hovering over label of a radio will show the pointer cursor ([#32015](https://github.com/angular/components/pull/32015)) | -| [de3f9e566](https://github.com/angular/components/commit/de3f9e5662edae3c19f44a89ee1ee34555eba147) | fix | **timepicker:** assign form control value before emitting events ([#31981](https://github.com/angular/components/pull/31981)) | -### material-date-fns-adapter -| Commit | Type | Description | -| -- | -- | -- | -| [2d1f8d068](https://github.com/angular/components/commit/2d1f8d068e18fa1e0044e0dd4c968c3fa6761e10) | fix | parse time string containing only hours ([#31978](https://github.com/angular/components/pull/31978)) | - - - - -# 21.0.0-next.6 "carbon-flamingo" (2025-10-01) -## Breaking Changes -### material -- * `AnimationCurves` has been removed. - * `AnimationDurations` has been removed. - * `NativeDateAdapter.useUtcForDisplay` has been removed. -### cdk-experimental -| Commit | Type | Description | -| -- | -- | -- | -| [f9e7eff127](https://github.com/angular/components/commit/f9e7eff127447a685126f3c942571653aa245728) | feat | **combobox:** introduce new signals-based combobox ([#31872](https://github.com/angular/components/pull/31872)) | -### material -| Commit | Type | Description | -| -- | -- | -- | -| [ef70029820](https://github.com/angular/components/commit/ef70029820423ff7ba6a5a1a372c24a0583a03f2) | feat | **chips:** allow for modifiers to be specified on separator keys ([#31914](https://github.com/angular/components/pull/31914)) | -| [1b06a8ea80](https://github.com/angular/components/commit/1b06a8ea8033a9cadffb52102aa74cc4f768adb1) | fix | **core:** remove deprecated APIs for v21 ([#31924](https://github.com/angular/components/pull/31924)) | -| [81eeff4bed](https://github.com/angular/components/commit/81eeff4beddbadd6518aca123182ae271be80819) | fix | **menu:** prevent child menu reopening while parent is animating away ([#31958](https://github.com/angular/components/pull/31958)) | -| [813f66b839](https://github.com/angular/components/commit/813f66b839d1684c3d5342e55ba61e948c979fab) | fix | **menu:** switch internal state to signals ([#31934](https://github.com/angular/components/pull/31934)) | -| [131c7ff804](https://github.com/angular/components/commit/131c7ff80420a9501618be1cb1c4b168cd286c4a) | fix | **paginator:** trim extraneous announcements ([#31943](https://github.com/angular/components/pull/31943)) | -| [6fba2049c3](https://github.com/angular/components/commit/6fba2049c36b86659a1713baf965da8651b6aae4) | fix | **select:** rotate arrow while open ([#31936](https://github.com/angular/components/pull/31936)) | -### cdk +| [57e831975e](https://github.com/angular/components/commit/57e831975e3d0eaf19b02988be155baeafbf6152) | fix | **form-field:** outline being thrown off by Tailwind ([#32513](https://github.com/angular/components/pull/32513)) | +| [454bf96089](https://github.com/angular/components/commit/454bf9608919e0c7807afd4010551d05e1776637) | fix | **schematics:** combine style resets ([#32496](https://github.com/angular/components/pull/32496)) | +| [d3139205c0](https://github.com/angular/components/commit/d3139205c096504533c361f1649156d3b9337bad) | fix | **slide-toggle:** Fix a11y issues by hiding label when it has no content. ([#32480](https://github.com/angular/components/pull/32480)) | +| [a3dfa754c9](https://github.com/angular/components/commit/a3dfa754c9080f023c3f4b0bd727c2d391f6c6c1) | fix | **tooltip:** remove explicit usePopover ([#32528](https://github.com/angular/components/pull/32528)) | +### multiple | Commit | Type | Description | | -- | -- | -- | -| [667a007d0d](https://github.com/angular/components/commit/667a007d0d4017d14eadb2db4b5c0665efa1c2b9) | fix | **scrolling:** Fix undefined error when documentElement.style is undefined ([#31904](https://github.com/angular/components/pull/31904)) | -| [2918e2804a](https://github.com/angular/components/commit/2918e2804a4563c64a20822605424d66de7adb91) | fix | **scrolling:** prevent subpixel gaps in virtual scroll viewport ([#31940](https://github.com/angular/components/pull/31940)) | +| [ecfe310e8a](https://github.com/angular/components/commit/ecfe310e8ab09ef12b4e3980da5ac090fd111009) | fix | type issues when importing Aria directives ([#32561](https://github.com/angular/components/pull/32561)) | +| [1620cabb51](https://github.com/angular/components/commit/1620cabb518aa897cff598487cc7007ebc22a5d4) | fix | use focus-visible for focus indicator ([#32514](https://github.com/angular/components/pull/32514)) | - -# 20.2.7 "ceramic-nebula" (2025-10-01) -### material -| Commit | Type | Description | -| -- | -- | -- | -| [85ed6550c2](https://github.com/angular/components/commit/85ed6550c2a3f8199350dcb1fb7d6f775dc2ba61) | fix | **menu:** prevent child menu reopening while parent is animating away ([#31958](https://github.com/angular/components/pull/31958)) | - - - - -# 21.0.0-next.5 "hungry-kiwi" (2025-09-24) -## Breaking Changes + +# 21.0.3 "plastic-moose" (2025-12-10) ### cdk -- * `$z-index-overlay-container` has been removed. Use `$overlay-container-z-index` instead. - * `$z-index-overlay` has been removed. Use `$overlay-z-index` instead. - * `$dark-backdrop-background` has been removed. Use `$overlay-backdrop-color` instead. - * `$z-index-overlay-backdrop` has been removed. Use `$overlay-backdrop-z-index` instead. -### cdk-experimental | Commit | Type | Description | | -- | -- | -- | -| [f0047282a](https://github.com/angular/components/commit/f0047282a10551bb9044c74e4b441e795bec1de9) | fix | **ui-patterns:** preserveContent should not render until first visible ([#31660](https://github.com/angular/components/pull/31660)) | +| [fd2213c5e7](https://github.com/angular/components/commit/fd2213c5e742697da4d7f68d8e4040f6eaeadfff) | fix | **menu:** allow user to pass selector for transform origin ([#32462](https://github.com/angular/components/pull/32462)) | +| [09ec44973f](https://github.com/angular/components/commit/09ec44973f8993b2a131aff30a0d68a45067f1ea) | fix | **overlay:** error when attempting to attach disposed overlay ([#32489](https://github.com/angular/components/pull/32489)) | ### material | Commit | Type | Description | | -- | -- | -- | -| [737c69fce](https://github.com/angular/components/commit/737c69fce7c362a4e49fb7f7869ed7237f4f8a35) | feat | **radio:** Hovering over label of a radio will show the pointer cursor ([#31894](https://github.com/angular/components/pull/31894)) | -| [3619903fa](https://github.com/angular/components/commit/3619903fa26910a784f01bee627e30d922b9b525) | feat | **testing:** Add icon name filtering to MatButtonHarness ([#31852](https://github.com/angular/components/pull/31852)) | -| [3b95117e5](https://github.com/angular/components/commit/3b95117e5901b4f53b685ca031f12f108a96f86f) | fix | **chips:** remove visible overflow for labels ([#31679](https://github.com/angular/components/pull/31679)) | -| [7a17fe950](https://github.com/angular/components/commit/7a17fe950dd69505d0cea705445aff14312a0212) | fix | **core:** move internal tokens ([#31907](https://github.com/angular/components/pull/31907)) | -| [977f46fe6](https://github.com/angular/components/commit/977f46fe61c9e77d0b3706a94016c14cd0cdbe90) | fix | **form-field:** restore error message animation ([#31774](https://github.com/angular/components/pull/31774)) | -| [ff10f0448](https://github.com/angular/components/commit/ff10f044826323811eee0f918e9c1515a5514c5e) | fix | **stepper:** Adjust aria tab-related roles to fix violations ([#31844](https://github.com/angular/components/pull/31844)) | -| [b6d81939c](https://github.com/angular/components/commit/b6d81939c822684a4084b3081a2a42d885e1907d) | fix | **table:** style no data row properly ([#31895](https://github.com/angular/components/pull/31895)) | -### cdk -| Commit | Type | Description | -| -- | -- | -- | -| [84fc0d963](https://github.com/angular/components/commit/84fc0d9638948ee2a94659d5af78894809f2a30c) | fix | **overlay:** remove deprecated variables ([#31898](https://github.com/angular/components/pull/31898)) | +| [151322f3b3](https://github.com/angular/components/commit/151322f3b3dd96e66f923dc4b0b4f81226ee44e6) | fix | **core:** default secondary color for focus indicator ([#32491](https://github.com/angular/components/pull/32491)) | +| [b1287cf9a6](https://github.com/angular/components/commit/b1287cf9a64a0663ac6a5ce3222a695cd502b8bc) | fix | **datepicker:** value reset when invalid value is entered using signal forms ([#32485](https://github.com/angular/components/pull/32485)) | +| [f4af3981b6](https://github.com/angular/components/commit/f4af3981b64bfca7cfe4ea1413c40446731ff3fe) | fix | **table:** fixed layout not working ([#32494](https://github.com/angular/components/pull/32494)) | - -# 20.2.5 "sparkling-penguin" (2025-09-24) -### material + +# 21.0.2 "babefphite-button" (2025-12-03) +### aria | Commit | Type | Description | | -- | -- | -- | -| [36be42637](https://github.com/angular/components/commit/36be42637df5021ae9afa4d097e84d83d78c197e) | fix | **core:** move internal tokens ([#31907](https://github.com/angular/components/pull/31907)) | -| [3ac762be5](https://github.com/angular/components/commit/3ac762be5dc180594c0681e2842e35123195feb6) | fix | **form-field:** restore error message animation ([#31774](https://github.com/angular/components/pull/31774)) | -| [65f23c003](https://github.com/angular/components/commit/65f23c003e94d59bbb08ad81eb66d725b1b5e79a) | fix | **table:** style no data row properly ([#31895](https://github.com/angular/components/pull/31895)) | - - - - -# 21.0.0-next.4 "v21.0.0-next4 release" (2025-09-17) -### material -| Commit | Type | Description | -| -- | -- | -- | -| [962a60c11](https://github.com/angular/components/commit/962a60c113ffdcb8920c1b4fee60d850007fda5f) | fix | **button:** do not show hover state on devices that don't support hover ([#31866](https://github.com/angular/components/pull/31866)) | -| [31562a4b8](https://github.com/angular/components/commit/31562a4b8f2700d43c53f2c170f14d4b28a7ac53) | fix | **core:** separate text/bg colors in utility classes ([#31879](https://github.com/angular/components/pull/31879)) | -| [a2906ddf3](https://github.com/angular/components/commit/a2906ddf36de4897b839df46941e59f3c0e0d727) | fix | **tabs:** attach content inside the zone ([#31868](https://github.com/angular/components/pull/31868)) | -### cdk-experimental -| Commit | Type | Description | -| -- | -- | -- | -| [c21dfa348](https://github.com/angular/components/commit/c21dfa348d49c2312e0f5c523f5d13ea51a7118f) | fix | **ui-patterns:** enter/space/click in single selection mode should not deselect tree item ([#31843](https://github.com/angular/components/pull/31843)) | - - - - -# 20.2.4 "v20.2.4 release" (2025-09-17) +| [b8f2151d0](https://github.com/angular/components/commit/b8f2151d02f7d3220750b8e60783cfeedd5a39d1) | fix | **menu:** focus flicker bug | +| [591c3d8cc](https://github.com/angular/components/commit/591c3d8ccd8a6875c57f47357b2b1c0127fb4704) | fix | **menu:** update api goldens ([#32463](https://github.com/angular/components/pull/32463)) | +| [bfe017741](https://github.com/angular/components/commit/bfe0177411c679b03d457532dfd5b82b235576df) | fix | **menu:** update unit tests to use ngMenuContent | ### material | Commit | Type | Description | | -- | -- | -- | -| [e7a0c19d0](https://github.com/angular/components/commit/e7a0c19d09bbe38852168c1a5ffcfeed66c1da6f) | fix | **tabs:** attach content inside the zone ([#31868](https://github.com/angular/components/pull/31868)) | +| [a6de52a67](https://github.com/angular/components/commit/a6de52a67c9caafce5dde03a24a7042315091771) | fix | **datepicker:** do not re-assign the same forms value ([#32447](https://github.com/angular/components/pull/32447)) | +| [ef8388b71](https://github.com/angular/components/commit/ef8388b714ca88def0bad2f9fa5ca544dd5260e1) | fix | **timepicker:** valueChanges emitting on init ([#32434](https://github.com/angular/components/pull/32434)) | - -# 21.0.0-next.3 "red-envelope" (2025-09-11) -## Breaking Changes -### material -- * `MatCommonModule` has been removed. - * `GranularSanityChecks` has been removed. - * `MATERIAL_SANITY_CHECKS` has been removed. - * `SanityChecks` has been removed. -### cdk-experimental -| Commit | Type | Description | -| -- | -- | -- | -| [f137183858](https://github.com/angular/components/commit/f137183858bf6bb9d47f7d184ea55241f2ee4a61) | fix | **accordion:** removes inert attribute from accordion trigger ([#31817](https://github.com/angular/components/pull/31817)) | -### material -| Commit | Type | Description | -| -- | -- | -- | -| [931ac3c1c7](https://github.com/angular/components/commit/931ac3c1c7f8468acaae1e9b266bdd5f52cd35fd) | fix | **chips:** Adjust trailing icon opacity based on chip state ([#31828](https://github.com/angular/components/pull/31828)) | -| [c832533062](https://github.com/angular/components/commit/c832533062738e91142d0222f99b1e6859e89cce) | fix | **core:** remove MatCommonModule ([#31813](https://github.com/angular/components/pull/31813)) | -| [878700d10a](https://github.com/angular/components/commit/878700d10ab042b6a62c6f86f4fcc24d5a0ae685) | fix | **progress-bar:** avoid CSP issues due to buffer dots ([#31818](https://github.com/angular/components/pull/31818)) | -| [5a1a0ba4e6](https://github.com/angular/components/commit/5a1a0ba4e68c40886505c8c096f6c1257b9edb7b) | fix | **select:** ensure proper highlighting on selection ([#31789](https://github.com/angular/components/pull/31789)) | -| [e0a35c52d5](https://github.com/angular/components/commit/e0a35c52d582d9f08aa9e76490481984dae53b75) | fix | **slider:** incorrect indicator transform origin in M3 ([#31834](https://github.com/angular/components/pull/31834)) | + +# 21.0.1 "sulfur-snack" (2025-11-26) ### cdk | Commit | Type | Description | | -- | -- | -- | -| [54f641e330](https://github.com/angular/components/commit/54f641e33073172e426b444500fdea552c94d2e3) | fix | **drag-drop:** allow axis lock to be reset ([#31829](https://github.com/angular/components/pull/31829)) | - - - - -# 20.2.3 "tango-heels" (2025-09-11) -### cdk +| [ccc12c387](https://github.com/angular/components/commit/ccc12c3879b3b58d6821e80ba1ef79db25a49572) | fix | **testing:** errors in harnesses when using Vitest ([#32399](https://github.com/angular/components/pull/32399)) | +### material | Commit | Type | Description | | -- | -- | -- | -| [442d4ca6b7](https://github.com/angular/components/commit/442d4ca6b752eabcf60003df0f1ad6905dddad5f) | fix | **drag-drop:** allow axis lock to be reset ([#31829](https://github.com/angular/components/pull/31829)) | -### material +| [043d9cacc](https://github.com/angular/components/commit/043d9cacc7d76828d02f921447b48688ab3d4129) | fix | **select:** render panel next to trigger ([#32363](https://github.com/angular/components/pull/32363)) | +### multiple | Commit | Type | Description | | -- | -- | -- | -| [ec33bf8eba](https://github.com/angular/components/commit/ec33bf8eba46b1281e6b2a814a1ce3e15475ec20) | fix | **progress-bar:** avoid CSP issues due to buffer dots ([#31818](https://github.com/angular/components/pull/31818)) | -| [9a68265302](https://github.com/angular/components/commit/9a682653023fd3d181d4b5b318ffc13974a9bf2b) | fix | **slider:** incorrect indicator transform origin in M3 ([#31834](https://github.com/angular/components/pull/31834)) | +| [02965bb0e](https://github.com/angular/components/commit/02965bb0eee969549518a49a796497ae1fe89569) | fix | resolve forward ref errors ([#32413](https://github.com/angular/components/pull/32413)) | - -# 21.0.0-next.2 "plastic-screw" (2025-09-03) + +# 21.0.0 "damask-dachshund" (2025-11-19) ## Breaking Changes ### cdk - * `LIVE_ANNOUNCER_ELEMENT_TOKEN_FACTORY` has been removed. * `TREE_KEY_MANAGER_FACTORY` has been removed. * `TREE_KEY_MANAGER_FACTORY_PROVIDER` has been removed. +- * `$z-index-overlay-container` has been removed. Use `$overlay-container-z-index` instead. + * `$z-index-overlay` has been removed. Use `$overlay-z-index` instead. + * `$dark-backdrop-background` has been removed. Use `$overlay-backdrop-color` instead. + * `$z-index-overlay-backdrop` has been removed. Use `$overlay-backdrop-z-index` instead. +- * `TemplatePortalDirective` has been removed. Use `CdkPortal` instead. + * `PortalHostDirective` has been removed. Use `CdkPortalOutlet` instead. +- * `TestElement` implementations need to provide a `setContenteditableValue`. ### material - * `MAT_AUTOCOMPLETE_DEFAULT_OPTIONS_FACTORY` has been removed. * `MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY` has been removed. @@ -236,7 +99,14 @@ - * `MAT_BUTTON_TOGGLE_GROUP_DEFAULT_OPTIONS_FACTORY` has been removed. - * `MAT_FAB_DEFAULT_OPTIONS_FACTORY` has been removed. - * `MAT_CHECKBOX_DEFAULT_OPTIONS_FACTORY` has been removed. +- * `AnimationCurves` has been removed. + * `AnimationDurations` has been removed. + * `NativeDateAdapter.useUtcForDisplay` has been removed. - * `MAT_DATE_LOCAL_FACTORY` has been removed. +- * `MatCommonModule` has been removed. + * `GranularSanityChecks` has been removed. + * `MATERIAL_SANITY_CHECKS` has been removed. + * `SanityChecks` has been removed. - * `matDatepickerAnimations` symbol has been removed. - * `MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY` has been removed. * `MAT_DATEPICKER_SCROLL_STRATEGY_FACTORY_PROVIDER` has been removed. @@ -287,111 +157,243 @@ ### material-luxon-adapter | Commit | Type | Description | | -- | -- | -- | -| [c1486fb7f8](https://github.com/angular/components/commit/c1486fb7f86c94d4a5986a60752094abe1b79912) | fix | remove deprecated factory functions | +| [c1486fb7f](https://github.com/angular/components/commit/c1486fb7f86c94d4a5986a60752094abe1b79912) | fix | remove deprecated factory functions | ### material-moment-adapter | Commit | Type | Description | | -- | -- | -- | -| [6cee2b9e2d](https://github.com/angular/components/commit/6cee2b9e2d26027804233ade82fede9cfbbe06cb) | fix | remove deprecated factory functions | +| [6cee2b9e2](https://github.com/angular/components/commit/6cee2b9e2d26027804233ade82fede9cfbbe06cb) | fix | remove deprecated factory functions | +### cdk-experimental +| Commit | Type | Description | +| -- | -- | -- | +| [f9e7eff12](https://github.com/angular/components/commit/f9e7eff127447a685126f3c942571653aa245728) | feat | **combobox:** introduce new signals-based combobox ([#31872](https://github.com/angular/components/pull/31872)) | +| [f13718385](https://github.com/angular/components/commit/f137183858bf6bb9d47f7d184ea55241f2ee4a61) | fix | **accordion:** removes inert attribute from accordion trigger ([#31817](https://github.com/angular/components/pull/31817)) | +| [668a2b4d5](https://github.com/angular/components/commit/668a2b4d5aa89750c4c4cb65d2659d9a41042ba5) | fix | **ui-patterns:** deselectAll unavailable items ([#31734](https://github.com/angular/components/pull/31734)) | +| [c21dfa348](https://github.com/angular/components/commit/c21dfa348d49c2312e0f5c523f5d13ea51a7118f) | fix | **ui-patterns:** enter/space/click in single selection mode should not deselect tree item ([#31843](https://github.com/angular/components/pull/31843)) | +| [d2c3bb971](https://github.com/angular/components/commit/d2c3bb971db4515d04b8842bcf96d4a8f8a65dac) | fix | **ui-patterns:** focus list when using active desce… ([#31756](https://github.com/angular/components/pull/31756)) | +| [f0047282a](https://github.com/angular/components/commit/f0047282a10551bb9044c74e4b441e795bec1de9) | fix | **ui-patterns:** preserveContent should not render until first visible ([#31660](https://github.com/angular/components/pull/31660)) | +| [df0d753f1](https://github.com/angular/components/commit/df0d753f166562ef15252b0923a583a93b76a4b2) | fix | **ui-patterns:** Tree expand/collapse key should work in follow focus mode ([#31747](https://github.com/angular/components/pull/31747)) | ### google-maps | Commit | Type | Description | | -- | -- | -- | -| [17cc7606a1](https://github.com/angular/components/commit/17cc7606a1efad644254505d116092f0cee20bfe) | fix | some events not firing on advanced marker | +| [17cc7606a](https://github.com/angular/components/commit/17cc7606a1efad644254505d116092f0cee20bfe) | fix | some events not firing on advanced marker | ### material | Commit | Type | Description | | -- | -- | -- | -| [255df78cb1](https://github.com/angular/components/commit/255df78cb154b613d5f7db2b64b66fbcca27da45) | fix | **autocomplete:** remove deprecated factory functions | -| [e8d005cbf8](https://github.com/angular/components/commit/e8d005cbf8823ad70e3e17d52df3924d6cd015df) | fix | **bottom-sheet:** remove deprecated animation definitions | -| [7dc05280f7](https://github.com/angular/components/commit/7dc05280f7876260636a9800442e9d972099eb28) | fix | **button-toggle:** remove deprecated factory functions | -| [69316b8713](https://github.com/angular/components/commit/69316b8713b0ae54de39cc893bc7a10ff356bb74) | fix | **button:** remove deprecated factory functions | -| [b2c4df2d1e](https://github.com/angular/components/commit/b2c4df2d1e31a831f2082534e4228d1f3623bb56) | fix | **checkbox:** remove deprecated factory functions | -| [24932b6e23](https://github.com/angular/components/commit/24932b6e23a3f1ebb6759e228bdcdda9ef77de73) | fix | **core:** remove deprecated factory functions | -| [870433501c](https://github.com/angular/components/commit/870433501c9435128f14b40d478803c477fd5a50) | fix | **core:** rename some utility classes ([#31795](https://github.com/angular/components/pull/31795)) | -| [3d89dfc3e9](https://github.com/angular/components/commit/3d89dfc3e9db1bc3acf168e517611ec2ac4ef121) | fix | **datepicker:** remove deprecated animation definitions | -| [89ff55f411](https://github.com/angular/components/commit/89ff55f411943492f54e8b8862770127b2dafb0d) | fix | **datepicker:** remove deprecated factory functions | -| [65c9b5ec76](https://github.com/angular/components/commit/65c9b5ec76982cdb16cd92c17a9d7c747549760c) | fix | **dialog:** remove deprecated animation definitions | -| [aee4e92397](https://github.com/angular/components/commit/aee4e923973d4f78ece4323eb712b760aef9e84c) | fix | **expansion:** remove deprecated animation definitions | -| [232b9fc595](https://github.com/angular/components/commit/232b9fc59535c5f04aaf16e07589e593395df4c1) | fix | **form-field:** remove deprecated animation definitions | -| [dd5abe37e9](https://github.com/angular/components/commit/dd5abe37e94adf6a93c174f01d77eef19ef5919c) | fix | **icon:** remove deprecated factory functions | -| [814ff1a25a](https://github.com/angular/components/commit/814ff1a25a5cb0bfeead32903ea8a23c70bf50da) | fix | **menu:** remove deprecated animation definitions | -| [4b06a1a64b](https://github.com/angular/components/commit/4b06a1a64b0ab6d73e33b546079bde9ace6050ae) | fix | **menu:** remove deprecated factory functions | -| [6d26c0fc1a](https://github.com/angular/components/commit/6d26c0fc1a382c6f4cd5f24761b93944ec3a0966) | fix | **paginator:** remove deprecated factory functions | -| [8fc72e9319](https://github.com/angular/components/commit/8fc72e93194edc3c6f49c5ef9ac9caf227d7ef3e) | fix | **progress-bar:** remove deprecated factory functions | -| [e1b68922bd](https://github.com/angular/components/commit/e1b68922bd6b5559ac9bfb6267c1b80df2f5e483) | fix | **progress-spinner:** remove deprecated factory functions | -| [29c296f2fb](https://github.com/angular/components/commit/29c296f2fb6d83b99cb4886856154c3c2b5c8c28) | fix | **radio:** remove deprecated factory functions | -| [7d25138f58](https://github.com/angular/components/commit/7d25138f580193f3cf0e09ef2d35659466750a75) | fix | **select:** remove deprecated animation definitions | -| [479b4e343c](https://github.com/angular/components/commit/479b4e343c55dc9227566d85ee7525b2e6c67e02) | fix | **select:** remove deprecated factory functions | -| [e87b95dc95](https://github.com/angular/components/commit/e87b95dc955942db118f6ed2144dbda82d399415) | fix | **sidenav:** remove deprecated animation definitions | -| [4ec00baf54](https://github.com/angular/components/commit/4ec00baf54e739ccf7e8af686b0fa0ef7c2ad750) | fix | **sidenav:** remove deprecated factory functions | -| [2259c7b4c7](https://github.com/angular/components/commit/2259c7b4c7810eacbaaeafff116faa6f0fa47ea3) | fix | **snack-bar:** remove deprecated animation definitions | -| [54aad6efc4](https://github.com/angular/components/commit/54aad6efc4af6312971be4ee22d6cc85d587acb2) | fix | **snack-bar:** remove deprecated factory functions | -| [6bdd8ae097](https://github.com/angular/components/commit/6bdd8ae09748821e2050daeab1318b08d7f3c92a) | fix | **sort:** remove deprecated animation definitions | -| [f32bf20891](https://github.com/angular/components/commit/f32bf20891903b7182e87276c4968d880762ed52) | fix | **sort:** remove deprecated factory functions | -| [bb7dbce929](https://github.com/angular/components/commit/bb7dbce92995385be39ee77517606d4006d4e07e) | fix | **stepper:** remove deprecated animation definitions | -| [ac840a8c6c](https://github.com/angular/components/commit/ac840a8c6c4731e9429425b52c9006285127c3d9) | fix | **stepper:** remove deprecated factory functions | -| [a7fce5e2c3](https://github.com/angular/components/commit/a7fce5e2c39110dca64ed5f9d68f145308d4d990) | fix | **tabs:** remove deprecated animation definitions | -| [a5a7c12f03](https://github.com/angular/components/commit/a5a7c12f0315e95984234d3d31f2e8d513bbddbf) | fix | **tabs:** remove deprecated factory functions | -| [ca1cd86dad](https://github.com/angular/components/commit/ca1cd86dad3628f80614aab104672d63b2288b26) | fix | **tooltip:** remove deprecated animation definitions | -| [bc10a87c4a](https://github.com/angular/components/commit/bc10a87c4af99d416b8e27553e1fe553bc24cf91) | fix | **tooltip:** remove deprecated factory functions | +| [527fc3718](https://github.com/angular/components/commit/527fc3718326fe0f0fd32a4e7c6130627d0e9cce) | feat | **bottom-sheet:** add injector to MatBottomSheetConfig ([#31965](https://github.com/angular/components/pull/31965)) | +| [ef7002982](https://github.com/angular/components/commit/ef70029820423ff7ba6a5a1a372c24a0583a03f2) | feat | **chips:** allow for modifiers to be specified on separator keys ([#31914](https://github.com/angular/components/pull/31914)) | +| [29f0bb238](https://github.com/angular/components/commit/29f0bb238a2a327ac6ed69071f6aa555693ab2d4) | feat | **chips:** make ChipInput optional for MatChipGrid ([#31693](https://github.com/angular/components/pull/31693)) | +| [dea603b88](https://github.com/angular/components/commit/dea603b88cf35d310674964b8b25514d5fe26772) | feat | **core:** add experimental utility classes ([#31702](https://github.com/angular/components/pull/31702)) | +| [737c69fce](https://github.com/angular/components/commit/737c69fce7c362a4e49fb7f7869ed7237f4f8a35) | feat | **radio:** Hovering over label of a radio will show the pointer cursor ([#31894](https://github.com/angular/components/pull/31894)) | +| [71d590796](https://github.com/angular/components/commit/71d590796c8c29a198fefa31864c06ddfd334738) | feat | **sort:** add content projection slot for custom icon ([#32016](https://github.com/angular/components/pull/32016)) | +| [85f596b3c](https://github.com/angular/components/commit/85f596b3c32d22541c3825da3479b67832a2f4da) | feat | **table:** add harness for "no data" row ([#32075](https://github.com/angular/components/pull/32075)) | +| [3619903fa](https://github.com/angular/components/commit/3619903fa26910a784f01bee627e30d922b9b525) | feat | **testing:** Add icon name filtering to MatButtonHarness ([#31852](https://github.com/angular/components/pull/31852)) | +| [9aa4cc881](https://github.com/angular/components/commit/9aa4cc88188d4dd5e933ca9767a0de06234f1474) | fix | **autocomplete:** empty autocomplete obscuring content ([#32348](https://github.com/angular/components/pull/32348)) | +| [255df78cb](https://github.com/angular/components/commit/255df78cb154b613d5f7db2b64b66fbcca27da45) | fix | **autocomplete:** remove deprecated factory functions | +| [cf04a3898](https://github.com/angular/components/commit/cf04a3898839affe430cdcfd3dbc5f58cf8c82f1) | fix | **autocomplete:** render overlay next to trigger ([#32282](https://github.com/angular/components/pull/32282)) | +| [e8d005cbf](https://github.com/angular/components/commit/e8d005cbf8823ad70e3e17d52df3924d6cd015df) | fix | **bottom-sheet:** remove deprecated animation definitions | +| [7dc05280f](https://github.com/angular/components/commit/7dc05280f7876260636a9800442e9d972099eb28) | fix | **button-toggle:** remove deprecated factory functions | +| [962a60c11](https://github.com/angular/components/commit/962a60c113ffdcb8920c1b4fee60d850007fda5f) | fix | **button:** do not show hover state on devices that don't support hover ([#31866](https://github.com/angular/components/pull/31866)) | +| [69316b871](https://github.com/angular/components/commit/69316b8713b0ae54de39cc893bc7a10ff356bb74) | fix | **button:** remove deprecated factory functions | +| [b2c4df2d1](https://github.com/angular/components/commit/b2c4df2d1e31a831f2082534e4228d1f3623bb56) | fix | **checkbox:** remove deprecated factory functions | +| [931ac3c1c](https://github.com/angular/components/commit/931ac3c1c7f8468acaae1e9b266bdd5f52cd35fd) | fix | **chips:** Adjust trailing icon opacity based on chip state ([#31828](https://github.com/angular/components/pull/31828)) | +| [13a9c48a0](https://github.com/angular/components/commit/13a9c48a093b1bfeab8f0328030dae60aca7519f) | fix | **chips:** refactor non-interactive actions to prevent adding click handlers ([#31664](https://github.com/angular/components/pull/31664)) | +| [3b95117e5](https://github.com/angular/components/commit/3b95117e5901b4f53b685ca031f12f108a96f86f) | fix | **chips:** remove visible overflow for labels ([#31679](https://github.com/angular/components/pull/31679)) | +| [347963303](https://github.com/angular/components/commit/3479633036abf467354e936c1ddb4fd2cefcd6ea) | fix | **chips:** strengthen edit/remove icons focus/hover styling ([#31759](https://github.com/angular/components/pull/31759)) | +| [1b06a8ea8](https://github.com/angular/components/commit/1b06a8ea8033a9cadffb52102aa74cc4f768adb1) | fix | **core:** remove deprecated APIs for v21 ([#31924](https://github.com/angular/components/pull/31924)) | +| [24932b6e2](https://github.com/angular/components/commit/24932b6e23a3f1ebb6759e228bdcdda9ef77de73) | fix | **core:** remove deprecated factory functions | +| [c83253306](https://github.com/angular/components/commit/c832533062738e91142d0222f99b1e6859e89cce) | fix | **core:** remove MatCommonModule ([#31813](https://github.com/angular/components/pull/31813)) | +| [18cedc737](https://github.com/angular/components/commit/18cedc7375bf0ab0590c9a984e5d380d52610ccc) | fix | **core:** rename corner extra-small to xs ([#32101](https://github.com/angular/components/pull/32101)) | +| [870433501](https://github.com/angular/components/commit/870433501c9435128f14b40d478803c477fd5a50) | fix | **core:** rename some utility classes ([#31795](https://github.com/angular/components/pull/31795)) | +| [605e2c9f6](https://github.com/angular/components/commit/605e2c9f6557b41f03ad3f9268d6c536433e1555) | fix | **core:** rename utility-classes to system-classes ([#31745](https://github.com/angular/components/pull/31745)) | +| [31562a4b8](https://github.com/angular/components/commit/31562a4b8f2700d43c53f2c170f14d4b28a7ac53) | fix | **core:** separate text/bg colors in utility classes ([#31879](https://github.com/angular/components/pull/31879)) | +| [3d89dfc3e](https://github.com/angular/components/commit/3d89dfc3e9db1bc3acf168e517611ec2ac4ef121) | fix | **datepicker:** remove deprecated animation definitions | +| [89ff55f41](https://github.com/angular/components/commit/89ff55f411943492f54e8b8862770127b2dafb0d) | fix | **datepicker:** remove deprecated factory functions | +| [47bdfb200](https://github.com/angular/components/commit/47bdfb200769847292a1f07c22f52f96a0892874) | fix | **dialog:** afterOpened emitting too early when animations are disabled ([#32211](https://github.com/angular/components/pull/32211)) | +| [65c9b5ec7](https://github.com/angular/components/commit/65c9b5ec76982cdb16cd92c17a9d7c747549760c) | fix | **dialog:** remove deprecated animation definitions | +| [aee4e9239](https://github.com/angular/components/commit/aee4e923973d4f78ece4323eb712b760aef9e84c) | fix | **expansion:** remove deprecated animation definitions | +| [232b9fc59](https://github.com/angular/components/commit/232b9fc59535c5f04aaf16e07589e593395df4c1) | fix | **form-field:** remove deprecated animation definitions | +| [dd5abe37e](https://github.com/angular/components/commit/dd5abe37e94adf6a93c174f01d77eef19ef5919c) | fix | **icon:** remove deprecated factory functions | +| [05d71e53a](https://github.com/angular/components/commit/05d71e53a16f7cdb19b96e208601a64e1389fa8a) | fix | **menu:** fix divider color property ([#31815](https://github.com/angular/components/pull/31815)) | +| [814ff1a25](https://github.com/angular/components/commit/814ff1a25a5cb0bfeead32903ea8a23c70bf50da) | fix | **menu:** remove deprecated animation definitions | +| [4b06a1a64](https://github.com/angular/components/commit/4b06a1a64b0ab6d73e33b546079bde9ace6050ae) | fix | **menu:** remove deprecated factory functions | +| [6d26c0fc1](https://github.com/angular/components/commit/6d26c0fc1a382c6f4cd5f24761b93944ec3a0966) | fix | **paginator:** remove deprecated factory functions | +| [131c7ff80](https://github.com/angular/components/commit/131c7ff80420a9501618be1cb1c4b168cd286c4a) | fix | **paginator:** trim extraneous announcements ([#31943](https://github.com/angular/components/pull/31943)) | +| [8fc72e931](https://github.com/angular/components/commit/8fc72e93194edc3c6f49c5ef9ac9caf227d7ef3e) | fix | **progress-bar:** remove deprecated factory functions | +| [e1b68922b](https://github.com/angular/components/commit/e1b68922bd6b5559ac9bfb6267c1b80df2f5e483) | fix | **progress-spinner:** remove deprecated factory functions | +| [29c296f2f](https://github.com/angular/components/commit/29c296f2fb6d83b99cb4886856154c3c2b5c8c28) | fix | **radio:** remove deprecated factory functions | +| [5a1a0ba4e](https://github.com/angular/components/commit/5a1a0ba4e68c40886505c8c096f6c1257b9edb7b) | fix | **select:** ensure proper highlighting on selection ([#31789](https://github.com/angular/components/pull/31789)) | +| [7d25138f5](https://github.com/angular/components/commit/7d25138f580193f3cf0e09ef2d35659466750a75) | fix | **select:** remove deprecated animation definitions | +| [479b4e343](https://github.com/angular/components/commit/479b4e343c55dc9227566d85ee7525b2e6c67e02) | fix | **select:** remove deprecated factory functions | +| [e87b95dc9](https://github.com/angular/components/commit/e87b95dc955942db118f6ed2144dbda82d399415) | fix | **sidenav:** remove deprecated animation definitions | +| [4ec00baf5](https://github.com/angular/components/commit/4ec00baf54e739ccf7e8af686b0fa0ef7c2ad750) | fix | **sidenav:** remove deprecated factory functions | +| [2259c7b4c](https://github.com/angular/components/commit/2259c7b4c7810eacbaaeafff116faa6f0fa47ea3) | fix | **snack-bar:** remove deprecated animation definitions | +| [54aad6efc](https://github.com/angular/components/commit/54aad6efc4af6312971be4ee22d6cc85d587acb2) | fix | **snack-bar:** remove deprecated factory functions | +| [6bdd8ae09](https://github.com/angular/components/commit/6bdd8ae09748821e2050daeab1318b08d7f3c92a) | fix | **sort:** remove deprecated animation definitions | +| [f32bf2089](https://github.com/angular/components/commit/f32bf20891903b7182e87276c4968d880762ed52) | fix | **sort:** remove deprecated factory functions | +| [ff10f0448](https://github.com/angular/components/commit/ff10f044826323811eee0f918e9c1515a5514c5e) | fix | **stepper:** Adjust aria tab-related roles to fix violations ([#31844](https://github.com/angular/components/pull/31844)) | +| [bb7dbce92](https://github.com/angular/components/commit/bb7dbce92995385be39ee77517606d4006d4e07e) | fix | **stepper:** remove deprecated animation definitions | +| [ac840a8c6](https://github.com/angular/components/commit/ac840a8c6c4731e9429425b52c9006285127c3d9) | fix | **stepper:** remove deprecated factory functions | +| [a7fce5e2c](https://github.com/angular/components/commit/a7fce5e2c39110dca64ed5f9d68f145308d4d990) | fix | **tabs:** remove deprecated animation definitions | +| [a5a7c12f0](https://github.com/angular/components/commit/a5a7c12f0315e95984234d3d31f2e8d513bbddbf) | fix | **tabs:** remove deprecated factory functions | +| [7dfabca03](https://github.com/angular/components/commit/7dfabca03d14729926b708e4c86d913bc5b8f735) | fix | **timepicker:** add interface for timepicker input ([#32050](https://github.com/angular/components/pull/32050)) | +| [cd14409a3](https://github.com/angular/components/commit/cd14409a390baf18b49280da69b5f710e9ec72ce) | fix | **timepicker:** render overlay next to trigger ([#32288](https://github.com/angular/components/pull/32288)) | +| [ca1cd86da](https://github.com/angular/components/commit/ca1cd86dad3628f80614aab104672d63b2288b26) | fix | **tooltip:** remove deprecated animation definitions | +| [bc10a87c4](https://github.com/angular/components/commit/bc10a87c4af99d416b8e27553e1fe553bc24cf91) | fix | **tooltip:** remove deprecated factory functions | ### cdk | Commit | Type | Description | | -- | -- | -- | -| [30f6c3c457](https://github.com/angular/components/commit/30f6c3c4575ca4e4d3a8cb8c152d3ffba67b9e0f) | fix | **a11y:** remove deprecated factory functions | +| [82cd076bf](https://github.com/angular/components/commit/82cd076bfb3084e258f8e20af6cac570349822ce) | feat | **overlay:** Allow passing separate X and Y values for the viewportMargin ([#29563](https://github.com/angular/components/pull/29563)) | +| [30f6c3c45](https://github.com/angular/components/commit/30f6c3c4575ca4e4d3a8cb8c152d3ffba67b9e0f) | fix | **a11y:** remove deprecated factory functions | +| [b112568d1](https://github.com/angular/components/commit/b112568d194963566b971c13c9c88b78990c221f) | fix | **overlay:** add DI token to opt out of popovers ([#32306](https://github.com/angular/components/pull/32306)) | +| [0e4bf076b](https://github.com/angular/components/commit/0e4bf076b163da2600a159ab084ad200d47296ac) | fix | **overlay:** hide native backdrop | +| [84f8f10ba](https://github.com/angular/components/commit/84f8f10ba871463e4f71a529a6bb0212093dc19b) | fix | **overlay:** make it easier to set default for overlay directive | +| [84fc0d963](https://github.com/angular/components/commit/84fc0d9638948ee2a94659d5af78894809f2a30c) | fix | **overlay:** remove deprecated variables ([#31898](https://github.com/angular/components/pull/31898)) | +| [a4dc30ce8](https://github.com/angular/components/commit/a4dc30ce8e2b397fcec5d585b6f0e3faa3835f5f) | fix | **overlay:** simplify matching the overlay to the trigger width | +| [8d00344f2](https://github.com/angular/components/commit/8d00344f200452971209075913e96804afa6f619) | fix | **overlay:** simplify public API of overlay directive | +| [6234d82e2](https://github.com/angular/components/commit/6234d82e2ca8101fdd1aac97257e92cb02466ef7) | fix | **overlay:** update golden file ([#32367](https://github.com/angular/components/pull/32367)) | +| [03c5d34db](https://github.com/angular/components/commit/03c5d34dbd684a37a608cf9d33e20c293163919c) | fix | **portal:** remove deprecated directives ([#32117](https://github.com/angular/components/pull/32117)) | +| [5b45df30c](https://github.com/angular/components/commit/5b45df30ca60b75b27313d3b1b52c42ac037eb4f) | fix | **table:** ensure CdkTable updates view with OnPush and trackBy ([#31451](https://github.com/angular/components/pull/31451)) | +| [544438c86](https://github.com/angular/components/commit/544438c865532b30005ef7d03606fc4be4818a39) | fix | **testing:** make setContenteditableValue required ([#32058](https://github.com/angular/components/pull/32058)) | +### aria +| Commit | Type | Description | +| -- | -- | -- | +| [a821a3ef0](https://github.com/angular/components/commit/a821a3ef07d99d5ce8631469cd818929b9c0559b) | feat | **grid:** create the aria grid ([#32092](https://github.com/angular/components/pull/32092)) | +| [f9d3cde14](https://github.com/angular/components/commit/f9d3cde14984c6da006e09e8e79809247e017a65) | feat | **menu:** create the aria menu ([#32080](https://github.com/angular/components/pull/32080)) | +| [a0b580027](https://github.com/angular/components/commit/a0b5800277c206127999e21eda77ef003c066aee) | feat | **toolbar:** adds skip disabled toolbar example to dev-app ([#32127](https://github.com/angular/components/pull/32127)) | +| [5396c4347](https://github.com/angular/components/commit/5396c43474fe272ad5e21366c027cd1ae0c6d593) | feat | **toolbar:** adds toolbar basic vertical example to dev-app ([#32126](https://github.com/angular/components/pull/32126)) | +| [ba9f79be5](https://github.com/angular/components/commit/ba9f79be528c6228e50a73809ec62efcbfc7afc6) | feat | **toolbar:** adds toolbar-basic-horizontal-example to dev-app ([#32106](https://github.com/angular/components/pull/32106)) | +| [ec6045b27](https://github.com/angular/components/commit/ec6045b270211131b6987e316fb3252745c89e11) | fix | **accordion:** rename value to panelId for trigger and panel ([#32295](https://github.com/angular/components/pull/32295)) | +| [0b03c6e96](https://github.com/angular/components/commit/0b03c6e96485f83447ed3451070be138bf21d4e6) | fix | **combobox:** add missing apis ([#32124](https://github.com/angular/components/pull/32124)) | +| [25223a2f8](https://github.com/angular/components/commit/25223a2f8be7b13699b94b99a1335e4ac7185772) | fix | **combobox:** dialog popup support ([#32279](https://github.com/angular/components/pull/32279)) | +| [a47ebeb96](https://github.com/angular/components/commit/a47ebeb964e794e3868659d68e46b3b782d1550b) | fix | **combobox:** disabled state ([#32308](https://github.com/angular/components/pull/32308)) | +| [127d3dba5](https://github.com/angular/components/commit/127d3dba5754a4ceaa60f56ced7b4795c29372cc) | fix | **combobox:** escape key behavior ([#32364](https://github.com/angular/components/pull/32364)) | +| [c3279ca4b](https://github.com/angular/components/commit/c3279ca4b47f91cd61e0ba0be24bdd10869fa059) | fix | **combobox:** highlighting edge cases ([#32136](https://github.com/angular/components/pull/32136)) | +| [1232805db](https://github.com/angular/components/commit/1232805db6f0a0a07154b3601eaa8b9cc0d94f31) | fix | **combobox:** readonly behavior ([#32169](https://github.com/angular/components/pull/32169)) | +| [6c46f950d](https://github.com/angular/components/commit/6c46f950d451862692c2c74f41a704a3ef0fd472) | fix | **combobox:** several small fixes ([#32202](https://github.com/angular/components/pull/32202)) | +| [8beb22f8c](https://github.com/angular/components/commit/8beb22f8c8d0d9f415225826188c38964c65ceee) | fix | **combobox:** use click instead of pointerup ([#32324](https://github.com/angular/components/pull/32324)) | +| [92d933421](https://github.com/angular/components/commit/92d933421953a2f5123d0f823dc7880bb4e69098) | fix | **grid:** fix navigation bugs and add grid behavior unit tests ([#32140](https://github.com/angular/components/pull/32140)) | +| [e3babf3fc](https://github.com/angular/components/commit/e3babf3fc3229879e38751eff2c5941ed2152ae7) | fix | **grid:** rtl navigation ([#32170](https://github.com/angular/components/pull/32170)) | +| [fe79e982c](https://github.com/angular/components/commit/fe79e982cb7b3f0b42c2be056face255ccfe5783) | fix | **menu:** add expansion delay ([#32293](https://github.com/angular/components/pull/32293)) | +| [3d1cafbdd](https://github.com/angular/components/commit/3d1cafbdd3839c12d5298f216abaef59f717f04c) | fix | **menu:** add selectable to inputs ([#32131](https://github.com/angular/components/pull/32131)) | +| [56631cb85](https://github.com/angular/components/commit/56631cb858fda514cfd81e23064e7859aa338843) | fix | **menu:** deferred content import | +| [95e648ad8](https://github.com/angular/components/commit/95e648ad8a4fb3591fd20229db3a0649ac95ebb8) | fix | **menu:** disabled state ([#32301](https://github.com/angular/components/pull/32301)) | +| [ce20dbe1a](https://github.com/angular/components/commit/ce20dbe1a3e4be0e1002533f7f1910b1f9efd0c3) | fix | **menu:** lazy render trigger ([#32203](https://github.com/angular/components/pull/32203)) | +| [19095030a](https://github.com/angular/components/commit/19095030a0a6f102aa1ba7276afbc12fd79a27c7) | fix | **menu:** public api cleanup ([#32189](https://github.com/angular/components/pull/32189)) | +| [4b5db1328](https://github.com/angular/components/commit/4b5db13286b263cb28918938dce515376b4a5f5b) | fix | **menu:** rtl text direction ([#32254](https://github.com/angular/components/pull/32254)) | +| [bac171d8b](https://github.com/angular/components/commit/bac171d8bc82fd7bfd716cc5214c49f1bfbc76bb) | fix | **toolbar:** allow developers to wrap widgets ([#32341](https://github.com/angular/components/pull/32341)) | +| [d8acd69f5](https://github.com/angular/components/commit/d8acd69f5d26c85ffc08224e67be5f594c85e38a) | fix | **tree:** adds rtl keyboard functionality for tree ([#32305](https://github.com/angular/components/pull/32305)) | +| [86558d2aa](https://github.com/angular/components/commit/86558d2aa6437556bac805a6acdf8c31f5b2cfb8) | fix | **tree:** internal conformance check ([#32337](https://github.com/angular/components/pull/32337)) | +| [09e31e716](https://github.com/angular/components/commit/09e31e71673a73d80033e7aaf8ad8f6ae9db8f89) | fix | **tree:** only reset selected values if used in combobox ([#32329](https://github.com/angular/components/pull/32329)) | +| [05f936ae1](https://github.com/angular/components/commit/05f936ae14d8943ced0ad981cde8f3c2ac95afd1) | fix | **tree:** tree item visibility issue ([#32156](https://github.com/angular/components/pull/32156)) | +| [afe4d063d](https://github.com/angular/components/commit/afe4d063dd8f3dc5932519761693e7a79de77dc1) | fix | **ui-patterns:** internal conformance fixes ([#32102](https://github.com/angular/components/pull/32102)) | +### multiple +| Commit | Type | Description | +| -- | -- | -- | +| [8a76ccfa0](https://github.com/angular/components/commit/8a76ccfa0f4db446aa679c00858f44d6b594dc04) | fix | allow ids to be inputs ([#32320](https://github.com/angular/components/pull/32320)) | +| [e7f9ef3e8](https://github.com/angular/components/commit/e7f9ef3e826a543b422505671c74e73b2a2f495e) | fix | change delays to use ms ([#32321](https://github.com/angular/components/pull/32321)) | +| [a8bbd2816](https://github.com/angular/components/commit/a8bbd281629aaa8978aa8c23a394d63a24058c45) | fix | change value inputs to 'values' for array-based types ([#32300](https://github.com/angular/components/pull/32300)) | +| [b50ecb9b6](https://github.com/angular/components/commit/b50ecb9b6ebb9f9769bd8694a4a5671071eeccef) | fix | enable overwriting `preventDefault` to allow triggering hyperlinks using enter key ([#32123](https://github.com/angular/components/pull/32123)) | +| [f38020952](https://github.com/angular/components/commit/f38020952b78fe3d87c8a3f6bda63684c018dd32) | fix | expose active from public api ([#32330](https://github.com/angular/components/pull/32330)) | +| [9ac3ab5f9](https://github.com/angular/components/commit/9ac3ab5f9cad2952c1a8fa139794de9518e6190a) | fix | expose element ([#32328](https://github.com/angular/components/pull/32328)) | +| [caa2b3b65](https://github.com/angular/components/commit/caa2b3b6595d8a69c5deaac827be69d2aac1111a) | fix | prevent focus on disabled components ([#32263](https://github.com/angular/components/pull/32263)) | +| [551ce3df3](https://github.com/angular/components/commit/551ce3df36785a7552f465b81ecede5796716f73) | fix | transform boolean attr ([#32319](https://github.com/angular/components/pull/32319)) | - -# 20.2.2 "plastic-moose" (2025-09-03) + +# 20.2.10 "aleutite-anchovy" (2025-10-22) +### material +| Commit | Type | Description | +| -- | -- | -- | +| [b2cd596d3](https://github.com/angular/components/commit/b2cd596d315585c1f8b895c64230b49aecd3e6f8) | fix | **core:** differentiate container colors in m2 ([#32076](https://github.com/angular/components/pull/32076)) | - -# 21.0.0-next.1 "althupite-avocado" (2025-08-27) -### cdk + +# 20.2.9 "plastic-spoon" (2025-10-15) +### material | Commit | Type | Description | | -- | -- | -- | -| [540637270](https://github.com/angular/components/commit/540637270a5b72173f299e2ef1731499f43f19d3) | fix | **tree:** resolve memory leak ([#31754](https://github.com/angular/components/pull/31754)) | +| [af3b961214](https://github.com/angular/components/commit/af3b9612145ed20a3290f773e4fbf51206804145) | fix | **checkbox:** use GrayText for disabled colors in high contrast mode ([#32066](https://github.com/angular/components/pull/32066)) | +| [a90abb0a77](https://github.com/angular/components/commit/a90abb0a77b77b0ec5188582a1ea4d587508da5e) | fix | **snack-bar:** add max height for snack bar ([#32000](https://github.com/angular/components/pull/32000)) | + + + + +# 20.2.8 "strontium-summit" (2025-10-08) ### material | Commit | Type | Description | | -- | -- | -- | -| [29f0bb238](https://github.com/angular/components/commit/29f0bb238a2a327ac6ed69071f6aa555693ab2d4) | feat | **chips:** make ChipInput optional for MatChipGrid ([#31693](https://github.com/angular/components/pull/31693)) | -| [13a9c48a0](https://github.com/angular/components/commit/13a9c48a093b1bfeab8f0328030dae60aca7519f) | fix | **chips:** refactor non-interactive actions to prevent adding click handlers ([#31664](https://github.com/angular/components/pull/31664)) | -| [347963303](https://github.com/angular/components/commit/3479633036abf467354e936c1ddb4fd2cefcd6ea) | fix | **chips:** strengthen edit/remove icons focus/hover styling ([#31759](https://github.com/angular/components/pull/31759)) | -| [605e2c9f6](https://github.com/angular/components/commit/605e2c9f6557b41f03ad3f9268d6c536433e1555) | fix | **core:** rename utility-classes to system-classes ([#31745](https://github.com/angular/components/pull/31745)) | -| [8010c7cde](https://github.com/angular/components/commit/8010c7cde8e05661a978023dfd3c8c01a2861f97) | fix | **datepicker:** add visible labels to calendar buttons ([#31777](https://github.com/angular/components/pull/31777)) | -| [46e189569](https://github.com/angular/components/commit/46e189569ed30b63ae8817ff4390bb1274a5a8b9) | fix | **sort:** error if signal is bound to disabled input ([#31776](https://github.com/angular/components/pull/31776)) | -### cdk-experimental +| [6d61babe7](https://github.com/angular/components/commit/6d61babe77a6a6f0c464b498ee773561b795663f) | fix | **datepicker:** error due to synchronous change detection | +| [e43dcabd0](https://github.com/angular/components/commit/e43dcabd005239a380ffef50cfea374b24a67735) | fix | **datepicker:** make date filter nullable ([#31980](https://github.com/angular/components/pull/31980)) | +| [f30c1c6c3](https://github.com/angular/components/commit/f30c1c6c3f6490ddf21ba668d4065c4d5f89f26f) | fix | **radio:** Hovering over label of a radio will show the pointer cursor ([#32015](https://github.com/angular/components/pull/32015)) | +| [de3f9e566](https://github.com/angular/components/commit/de3f9e5662edae3c19f44a89ee1ee34555eba147) | fix | **timepicker:** assign form control value before emitting events ([#31981](https://github.com/angular/components/pull/31981)) | +### material-date-fns-adapter | Commit | Type | Description | | -- | -- | -- | -| [668a2b4d5](https://github.com/angular/components/commit/668a2b4d5aa89750c4c4cb65d2659d9a41042ba5) | fix | **ui-patterns:** deselectAll unavailable items ([#31734](https://github.com/angular/components/pull/31734)) | -| [d2c3bb971](https://github.com/angular/components/commit/d2c3bb971db4515d04b8842bcf96d4a8f8a65dac) | fix | **ui-patterns:** focus list when using active desce… ([#31756](https://github.com/angular/components/pull/31756)) | -| [df0d753f1](https://github.com/angular/components/commit/df0d753f166562ef15252b0923a583a93b76a4b2) | fix | **ui-patterns:** Tree expand/collapse key should work in follow focus mode ([#31747](https://github.com/angular/components/pull/31747)) | +| [2d1f8d068](https://github.com/angular/components/commit/2d1f8d068e18fa1e0044e0dd4c968c3fa6761e10) | fix | parse time string containing only hours ([#31978](https://github.com/angular/components/pull/31978)) | - -# 20.2.1 "armalcolite-alligator" (2025-08-27) + +# 20.2.7 "ceramic-nebula" (2025-10-01) +### material +| Commit | Type | Description | +| -- | -- | -- | +| [85ed6550c2](https://github.com/angular/components/commit/85ed6550c2a3f8199350dcb1fb7d6f775dc2ba61) | fix | **menu:** prevent child menu reopening while parent is animating away ([#31958](https://github.com/angular/components/pull/31958)) | + + + + +# 20.2.5 "sparkling-penguin" (2025-09-24) +### material +| Commit | Type | Description | +| -- | -- | -- | +| [36be42637](https://github.com/angular/components/commit/36be42637df5021ae9afa4d097e84d83d78c197e) | fix | **core:** move internal tokens ([#31907](https://github.com/angular/components/pull/31907)) | +| [3ac762be5](https://github.com/angular/components/commit/3ac762be5dc180594c0681e2842e35123195feb6) | fix | **form-field:** restore error message animation ([#31774](https://github.com/angular/components/pull/31774)) | +| [65f23c003](https://github.com/angular/components/commit/65f23c003e94d59bbb08ad81eb66d725b1b5e79a) | fix | **table:** style no data row properly ([#31895](https://github.com/angular/components/pull/31895)) | + + + + +# 20.2.4 "v20.2.4 release" (2025-09-17) +### material +| Commit | Type | Description | +| -- | -- | -- | +| [e7a0c19d0](https://github.com/angular/components/commit/e7a0c19d09bbe38852168c1a5ffcfeed66c1da6f) | fix | **tabs:** attach content inside the zone ([#31868](https://github.com/angular/components/pull/31868)) | + + + + +# 20.2.3 "tango-heels" (2025-09-11) ### cdk | Commit | Type | Description | | -- | -- | -- | -| [ee808f8f3](https://github.com/angular/components/commit/ee808f8f32fc27d59c56b63044355e4c7e0e416c) | fix | **tree:** resolve memory leak ([#31754](https://github.com/angular/components/pull/31754)) | +| [442d4ca6b7](https://github.com/angular/components/commit/442d4ca6b752eabcf60003df0f1ad6905dddad5f) | fix | **drag-drop:** allow axis lock to be reset ([#31829](https://github.com/angular/components/pull/31829)) | ### material | Commit | Type | Description | | -- | -- | -- | -| [04c598ad0](https://github.com/angular/components/commit/04c598ad0a1a16a0149b324dc442255c2fdc0c17) | fix | **datepicker:** add visible labels to calendar buttons ([#31777](https://github.com/angular/components/pull/31777)) | -| [839f3c1c1](https://github.com/angular/components/commit/839f3c1c1354438fdfa554662f5278703937678f) | fix | **sort:** error if signal is bound to disabled input ([#31776](https://github.com/angular/components/pull/31776)) | +| [ec33bf8eba](https://github.com/angular/components/commit/ec33bf8eba46b1281e6b2a814a1ce3e15475ec20) | fix | **progress-bar:** avoid CSP issues due to buffer dots ([#31818](https://github.com/angular/components/pull/31818)) | +| [9a68265302](https://github.com/angular/components/commit/9a682653023fd3d181d4b5b318ffc13974a9bf2b) | fix | **slider:** incorrect indicator transform origin in M3 ([#31834](https://github.com/angular/components/pull/31834)) | + + + + +# 20.2.2 "plastic-moose" (2025-09-03) - -# 21.0.0-next.0 "neodymium-fountain" (2025-08-20) + +# 20.2.1 "armalcolite-alligator" (2025-08-27) ### cdk | Commit | Type | Description | | -- | -- | -- | -| [5b45df30c](https://github.com/angular/components/commit/5b45df30ca60b75b27313d3b1b52c42ac037eb4f) | fix | **table:** ensure CdkTable updates view with OnPush and trackBy ([#31451](https://github.com/angular/components/pull/31451)) | +| [ee808f8f3](https://github.com/angular/components/commit/ee808f8f32fc27d59c56b63044355e4c7e0e416c) | fix | **tree:** resolve memory leak ([#31754](https://github.com/angular/components/pull/31754)) | ### material | Commit | Type | Description | | -- | -- | -- | -| [dea603b88](https://github.com/angular/components/commit/dea603b88cf35d310674964b8b25514d5fe26772) | feat | **core:** add experimental utility classes ([#31702](https://github.com/angular/components/pull/31702)) | +| [04c598ad0](https://github.com/angular/components/commit/04c598ad0a1a16a0149b324dc442255c2fdc0c17) | fix | **datepicker:** add visible labels to calendar buttons ([#31777](https://github.com/angular/components/pull/31777)) | +| [839f3c1c1](https://github.com/angular/components/commit/839f3c1c1354438fdfa554662f5278703937678f) | fix | **sort:** error if signal is bound to disabled input ([#31776](https://github.com/angular/components/pull/31776)) | diff --git a/MODULE.bazel b/MODULE.bazel index 103c8047efc7..c52b7408ba5f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -4,21 +4,21 @@ module( name = "components", ) -bazel_dep(name = "yq.bzl", version = "0.3.1") -bazel_dep(name = "rules_nodejs", version = "6.5.2") -bazel_dep(name = "aspect_rules_js", version = "2.6.2") +bazel_dep(name = "yq.bzl", version = "0.3.2") +bazel_dep(name = "rules_nodejs", version = "6.6.2") +bazel_dep(name = "aspect_rules_js", version = "2.8.3") bazel_dep(name = "rules_pkg", version = "1.1.0") -bazel_dep(name = "tar.bzl", version = "0.6.0") -bazel_dep(name = "aspect_bazel_lib", version = "2.21.2") -bazel_dep(name = "aspect_rules_esbuild", version = "0.23.0") -bazel_dep(name = "aspect_rules_jasmine", version = "2.0.0") +bazel_dep(name = "tar.bzl", version = "0.7.0") +bazel_dep(name = "aspect_bazel_lib", version = "2.22.0") +bazel_dep(name = "aspect_rules_esbuild", version = "0.24.0") +bazel_dep(name = "aspect_rules_jasmine", version = "2.0.2") bazel_dep(name = "platforms", version = "1.0.0") -bazel_dep(name = "aspect_rules_ts", version = "3.7.0") +bazel_dep(name = "aspect_rules_ts", version = "3.8.0") bazel_dep(name = "bazel_skylib", version = "1.8.2") bazel_dep(name = "rules_browsers") git_override( module_name = "rules_browsers", - commit = "6a699bf3e896690e2923cf3ade29fbd4e492e366", + commit = "8ef3e996d5fc040a35770f860987d8b9cad8ef3d", remote = "https://github.com/devversion/rules_browsers.git", ) @@ -32,14 +32,14 @@ git_override( bazel_dep(name = "rules_angular") git_override( module_name = "rules_angular", - commit = "c3721b6ece2050a59a97562e3b95527a3092b03b", + commit = "7133b97252508f8528e5c5818a9a73cacc2e2a0e", remote = "https://github.com/devversion/rules_angular.git", ) bazel_dep(name = "devinfra") git_override( module_name = "devinfra", - commit = "c584c3565b71c7a8cda81d55bb14e3e66ef934da", + commit = "dd5658bd720370542913e23b21d80450bac94b60", remote = "https://github.com/angular/dev-infra.git", ) @@ -56,10 +56,15 @@ rules_ts_ext.deps( use_repo(rules_ts_ext, **{"npm_typescript": "components_npm_typescript"}) node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") -node.toolchain(node_version = "22.12.0") +node.toolchain(node_version_from_nvmrc = "//:.nvmrc") use_repo(node, "nodejs_toolchains") pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm") +pnpm.pnpm( + name = "pnpm", + pnpm_version = "10.26.0", + pnpm_version_integrity = "sha512-Oz9scl6+cSUGwKsa1BM8+GsfS2h+/85iqbOLTXLjlUJC5kMZD8UfoWQpScc19APevUT1yw7dZXq+Y6i2p+HkAg==", +) use_repo(pnpm, "pnpm") npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm") @@ -97,30 +102,52 @@ npm.npm_translate_lock( "@angular/aria": [ "//integration:__subpackages__", "//docs:__subpackages__", + "//src/components-examples:__subpackages__", + "//src/dev-app:__subpackages__", ], "@angular/cdk": [ - "//integration:__subpackages__", "//docs:__subpackages__", + "//integration:__subpackages__", + "//src/aria:__subpackages__", + "//src/cdk-experimental:__subpackages__", + "//src/components-examples:__subpackages__", + "//src/dev-app:__subpackages__", + "//src/material-experimental:__subpackages__", + "//src/material:__subpackages__", + "//src/e2e-app:__subpackages__", ], "@angular/cdk-experimental": [ - "//integration:__subpackages__", "//docs:__subpackages__", + "//integration:__subpackages__", + "//src/components-examples:__subpackages__", + "//src/dev-app:__subpackages__", + "//src/material-experimental:__subpackages__", + "//src/e2e-app:__subpackages__", ], "@angular/material": [ - "//integration:__subpackages__", "//docs:__subpackages__", + "//integration:__subpackages__", + "//src/components-examples:__subpackages__", + "//src/dev-app:__subpackages__", + "//src/material-experimental:__subpackages__", + "//src/material-moment-adapter:__subpackages__", + "//src/e2e-app:__subpackages__", ], "@angular/material-experimental": [ "//integration:__subpackages__", "//docs:__subpackages__", + "//src/components-examples:__subpackages__", + "//src/dev-app:__subpackages__", ], "@angular/google-maps": [ "//integration:__subpackages__", "//docs:__subpackages__", + "//src/dev-app:__subpackages__", ], "@angular/youtube-player": [ "//integration:__subpackages__", "//docs:__subpackages__", + "//src/dev-app:__subpackages__", ], "@angular/material-moment-adapter": [ "//integration:__subpackages__", @@ -133,10 +160,10 @@ npm.npm_translate_lock( "@angular/material-luxon-adapter": [ "//integration:__subpackages__", "//docs:__subpackages__", + "//src/components-examples:__subpackages__", ], }, pnpm_lock = "//:pnpm-lock.yaml", - verify_node_modules_ignored = "//:.bazelignore", ) use_repo(npm, "npm") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 1db2dbbcba98..fb4608dd96e5 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -1,5 +1,5 @@ { - "lockFileVersion": 13, + "lockFileVersion": 18, "registryFileHashes": { "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", @@ -10,31 +10,35 @@ "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da", - "https://bcr.bazel.build/modules/apple_support/1.23.1/MODULE.bazel": "53763fed456a968cf919b3240427cf3a9d5481ec5466abc9d5dc51bc70087442", - "https://bcr.bazel.build/modules/apple_support/1.23.1/source.json": "d888b44312eb0ad2c21a91d026753f330caa48a25c9b2102fae75eb2b0dcfdd2", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.0.0/MODULE.bazel": "e118477db5c49419a88d78ebc7a2c2cea9d49600fe0f490c1903324a2c16ecd9", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.14.0/MODULE.bazel": "2b31ffcc9bdc8295b2167e07a757dbbc9ac8906e7028e5170a3708cecaac119f", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.17.1/MODULE.bazel": "9b027af55f619c7c444cead71061578fab6587e5e1303fa4ed61d49d2b1a7262", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.3/MODULE.bazel": "253d739ba126f62a5767d832765b12b59e9f8d2bc88cc1572f4a73e46eb298ca", - "https://bcr.bazel.build/modules/aspect_bazel_lib/2.21.2/MODULE.bazel": "276347663a25b0d5bd6cad869252bea3e160c4d980e764b15f3bae7f80b30624", - "https://bcr.bazel.build/modules/aspect_bazel_lib/2.21.2/source.json": "f42051fa42629f0e59b7ac2adf0a55749144b11f1efcd8c697f0ee247181e526", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.0/MODULE.bazel": "7fe0191f047d4fe4a4a46c1107e2350cbb58a8fc2e10913aa4322d3190dec0bf", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.0/source.json": "369df5b7f2eae82f200fff95cf1425f90dee90a0d0948122060b48150ff0e224", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.7.7/MODULE.bazel": "491f8681205e31bb57892d67442ce448cda4f472a8e6b3dc062865e29a64f89c", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.8.1/MODULE.bazel": "812d2dd42f65dca362152101fbec418029cc8fd34cbad1a2fde905383d705838", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.9.3/MODULE.bazel": "66baf724dbae7aff4787bf2245cc188d50cb08e07789769730151c0943587c14", - "https://bcr.bazel.build/modules/aspect_rules_esbuild/0.23.0/MODULE.bazel": "9b437a9ec25a619304940434fa03b8d41248213eb7009da2c898f3d6a4075ef3", - "https://bcr.bazel.build/modules/aspect_rules_esbuild/0.23.0/source.json": "7b4cac4e61bae4262e7f67f6bec0b200fcb9060044f12e84a3bc37e0be245de7", - "https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.0/MODULE.bazel": "071d1952527721bf8b180e1299def24edaece9d7466e31a311981640da82c6be", - "https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.0/source.json": "45fa9603cdfe100575a12d8b65fa425fe8713dd8c9f0cdf802168b670bc0e299", + "https://bcr.bazel.build/modules/aspect_rules_esbuild/0.24.0/MODULE.bazel": "15d19e46ec74e9e49ddf3c335e7a91b0657571654b0960bdcd10b771eeb4f7cb", + "https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.0/MODULE.bazel": "5fef5ec709c837312823f9bcf0f276661e2cb48ad52f17c4e01176bbf1e9bf58", + "https://bcr.bazel.build/modules/aspect_rules_esbuild/0.25.0/source.json": "5e42968c6d23ab8bd95c02634b16864d866334347827cb6a8425b86c11cc4363", + "https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.2/MODULE.bazel": "45f054400ff242c4433f6d7f20f6123a9a72739cb7a1f44247d738db1644f46c", + "https://bcr.bazel.build/modules/aspect_rules_jasmine/2.0.2/source.json": "3ed399a5654259a822448f9cdbf21f6c738f16ccd7f89249c7507e374cbdd1e3", "https://bcr.bazel.build/modules/aspect_rules_js/2.0.0/MODULE.bazel": "b45b507574aa60a92796e3e13c195cd5744b3b8aff516a9c0cb5ae6a048161c5", "https://bcr.bazel.build/modules/aspect_rules_js/2.4.2/MODULE.bazel": "0d01db38b96d25df7ed952a5e96eac4b3802723d146961974bf020f6dd07591d", "https://bcr.bazel.build/modules/aspect_rules_js/2.6.2/MODULE.bazel": "ed2a871f4ab8fbde0cab67c425745069d84ea64b64313fa1a2954017326511f5", - "https://bcr.bazel.build/modules/aspect_rules_js/2.6.2/source.json": "59933fb8ddabd9740a3c12ff5552f06f2b8d68c3633883c681c757bf227c3763", + "https://bcr.bazel.build/modules/aspect_rules_js/2.8.3/MODULE.bazel": "807ce5f624124a8bc586c743394d174e85f0f9c6c4e0e2410b4088aebe790ac8", + "https://bcr.bazel.build/modules/aspect_rules_js/2.8.3/source.json": "c35cb4e04f61a09c17f8c569894b80de884b1e3dee2d33829704786e3f778037", "https://bcr.bazel.build/modules/aspect_rules_ts/3.6.3/MODULE.bazel": "d09db394970f076176ce7bab5b5fa7f0d560fd4f30b8432ea5e2c2570505b130", "https://bcr.bazel.build/modules/aspect_rules_ts/3.7.0/MODULE.bazel": "5aace216caf88638950ef061245d23c36f57c8359e56e97f02a36f70bb09c50f", - "https://bcr.bazel.build/modules/aspect_rules_ts/3.7.0/source.json": "4a8115ea69dd796353232ff27a7e93e6d7d1ad43bea1eb33c6bd3acfa656bf2e", + "https://bcr.bazel.build/modules/aspect_rules_ts/3.8.0/MODULE.bazel": "b1ab5a46cc68c11192613035703606482b115516969788b8c313ad583395366d", + "https://bcr.bazel.build/modules/aspect_rules_ts/3.8.1/MODULE.bazel": "796622c65ae3008374fc2d77c32ddb4ef6da9fe891826ce648f70033a48b3667", + "https://bcr.bazel.build/modules/aspect_rules_ts/3.8.1/source.json": "a7c4f332f5c21f4e63d073f8dda40bf278d5307499fb307b35058dba558f417a", "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.3/MODULE.bazel": "20f53b145f40957a51077ae90b37b7ce83582a1daf9350349f0f86179e19dd0d", "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.6/MODULE.bazel": "cafb8781ad591bc57cc765dca5fefab08cf9f65af363d162b79d49205c7f8af7", "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.8/MODULE.bazel": "aa975a83e72bcaac62ee61ab12b788ea324a1d05c4aab28aadb202f647881679", - "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.2.8/source.json": "786cbc49377fb6bf4859aec5b1c61f8fc26b08e9fdb929e2dde2e1e2a406bd24", + "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/MODULE.bazel": "37c764292861c2f70314efa9846bb6dbb44fc0308903b3285da6528305450183", + "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/source.json": "605086bbc197743a0d360f7ddc550a1d4dfa0441bc807236e17170f636153348", "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", @@ -42,13 +46,15 @@ "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b", - "https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65", + "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", "https://bcr.bazel.build/modules/bazel_features/1.34.0/MODULE.bazel": "e8475ad7c8965542e0c7aac8af68eb48c4af904be3d614b6aa6274c092c2ea1e", "https://bcr.bazel.build/modules/bazel_features/1.34.0/source.json": "dfa5c4b01110313153b484a735764d247fee5624bbab63d25289e43b151a657a", "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", "https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", "https://bcr.bazel.build/modules/bazel_lib/3.0.0-beta.1/MODULE.bazel": "407729e232f611c3270005b016b437005daa7b1505826798ea584169a476e878", - "https://bcr.bazel.build/modules/bazel_lib/3.0.0-beta.1/source.json": "72bfbe19a3936675719157798de64631e9ac54c2b41f13b544b821d094f4840a", + "https://bcr.bazel.build/modules/bazel_lib/3.0.0/MODULE.bazel": "22b70b80ac89ad3f3772526cd9feee2fa412c2b01933fea7ed13238a448d370d", + "https://bcr.bazel.build/modules/bazel_lib/3.0.0/source.json": "895f21909c6fba01d7c17914bb6c8e135982275a1b18cdaa4e62272217ef1751", "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", @@ -63,7 +69,8 @@ "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6", "https://bcr.bazel.build/modules/bazel_skylib/1.8.2/MODULE.bazel": "69ad6927098316848b34a9142bcc975e018ba27f08c4ff403f50c1b6e646ca67", - "https://bcr.bazel.build/modules/bazel_skylib/1.8.2/source.json": "34a3c8bcf233b835eb74be9d628899bb32999d3e0eadef1947a0a562a2b16ffb", + "https://bcr.bazel.build/modules/bazel_skylib/1.9.0/MODULE.bazel": "72997b29dfd95c3fa0d0c48322d05590418edef451f8db8db5509c57875fb4b7", + "https://bcr.bazel.build/modules/bazel_skylib/1.9.0/source.json": "7ad77c1e8c1b84222d9b3f3cae016a76639435744c19330b0b37c0a3c9da7dc0", "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.1/MODULE.bazel": "cdf8cbe5ee750db04b78878c9633cc76e80dcf4416cbe982ac3a9222f80713c8", @@ -87,7 +94,6 @@ "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", - "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", "https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": "f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580", "https://bcr.bazel.build/modules/platforms/1.0.0/source.json": "f4ff1fd412e0246fd38c82328eb209130ead81d62dcd5a9e40910f867f733d96", "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", @@ -95,9 +101,9 @@ "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", "https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92", - "https://bcr.bazel.build/modules/protobuf/29.0-rc3/source.json": "c16a6488fb279ef578da7098e605082d72ed85fc8d843eaae81e7d27d0f4625d", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.0/source.json": "b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981", "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", - "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022", "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", @@ -106,8 +112,8 @@ "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", - "https://bcr.bazel.build/modules/rules_cc/0.0.11/MODULE.bazel": "9f249c5624a4788067b96b8b896be10c7e8b4375dc46f6d8e1e51100113e0992", "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", + "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", @@ -130,10 +136,10 @@ "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2", "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", - "https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1", + "https://bcr.bazel.build/modules/rules_java/8.14.0/MODULE.bazel": "717717ed40cc69994596a45aec6ea78135ea434b8402fb91b009b9151dd65615", + "https://bcr.bazel.build/modules/rules_java/8.14.0/source.json": "8a88c4ca9e8759da53cddc88123880565c520503321e2566b4e33d0287a3d4bc", "https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017", "https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939", - "https://bcr.bazel.build/modules/rules_java/8.5.1/source.json": "db1a77d81b059e0f84985db67a22f3f579a529a86b7997605be3d214a0abe38e", "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", @@ -152,7 +158,8 @@ "https://bcr.bazel.build/modules/rules_nodejs/6.3.0/MODULE.bazel": "45345e4aba35dd6e4701c1eebf5a4e67af4ed708def9ebcdc6027585b34ee52d", "https://bcr.bazel.build/modules/rules_nodejs/6.5.0/MODULE.bazel": "546d0cf79f36f9f6e080816045f97234b071c205f4542e3351bd4424282a8810", "https://bcr.bazel.build/modules/rules_nodejs/6.5.2/MODULE.bazel": "7f9ea68a0ce6d82905ce9f74e76ab8a8b4531ed4c747018c9d76424ad0b3370d", - "https://bcr.bazel.build/modules/rules_nodejs/6.5.2/source.json": "6a6ca0940914d55c550d1417cad13a56c9900e23f651a762d8ccc5a64adcf661", + "https://bcr.bazel.build/modules/rules_nodejs/6.6.2/MODULE.bazel": "9fdb5e1d50246a25761f150fcc820dc47e4052330a8408451e628804f9ca64a6", + "https://bcr.bazel.build/modules/rules_nodejs/6.6.2/source.json": "6e8c1ecc64ff8da147c1620f862ad77d7b19c5d1b52b3aa5e847d5b3d0de4cc3", "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", "https://bcr.bazel.build/modules/rules_pkg/1.1.0/MODULE.bazel": "9db8031e71b6ef32d1846106e10dd0ee2deac042bd9a2de22b4761b0c3036453", @@ -164,12 +171,12 @@ "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", - "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7", "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", "https://bcr.bazel.build/modules/rules_python/1.0.0/MODULE.bazel": "898a3d999c22caa585eb062b600f88654bf92efb204fa346fb55f6f8edffca43", "https://bcr.bazel.build/modules/rules_python/1.0.0/source.json": "b0162a65c6312e45e7912e39abd1a7f8856c2c7e41ecc9b6dc688a6f6400a917", "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", @@ -186,80 +193,77 @@ "https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216", "https://bcr.bazel.build/modules/tar.bzl/0.2.1/MODULE.bazel": "52d1c00a80a8cc67acbd01649e83d8dd6a9dc426a6c0b754a04fe8c219c76468", "https://bcr.bazel.build/modules/tar.bzl/0.5.1/MODULE.bazel": "7c2eb3dcfc53b0f3d6f9acdfd911ca803eaf92aadf54f8ca6e4c1f3aee288351", - "https://bcr.bazel.build/modules/tar.bzl/0.6.0/MODULE.bazel": "a3584b4edcfafcabd9b0ef9819808f05b372957bbdff41601429d5fd0aac2e7c", - "https://bcr.bazel.build/modules/tar.bzl/0.6.0/source.json": "4a620381df075a16cb3a7ed57bd1d05f7480222394c64a20fa51bdb636fda658", + "https://bcr.bazel.build/modules/tar.bzl/0.7.0/MODULE.bazel": "cc1acd85da33c80e430b65219a620d54d114628df24a618c3a5fa0b65e988da9", + "https://bcr.bazel.build/modules/tar.bzl/0.7.0/source.json": "9becb80306f42d4810bfa16379fb48aad0b01ce5342bc12fe47dcd6af3ac4d7a", "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", "https://bcr.bazel.build/modules/yq.bzl/0.1.1/MODULE.bazel": "9039681f9bcb8958ee2c87ffc74bdafba9f4369096a2b5634b88abc0eaefa072", "https://bcr.bazel.build/modules/yq.bzl/0.2.0/MODULE.bazel": "6f3a675677db8885be4d607fde14cc51829715e3a879fb016eb9bf336786ce6d", - "https://bcr.bazel.build/modules/yq.bzl/0.3.1/MODULE.bazel": "9bcb7151b3cd4681b89d350530eaf7b45e32a44dda94843b8932b0cb1cd4594a", - "https://bcr.bazel.build/modules/yq.bzl/0.3.1/source.json": "f0b0f204a2a6b0e34b4c9541efe8c04f2ef1af65948daa784eccea738b21dbd2", + "https://bcr.bazel.build/modules/yq.bzl/0.3.2/MODULE.bazel": "0384efa70e8033d842ea73aa4b7199fa099709e236a7264345c03937166670b6", + "https://bcr.bazel.build/modules/yq.bzl/0.3.2/source.json": "c4ec3e192477e154f08769e29d69e8fd36e8a4f0f623997f3e1f6f7d328f7d7d", "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", - "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", - "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", - "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" }, "selectedYankedVersions": {}, "moduleExtensions": { - "@@aspect_rules_esbuild~//esbuild:extensions.bzl%esbuild": { + "@@aspect_rules_esbuild+//esbuild:extensions.bzl%esbuild": { "general": { - "bzlTransitiveDigest": "W+cy7GU3S29h8PPWylmMlPB5Z16vuZzJX4k0jlXGFoc=", - "usagesDigest": "H070ZIHhSlR+Han009l+GdDSuT9AJssdyVHQ7xjstSo=", + "bzlTransitiveDigest": "cOsNHoj4Yf1EmxDxGg5atteXakqrrOncy6QX6I9jR4k=", + "usagesDigest": "ToTaCONCN/E05krnHXLM1kpV1zrHNxHrGpUip973II4=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "esbuild_darwin-x64": { - "bzlFile": "@@aspect_rules_esbuild~//esbuild:repositories.bzl", - "ruleClassName": "esbuild_repositories", + "repoRuleId": "@@aspect_rules_esbuild+//esbuild:repositories.bzl%esbuild_repositories", "attributes": { "esbuild_version": "0.19.9", + "integrity": "", "platform": "darwin-x64" } }, "esbuild_darwin-arm64": { - "bzlFile": "@@aspect_rules_esbuild~//esbuild:repositories.bzl", - "ruleClassName": "esbuild_repositories", + "repoRuleId": "@@aspect_rules_esbuild+//esbuild:repositories.bzl%esbuild_repositories", "attributes": { "esbuild_version": "0.19.9", + "integrity": "", "platform": "darwin-arm64" } }, "esbuild_linux-x64": { - "bzlFile": "@@aspect_rules_esbuild~//esbuild:repositories.bzl", - "ruleClassName": "esbuild_repositories", + "repoRuleId": "@@aspect_rules_esbuild+//esbuild:repositories.bzl%esbuild_repositories", "attributes": { "esbuild_version": "0.19.9", + "integrity": "", "platform": "linux-x64" } }, "esbuild_linux-arm64": { - "bzlFile": "@@aspect_rules_esbuild~//esbuild:repositories.bzl", - "ruleClassName": "esbuild_repositories", + "repoRuleId": "@@aspect_rules_esbuild+//esbuild:repositories.bzl%esbuild_repositories", "attributes": { "esbuild_version": "0.19.9", + "integrity": "", "platform": "linux-arm64" } }, "esbuild_win32-x64": { - "bzlFile": "@@aspect_rules_esbuild~//esbuild:repositories.bzl", - "ruleClassName": "esbuild_repositories", + "repoRuleId": "@@aspect_rules_esbuild+//esbuild:repositories.bzl%esbuild_repositories", "attributes": { "esbuild_version": "0.19.9", + "integrity": "", "platform": "win32-x64" } }, "esbuild_toolchains": { - "bzlFile": "@@aspect_rules_esbuild~//esbuild/private:toolchains_repo.bzl", - "ruleClassName": "toolchains_repo", + "repoRuleId": "@@aspect_rules_esbuild+//esbuild/private:toolchains_repo.bzl%toolchains_repo", "attributes": { "esbuild_version": "0.19.9", "user_repository_name": "esbuild" } }, "npm__esbuild_0.19.9": { - "bzlFile": "@@aspect_rules_js~//npm/private:npm_import.bzl", - "ruleClassName": "npm_import_rule", + "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_rule", "attributes": { "package": "esbuild", "version": "0.19.9", @@ -282,13 +286,11 @@ "extra_build_content": "", "generate_bzl_library_targets": false, "extract_full_archive": false, - "exclude_package_contents": [], - "system_tar": "auto" + "exclude_package_contents": [] } }, "npm__esbuild_0.19.9__links": { - "bzlFile": "@@aspect_rules_js~//npm/private:npm_import.bzl", - "ruleClassName": "npm_import_links", + "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_links", "attributes": { "package": "esbuild", "version": "0.19.9", @@ -314,96 +316,110 @@ }, "recordedRepoMappingEntries": [ [ - "aspect_bazel_lib~", + "aspect_bazel_lib+", "bazel_skylib", - "bazel_skylib~" + "bazel_skylib+" ], [ - "aspect_bazel_lib~", + "aspect_bazel_lib+", "bazel_tools", "bazel_tools" ], [ - "aspect_bazel_lib~", + "aspect_bazel_lib+", "tar.bzl", - "tar.bzl~" + "tar.bzl+" ], [ - "aspect_rules_esbuild~", + "aspect_rules_esbuild+", "aspect_rules_js", - "aspect_rules_js~" + "aspect_rules_js+" ], [ - "aspect_rules_esbuild~", + "aspect_rules_esbuild+", "aspect_tools_telemetry_report", - "aspect_tools_telemetry~~telemetry~aspect_tools_telemetry_report" + "aspect_tools_telemetry++telemetry+aspect_tools_telemetry_report" ], [ - "aspect_rules_esbuild~", + "aspect_rules_esbuild+", "bazel_skylib", - "bazel_skylib~" + "bazel_skylib+" ], [ - "aspect_rules_js~", + "aspect_rules_js+", "aspect_bazel_lib", - "aspect_bazel_lib~" + "aspect_bazel_lib+" ], [ - "aspect_rules_js~", + "aspect_rules_js+", "aspect_rules_js", - "aspect_rules_js~" + "aspect_rules_js+" ], [ - "aspect_rules_js~", + "aspect_rules_js+", "aspect_tools_telemetry_report", - "aspect_tools_telemetry~~telemetry~aspect_tools_telemetry_report" + "aspect_tools_telemetry++telemetry+aspect_tools_telemetry_report" ], [ - "aspect_rules_js~", + "aspect_rules_js+", + "bazel_lib", + "bazel_lib+" + ], + [ + "aspect_rules_js+", "bazel_skylib", - "bazel_skylib~" + "bazel_skylib+" ], [ - "aspect_rules_js~", + "aspect_rules_js+", "bazel_tools", "bazel_tools" ], [ - "tar.bzl~", - "aspect_bazel_lib", - "aspect_bazel_lib~" + "bazel_lib+", + "bazel_skylib", + "bazel_skylib+" + ], + [ + "bazel_lib+", + "bazel_tools", + "bazel_tools" + ], + [ + "tar.bzl+", + "bazel_lib", + "bazel_lib+" ], [ - "tar.bzl~", + "tar.bzl+", "bazel_skylib", - "bazel_skylib~" + "bazel_skylib+" ], [ - "tar.bzl~", + "tar.bzl+", "tar.bzl", - "tar.bzl~" + "tar.bzl+" ] ] } }, - "@@aspect_rules_js~//npm:extensions.bzl%pnpm": { + "@@aspect_rules_js+//npm:extensions.bzl%pnpm": { "general": { - "bzlTransitiveDigest": "kFo9dd9KDRPKtK0RkVyoouzNI0l+bqG8cEaw+4+ZnVw=", - "usagesDigest": "YbFxfk4LS8ZRSHiDWDKkBXNqTdHX58mv4QOfh7MzUAM=", + "bzlTransitiveDigest": "fFcLmS3p3sFcn/GGOh4LxupnmV3++FYtXPG7KyQUZx4=", + "usagesDigest": "P+i0x4shIfQ52VgrfmEA2YOTpwyIfLRdaDta4gGRuoU=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "pnpm": { - "bzlFile": "@@aspect_rules_js~//npm/private:npm_import.bzl", - "ruleClassName": "npm_import_rule", + "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_rule", "attributes": { "package": "pnpm", - "version": "8.6.7", + "version": "10.26.0", "root_package": "", "link_workspace": "", "link_packages": {}, - "integrity": "sha512-vRIWpD/L4phf9Bk2o/O2TDR8fFoJnpYrp2TKqTIZF/qZ2/rgL3qKXzHofHgbXsinwMoSEigz28sqk3pQ+yMEQQ==", + "integrity": "sha512-Oz9scl6+cSUGwKsa1BM8+GsfS2h+/85iqbOLTXLjlUJC5kMZD8UfoWQpScc19APevUT1yw7dZXq+Y6i2p+HkAg==", "url": "", "commit": "", "patch_args": [ @@ -419,16 +435,14 @@ "extra_build_content": "load(\"@aspect_rules_js//js:defs.bzl\", \"js_binary\")\njs_binary(name = \"pnpm\", data = glob([\"package/**\"]), entry_point = \"package/dist/pnpm.cjs\", visibility = [\"//visibility:public\"])", "generate_bzl_library_targets": false, "extract_full_archive": true, - "exclude_package_contents": [], - "system_tar": "auto" + "exclude_package_contents": [] } }, "pnpm__links": { - "bzlFile": "@@aspect_rules_js~//npm/private:npm_import.bzl", - "ruleClassName": "npm_import_links", + "repoRuleId": "@@aspect_rules_js+//npm/private:npm_import.bzl%npm_import_links", "attributes": { "package": "pnpm", - "version": "8.6.7", + "version": "10.26.0", "dev": false, "root_package": "", "link_packages": {}, @@ -451,91 +465,105 @@ }, "recordedRepoMappingEntries": [ [ - "aspect_bazel_lib~", + "aspect_bazel_lib+", "bazel_skylib", - "bazel_skylib~" + "bazel_skylib+" ], [ - "aspect_bazel_lib~", + "aspect_bazel_lib+", "bazel_tools", "bazel_tools" ], [ - "aspect_bazel_lib~", + "aspect_bazel_lib+", "tar.bzl", - "tar.bzl~" + "tar.bzl+" ], [ - "aspect_rules_js~", + "aspect_rules_js+", "aspect_bazel_lib", - "aspect_bazel_lib~" + "aspect_bazel_lib+" ], [ - "aspect_rules_js~", + "aspect_rules_js+", "aspect_rules_js", - "aspect_rules_js~" + "aspect_rules_js+" ], [ - "aspect_rules_js~", + "aspect_rules_js+", "aspect_tools_telemetry_report", - "aspect_tools_telemetry~~telemetry~aspect_tools_telemetry_report" + "aspect_tools_telemetry++telemetry+aspect_tools_telemetry_report" ], [ - "aspect_rules_js~", + "aspect_rules_js+", "bazel_features", - "bazel_features~" + "bazel_features+" + ], + [ + "aspect_rules_js+", + "bazel_lib", + "bazel_lib+" ], [ - "aspect_rules_js~", + "aspect_rules_js+", "bazel_skylib", - "bazel_skylib~" + "bazel_skylib+" ], [ - "aspect_rules_js~", + "aspect_rules_js+", "bazel_tools", "bazel_tools" ], [ - "bazel_features~", + "bazel_features+", "bazel_features_globals", - "bazel_features~~version_extension~bazel_features_globals" + "bazel_features++version_extension+bazel_features_globals" ], [ - "bazel_features~", + "bazel_features+", "bazel_features_version", - "bazel_features~~version_extension~bazel_features_version" + "bazel_features++version_extension+bazel_features_version" ], [ - "tar.bzl~", - "aspect_bazel_lib", - "aspect_bazel_lib~" + "bazel_lib+", + "bazel_skylib", + "bazel_skylib+" ], [ - "tar.bzl~", + "bazel_lib+", + "bazel_tools", + "bazel_tools" + ], + [ + "tar.bzl+", + "bazel_lib", + "bazel_lib+" + ], + [ + "tar.bzl+", "bazel_skylib", - "bazel_skylib~" + "bazel_skylib+" ], [ - "tar.bzl~", + "tar.bzl+", "tar.bzl", - "tar.bzl~" + "tar.bzl+" ] ] } }, - "@@aspect_rules_ts~//ts:extensions.bzl%ext": { + "@@aspect_rules_ts+//ts:extensions.bzl%ext": { "general": { - "bzlTransitiveDigest": "9IJp6IlB/FMHFBJe4MX/DQM4zi3oArC8yqYE/+NyPwk=", - "usagesDigest": "V/cnAeJuoOSXti/YIjg6+EA/7x3Pcs9RlVXNWKtaDsA=", + "bzlTransitiveDigest": "OZ78102C/XbBaTqKdjNxyU7R16xIAUJbbdqR+ficsVI=", + "usagesDigest": "zJ+HzhBw6wXwPyI47ZyrROfOAeSFiX6nutOB1ldKNT0=", "recordedFileInputs": { - "@@rules_browsers~//package.json": "84dc1ba9b1c667a25894e97218bd8f247d54f24bb694efb397a881be3c06a4c5" + "@@rules_browsers+//package.json": "84dc1ba9b1c667a25894e97218bd8f247d54f24bb694efb397a881be3c06a4c5" }, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "components_npm_typescript": { - "bzlFile": "@@aspect_rules_ts~//ts/private:npm_repositories.bzl", - "ruleClassName": "http_archive_version", + "repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version", "attributes": { "version": "5.9.2", "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", @@ -545,11 +573,10 @@ } }, "npm_rules_browsers_typescript": { - "bzlFile": "@@aspect_rules_ts~//ts/private:npm_repositories.bzl", - "ruleClassName": "http_archive_version", + "repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version", "attributes": { "version": "", - "version_from": "@@rules_browsers~//:package.json", + "version_from": "@@rules_browsers+//:package.json", "integrity": "", "urls": [ "https://registry.npmjs.org/typescript/-/typescript-{}.tgz" @@ -557,8 +584,7 @@ } }, "rules_angular_npm_typescript": { - "bzlFile": "@@aspect_rules_ts~//ts/private:npm_repositories.bzl", - "ruleClassName": "http_archive_version", + "repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version", "attributes": { "version": "5.9.2", "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", @@ -568,8 +594,7 @@ } }, "npm_typescript": { - "bzlFile": "@@aspect_rules_ts~//ts/private:npm_repositories.bzl", - "ruleClassName": "http_archive_version", + "repoRuleId": "@@aspect_rules_ts+//ts/private:npm_repositories.bzl%http_archive_version", "attributes": { "version": "5.9.3", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", @@ -581,78 +606,71 @@ }, "recordedRepoMappingEntries": [ [ - "aspect_rules_ts~", + "aspect_rules_ts+", "aspect_rules_ts", - "aspect_rules_ts~" - ], - [ - "aspect_rules_ts~", - "aspect_tools_telemetry_report", - "aspect_tools_telemetry~~telemetry~aspect_tools_telemetry_report" + "aspect_rules_ts+" ], [ - "aspect_rules_ts~", + "aspect_rules_ts+", "bazel_tools", "bazel_tools" ] ] } }, - "@@aspect_tools_telemetry~//:extension.bzl%telemetry": { + "@@aspect_tools_telemetry+//:extension.bzl%telemetry": { "general": { - "bzlTransitiveDigest": "gA7tPEdJXhskzPIEUxjX9IdDrM6+WjfbgXJ8Ez47umk=", - "usagesDigest": "iQKFO513wdLp8ePYECqwesGU0Ase6Q+uoj+I7R3Bcco=", + "bzlTransitiveDigest": "cl5A2O84vDL6Tt+Qga8FCj1DUDGqn+e7ly5rZ+4xvcc=", + "usagesDigest": "jIq82EcPVjOC/qQR0a9okIv+X01Vsy4H+a91u7xhCEA=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "aspect_tools_telemetry_report": { - "bzlFile": "@@aspect_tools_telemetry~//:extension.bzl", - "ruleClassName": "tel_repository", + "repoRuleId": "@@aspect_tools_telemetry+//:extension.bzl%tel_repository", "attributes": { "deps": { - "aspect_rules_js": "2.6.2", - "aspect_rules_esbuild": "0.23.0", - "aspect_rules_ts": "3.7.0", - "aspect_tools_telemetry": "0.2.8" + "aspect_rules_js": "2.8.3", + "aspect_rules_esbuild": "0.25.0", + "aspect_rules_jasmine": "2.0.2", + "aspect_rules_ts": "3.8.1", + "aspect_tools_telemetry": "0.3.3" } } } }, "recordedRepoMappingEntries": [ [ - "aspect_tools_telemetry~", - "aspect_bazel_lib", - "aspect_bazel_lib~" + "aspect_tools_telemetry+", + "bazel_lib", + "bazel_lib+" ], [ - "aspect_tools_telemetry~", + "aspect_tools_telemetry+", "bazel_skylib", - "bazel_skylib~" + "bazel_skylib+" ] ] } }, - "@@pybind11_bazel~//:python_configure.bzl%extension": { + "@@pybind11_bazel+//:python_configure.bzl%extension": { "general": { - "bzlTransitiveDigest": "whINYge95GgPtysKDbNHQ0ZlWYdtKybHs5y2tLF+x7Q=", - "usagesDigest": "gNvOHVcAlwgDsNXD0amkv2CC96mnaCThPQoE44y8K+w=", + "bzlTransitiveDigest": "4rSUGWibZDYLhHR+8eMwTNwAwdIv+xjVrtQ+gHtWHq4=", + "usagesDigest": "fycyB39YnXIJkfWCIXLUKJMZzANcuLy9ZE73hRucjFk=", "recordedFileInputs": { - "@@pybind11_bazel~//MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e" + "@@pybind11_bazel+//MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e" }, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "local_config_python": { - "bzlFile": "@@pybind11_bazel~//:python_configure.bzl", - "ruleClassName": "python_configure", + "repoRuleId": "@@pybind11_bazel+//:python_configure.bzl%python_configure", "attributes": {} }, "pybind11": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "build_file": "@@pybind11_bazel~//:pybind11.BUILD", + "build_file": "@@pybind11_bazel+//:pybind11.BUILD", "strip_prefix": "pybind11-2.11.1", "urls": [ "https://github.com/pybind/pybind11/archive/v2.11.1.zip" @@ -662,64 +680,60 @@ }, "recordedRepoMappingEntries": [ [ - "pybind11_bazel~", + "pybind11_bazel+", "bazel_tools", "bazel_tools" ] ] } }, - "@@rules_angular~//setup:extensions.bzl%rules_angular": { + "@@rules_angular+//setup:extensions.bzl%rules_angular": { "general": { "bzlTransitiveDigest": "fkaH7HMicL3g7/NDaFzlq39kcLopMyQ3KdbDn+5CRzA=", - "usagesDigest": "j/+xrVP2Fg9tqPsVh959PWNVX4TUn2I92d3qNs6FSC8=", + "usagesDigest": "rqqEVjxQ96set3CHBp1fQWOJEOXL24im9NxxILDpOq0=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "components_rules_angular_configurable_deps": { - "bzlFile": "@@rules_angular~//setup:repositories.bzl", - "ruleClassName": "configurable_deps_repo", + "repoRuleId": "@@rules_angular+//setup:repositories.bzl%configurable_deps_repo", "attributes": { - "angular_compiler_cli": "@@rules_angular~//:node_modules/@angular/compiler-cli", - "typescript": "@@rules_angular~//:node_modules/typescript" + "angular_compiler_cli": "@@rules_angular+//:node_modules/@angular/compiler-cli", + "typescript": "@@rules_angular+//:node_modules/typescript" } }, "rules_angular_configurable_deps": { - "bzlFile": "@@rules_angular~//setup:repositories.bzl", - "ruleClassName": "configurable_deps_repo", + "repoRuleId": "@@rules_angular+//setup:repositories.bzl%configurable_deps_repo", "attributes": { - "angular_compiler_cli": "@@rules_angular~//:node_modules/@angular/compiler-cli", - "typescript": "@@rules_angular~//:node_modules/typescript-local" + "angular_compiler_cli": "@@rules_angular+//:node_modules/@angular/compiler-cli", + "typescript": "@@rules_angular+//:node_modules/typescript-local" } }, "dev_infra_rules_angular_configurable_deps": { - "bzlFile": "@@rules_angular~//setup:repositories.bzl", - "ruleClassName": "configurable_deps_repo", + "repoRuleId": "@@rules_angular+//setup:repositories.bzl%configurable_deps_repo", "attributes": { - "angular_compiler_cli": "@@rules_angular~//:node_modules/@angular/compiler-cli", - "typescript": "@@rules_angular~//:node_modules/typescript" + "angular_compiler_cli": "@@rules_angular+//:node_modules/@angular/compiler-cli", + "typescript": "@@rules_angular+//:node_modules/typescript" } } }, "recordedRepoMappingEntries": [] } }, - "@@rules_browsers~//browsers:extensions.bzl%browsers": { + "@@rules_browsers+//browsers:extensions.bzl%browsers": { "general": { - "bzlTransitiveDigest": "6QMCx97Hwh2hyQPqZEA9AKAxbpygF41+K8xJfeqJYm8=", - "usagesDigest": "1PlExi+b77pSr2tAxFCVbpCtFoA7oixHabaL3dmas4Y=", + "bzlTransitiveDigest": "ljZlVgWkQJnI6EvlHVfYit2EttUE52gDTbvmota5YO8=", + "usagesDigest": "FS7q5WaIwg3KirS3njhuPFkTIBYvDaTInVGrlzu0XL8=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "rules_browsers_chrome_linux": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "4bc6d611d55dc96b213c8605cb8ac27d3c21973bf8b663df4cbf756c989e6745", + "sha256": "1419fa328bd7ea2697f26412ec693867516e4ef23c32eb13143a0b0b179b604b", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/linux64/chrome-headless-shell-linux64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/144.0.7531.0/linux64/chrome-headless-shell-linux64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-linux64/chrome-headless-shell" @@ -733,12 +747,11 @@ } }, "rules_browsers_chrome_mac": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "830cc2aafedbe7c9fe671c9898046f8900c06da89d12653ddc3ef26084d2f516", + "sha256": "792cbf9b77219b4476e41c49647bcd15e55f0988002fa1e4e6a720eb430c7eda", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/mac-x64/chrome-headless-shell-mac-x64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/144.0.7531.0/mac-x64/chrome-headless-shell-mac-x64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-x64/chrome-headless-shell" @@ -752,12 +765,11 @@ } }, "rules_browsers_chrome_mac_arm": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "5b5792f5c2d05c3f1f782346910869b61a37b9003f212315b19f4e46710cf8b9", + "sha256": "f0c1917769775e826dfa69936381d0d95b06fe67cf631ecd842380d5de0e4c7f", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/mac-arm64/chrome-headless-shell-mac-arm64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/144.0.7531.0/mac-arm64/chrome-headless-shell-mac-arm64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-mac-arm64/chrome-headless-shell" @@ -771,12 +783,11 @@ } }, "rules_browsers_chrome_win64": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "19bdbf6e1579b6c056b74709520ac9df573f4e80e4f026cc2360a29443cf6c0c", + "sha256": "6ce0f20dd743a804890f45f5349370e1aa7cd3ac3482c04686fcff5fafd01bb3", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/win64/chrome-headless-shell-win64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/144.0.7531.0/win64/chrome-headless-shell-win64.zip" ], "named_files": { "CHROME-HEADLESS-SHELL": "chrome-headless-shell-win64/chrome-headless-shell.exe" @@ -790,12 +801,11 @@ } }, "rules_browsers_chromedriver_linux": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "ea41e7a217d878c00e9d66a0724ff54be7d02d08adb7f6458b7d8487b6fbcd84", + "sha256": "baf4bf9d22881265487732f17d35a49e9aadd0837aa5c1c1eea520c8aa24a97f", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/linux64/chromedriver-linux64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/144.0.7531.0/linux64/chromedriver-linux64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-linux64/chromedriver" @@ -807,12 +817,11 @@ } }, "rules_browsers_chromedriver_mac": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "aede9b67301b930ff9c673df28429aa82ce05c105a4ccbef7e0cd30a97ae429d", + "sha256": "87560768d5aa203b37c0a1b8459a35b05e4ece54afee2df530f3bc33de4f63c5", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/mac-x64/chromedriver-mac-x64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/144.0.7531.0/mac-x64/chromedriver-mac-x64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-mac-x64/chromedriver" @@ -824,12 +833,11 @@ } }, "rules_browsers_chromedriver_mac_arm": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "5adf89a3e8edc6755920f4cfe2fe0515d40684878ef5201da5e02a9d491c4003", + "sha256": "99821795fa7c87eb92fb15248e23b237c83f397486d22ad9a10771622c36a5a0", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/mac-arm64/chromedriver-mac-arm64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/144.0.7531.0/mac-arm64/chromedriver-mac-arm64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-mac-arm64/chromedriver" @@ -841,12 +849,11 @@ } }, "rules_browsers_chromedriver_win64": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "a3dfe62b3e9e7a42bd324c07dcbbcc3a733a736b2a59f0e93b9250b88103ab73", + "sha256": "6e180e234a710c3cbf69566f64a662ed85473db6ae82275fd359f80ab288df99", "urls": [ - "https://storage.googleapis.com/chrome-for-testing-public/143.0.7482.0/win64/chromedriver-win64.zip" + "https://storage.googleapis.com/chrome-for-testing-public/144.0.7531.0/win64/chromedriver-win64.zip" ], "named_files": { "CHROMEDRIVER": "chromedriver-win64/chromedriver.exe" @@ -858,12 +865,11 @@ } }, "rules_browsers_firefox_linux": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "c66a48222ff67d51560240d321895c6926c9b3af345cbf688ced8517781d88d1", + "sha256": "00fb922cda6bab971e02bcbfb77923b0a234388ed7d77c23506ca0a1a61d4a86", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/144.0/linux-x86_64/en-US/firefox-144.0.tar.xz" + "https://archive.mozilla.org/pub/firefox/releases/145.0/linux-x86_64/en-US/firefox-145.0.tar.xz" ], "named_files": { "FIREFOX": "firefox/firefox" @@ -875,12 +881,11 @@ } }, "rules_browsers_firefox_mac": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "1e444b80921bc999d56c05a7decc1eaf88c0297cac5b90416299af2c77f5ecc9", + "sha256": "1c4556480deac8424049f3081a6de1e2c6de619bab3e8ce53e5a497b8d6d919e", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/144.0/mac/en-US/Firefox%20144.0.dmg" + "https://archive.mozilla.org/pub/firefox/releases/145.0/mac/en-US/Firefox%20145.0.dmg" ], "named_files": { "FIREFOX": "Firefox.app/Contents/MacOS/firefox" @@ -892,12 +897,11 @@ } }, "rules_browsers_firefox_mac_arm": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "1e444b80921bc999d56c05a7decc1eaf88c0297cac5b90416299af2c77f5ecc9", + "sha256": "1c4556480deac8424049f3081a6de1e2c6de619bab3e8ce53e5a497b8d6d919e", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/144.0/mac/en-US/Firefox%20144.0.dmg" + "https://archive.mozilla.org/pub/firefox/releases/145.0/mac/en-US/Firefox%20145.0.dmg" ], "named_files": { "FIREFOX": "Firefox.app/Contents/MacOS/firefox" @@ -909,12 +913,11 @@ } }, "rules_browsers_firefox_win64": { - "bzlFile": "@@rules_browsers~//browsers/private:browser_repo.bzl", - "ruleClassName": "browser_repo", + "repoRuleId": "@@rules_browsers+//browsers/private:browser_repo.bzl%browser_repo", "attributes": { - "sha256": "d1e8a7c061e25a41c8dfa85e3aee8e86e9263c69104d80906c978c8d0556563a", + "sha256": "4b0345c113242653d923b369fcbd48e3089c57658f8c1542f887c8a375d50306", "urls": [ - "https://archive.mozilla.org/pub/firefox/releases/144.0/win64/en-US/Firefox%20Setup%20144.0.exe" + "https://archive.mozilla.org/pub/firefox/releases/145.0/win64/en-US/Firefox%20Setup%20145.0.exe" ], "named_files": { "FIREFOX": "core/firefox.exe" @@ -929,17 +932,16 @@ "recordedRepoMappingEntries": [] } }, - "@@rules_fuzzing~//fuzzing/private:extensions.bzl%non_module_dependencies": { + "@@rules_fuzzing+//fuzzing/private:extensions.bzl%non_module_dependencies": { "general": { - "bzlTransitiveDigest": "hVgJRQ3Er45/UUAgNn1Yp2Khcp/Y8WyafA2kXIYmQ5M=", - "usagesDigest": "YnIrdgwnf3iCLfChsltBdZ7yOJh706lpa2vww/i2pDI=", + "bzlTransitiveDigest": "v2H25KPHEkN56IHR41S67Kzp5Xjxd75GBiazhON8jzc=", + "usagesDigest": "wy6ISK6UOcBEjj/mvJ/S3WeXoO67X+1llb9yPyFtPgc=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "platforms": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "urls": [ "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz", @@ -949,8 +951,7 @@ } }, "rules_python": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "sha256": "d70cd72a7a4880f0000a6346253414825c19cdd40a28289bdf67b8e6480edff8", "strip_prefix": "rules_python-0.28.0", @@ -958,8 +959,7 @@ } }, "bazel_skylib": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "sha256": "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94", "urls": [ @@ -969,8 +969,7 @@ } }, "com_google_absl": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "urls": [ "https://github.com/abseil/abseil-cpp/archive/refs/tags/20240116.1.zip" @@ -980,31 +979,27 @@ } }, "rules_fuzzing_oss_fuzz": { - "bzlFile": "@@rules_fuzzing~//fuzzing/private/oss_fuzz:repository.bzl", - "ruleClassName": "oss_fuzz_repository", + "repoRuleId": "@@rules_fuzzing+//fuzzing/private/oss_fuzz:repository.bzl%oss_fuzz_repository", "attributes": {} }, "honggfuzz": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "build_file": "@@rules_fuzzing~//:honggfuzz.BUILD", + "build_file": "@@rules_fuzzing+//:honggfuzz.BUILD", "sha256": "6b18ba13bc1f36b7b950c72d80f19ea67fbadc0ac0bb297ec89ad91f2eaa423e", "url": "https://github.com/google/honggfuzz/archive/2.5.zip", "strip_prefix": "honggfuzz-2.5" } }, "rules_fuzzing_jazzer": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_jar", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar", "attributes": { "sha256": "ee6feb569d88962d59cb59e8a31eb9d007c82683f3ebc64955fd5b96f277eec2", "url": "https://repo1.maven.org/maven2/com/code-intelligence/jazzer/0.20.1/jazzer-0.20.1.jar" } }, "rules_fuzzing_jazzer_api": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_jar", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar", "attributes": { "sha256": "f5a60242bc408f7fa20fccf10d6c5c5ea1fcb3c6f44642fec5af88373ae7aa1b", "url": "https://repo1.maven.org/maven2/com/code-intelligence/jazzer-api/0.20.1/jazzer-api-0.20.1.jar" @@ -1013,47 +1008,23 @@ }, "recordedRepoMappingEntries": [ [ - "rules_fuzzing~", - "bazel_tools", - "bazel_tools" - ] - ] - } - }, - "@@rules_java~//java:rules_java_deps.bzl%compatibility_proxy": { - "general": { - "bzlTransitiveDigest": "KIX40nDfygEWbU+rq3nYpt3tVgTK/iO8PKh5VMBlN7M=", - "usagesDigest": "pwHZ+26iLgQdwvdZeA5wnAjKnNI3y6XO2VbhOTeo5h8=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "compatibility_proxy": { - "bzlFile": "@@rules_java~//java:rules_java_deps.bzl", - "ruleClassName": "_compatibility_proxy_repo_rule", - "attributes": {} - } - }, - "recordedRepoMappingEntries": [ - [ - "rules_java~", + "rules_fuzzing+", "bazel_tools", "bazel_tools" ] ] } }, - "@@rules_kotlin~//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { "general": { - "bzlTransitiveDigest": "fus14IFJ/1LGWWGKPH/U18VnJCoMjfDt1ckahqCnM0A=", - "usagesDigest": "aJF6fLy82rR95Ff5CZPAqxNoFgOMLMN5ImfBS0nhnkg=", + "bzlTransitiveDigest": "OlvsB0HsvxbR8ZN+J9Vf00X/+WVz/Y/5Xrq2LgcVfdo=", + "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "com_github_jetbrains_kotlin_git": { - "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl", - "ruleClassName": "kotlin_compiler_git_repository", + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository", "attributes": { "urls": [ "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip" @@ -1062,16 +1033,14 @@ } }, "com_github_jetbrains_kotlin": { - "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl", - "ruleClassName": "kotlin_capabilities_repository", + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository", "attributes": { "git_repository_name": "com_github_jetbrains_kotlin_git", "compiler_version": "1.9.23" } }, "com_github_google_ksp": { - "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:ksp.bzl", - "ruleClassName": "ksp_compiler_plugin_repository", + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository", "attributes": { "urls": [ "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip" @@ -1081,8 +1050,7 @@ } }, "com_github_pinterest_ktlint": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file", "attributes": { "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985", "urls": [ @@ -1092,8 +1060,7 @@ } }, "rules_android": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806", "strip_prefix": "rules_android-0.1.1", @@ -1105,150 +1072,147 @@ }, "recordedRepoMappingEntries": [ [ - "rules_kotlin~", + "rules_kotlin+", "bazel_tools", "bazel_tools" ] ] } }, - "@@rules_nodejs~//nodejs:extensions.bzl%node": { + "@@rules_nodejs+//nodejs:extensions.bzl%node": { "general": { - "bzlTransitiveDigest": "FmfMiNXAxRoLWw3NloQbssosE1egrSvzirbQnso7j7E=", - "usagesDigest": "dMNT+qiygolcxk3T1nFST159tXO2wdWnMeeer3WBWnY=", + "bzlTransitiveDigest": "NwcLXHrbh2hoorA/Ybmcpjxsn/6avQmewDglodkDrgo=", + "usagesDigest": "7mqNH72MiuYZdoclnNM0WJiUJ1uOsw8XYY1VIXvrn+Y=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "nodejs_linux_amd64": { - "bzlFile": "@@rules_nodejs~//nodejs:repositories.bzl", - "ruleClassName": "_nodejs_repositories", + "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, "node_repositories": {}, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "22.12.0", + "node_version": "20.19.5", + "node_version_from_nvmrc": "@@//:.nvmrc", "include_headers": false, "platform": "linux_amd64" } }, "nodejs_linux_arm64": { - "bzlFile": "@@rules_nodejs~//nodejs:repositories.bzl", - "ruleClassName": "_nodejs_repositories", + "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, "node_repositories": {}, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "22.12.0", + "node_version": "20.19.5", + "node_version_from_nvmrc": "@@//:.nvmrc", "include_headers": false, "platform": "linux_arm64" } }, "nodejs_linux_s390x": { - "bzlFile": "@@rules_nodejs~//nodejs:repositories.bzl", - "ruleClassName": "_nodejs_repositories", + "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, "node_repositories": {}, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "22.12.0", + "node_version": "20.19.5", + "node_version_from_nvmrc": "@@//:.nvmrc", "include_headers": false, "platform": "linux_s390x" } }, "nodejs_linux_ppc64le": { - "bzlFile": "@@rules_nodejs~//nodejs:repositories.bzl", - "ruleClassName": "_nodejs_repositories", + "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, "node_repositories": {}, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "22.12.0", + "node_version": "20.19.5", + "node_version_from_nvmrc": "@@//:.nvmrc", "include_headers": false, "platform": "linux_ppc64le" } }, "nodejs_darwin_amd64": { - "bzlFile": "@@rules_nodejs~//nodejs:repositories.bzl", - "ruleClassName": "_nodejs_repositories", + "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, "node_repositories": {}, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "22.12.0", + "node_version": "20.19.5", + "node_version_from_nvmrc": "@@//:.nvmrc", "include_headers": false, "platform": "darwin_amd64" } }, "nodejs_darwin_arm64": { - "bzlFile": "@@rules_nodejs~//nodejs:repositories.bzl", - "ruleClassName": "_nodejs_repositories", + "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, "node_repositories": {}, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "22.12.0", + "node_version": "20.19.5", + "node_version_from_nvmrc": "@@//:.nvmrc", "include_headers": false, "platform": "darwin_arm64" } }, "nodejs_windows_amd64": { - "bzlFile": "@@rules_nodejs~//nodejs:repositories.bzl", - "ruleClassName": "_nodejs_repositories", + "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, "node_repositories": {}, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "22.12.0", + "node_version": "20.19.5", + "node_version_from_nvmrc": "@@//:.nvmrc", "include_headers": false, "platform": "windows_amd64" } }, "nodejs_windows_arm64": { - "bzlFile": "@@rules_nodejs~//nodejs:repositories.bzl", - "ruleClassName": "_nodejs_repositories", + "repoRuleId": "@@rules_nodejs+//nodejs:repositories.bzl%_nodejs_repositories", "attributes": { "node_download_auth": {}, "node_repositories": {}, "node_urls": [ "https://nodejs.org/dist/v{version}/{filename}" ], - "node_version": "22.12.0", + "node_version": "20.19.5", + "node_version_from_nvmrc": "@@//:.nvmrc", "include_headers": false, "platform": "windows_arm64" } }, "nodejs": { - "bzlFile": "@@rules_nodejs~//nodejs/private:nodejs_repo_host_os_alias.bzl", - "ruleClassName": "nodejs_repo_host_os_alias", + "repoRuleId": "@@rules_nodejs+//nodejs/private:nodejs_repo_host_os_alias.bzl%nodejs_repo_host_os_alias", "attributes": { "user_node_repository_name": "nodejs" } }, "nodejs_host": { - "bzlFile": "@@rules_nodejs~//nodejs/private:nodejs_repo_host_os_alias.bzl", - "ruleClassName": "nodejs_repo_host_os_alias", + "repoRuleId": "@@rules_nodejs+//nodejs/private:nodejs_repo_host_os_alias.bzl%nodejs_repo_host_os_alias", "attributes": { "user_node_repository_name": "nodejs" } }, "nodejs_toolchains": { - "bzlFile": "@@rules_nodejs~//nodejs/private:nodejs_toolchains_repo.bzl", - "ruleClassName": "nodejs_toolchains_repo", + "repoRuleId": "@@rules_nodejs+//nodejs/private:nodejs_toolchains_repo.bzl%nodejs_toolchains_repo", "attributes": { "user_node_repository_name": "nodejs" } @@ -1257,16 +1221,16 @@ "recordedRepoMappingEntries": [] } }, - "@@rules_python~//python/extensions:pip.bzl%pip": { + "@@rules_python+//python/extensions:pip.bzl%pip": { "general": { - "bzlTransitiveDigest": "sQcIxpGBMBOMzUZK9ARAkAR7oUiEiGgKZhHLEf9Prfk=", - "usagesDigest": "MKs5B778/fEkKhBaxuBt3oCCW+wPRuh2AxtITF8AMSU=", + "bzlTransitiveDigest": "k4yH+pmbTp1up4vf3Ew6RCqsUBcBaBznUiFqEh8KtZ4=", + "usagesDigest": "/9NP3RV6/DWuNdYAsIU/8UCgCX0TdPUJr0X6O+0lrtk=", "recordedFileInputs": { - "@@rules_python~//tools/publish/requirements_linux.txt": "8175b4c8df50ae2f22d1706961884beeb54e7da27bd2447018314a175981997d", - "@@rules_fuzzing~//fuzzing/requirements.txt": "ab04664be026b632a0d2a2446c4f65982b7654f5b6851d2f9d399a19b7242a5b", - "@@rules_python~//tools/publish/requirements_windows.txt": "7673adc71dc1a81d3661b90924d7a7c0fc998cd508b3cb4174337cef3f2de556", - "@@protobuf~//python/requirements.txt": "983be60d3cec4b319dcab6d48aeb3f5b2f7c3350f26b3a9e97486c37967c73c5", - "@@rules_python~//tools/publish/requirements_darwin.txt": "2994136eab7e57b083c3de76faf46f70fad130bc8e7360a7fed2b288b69e79dc" + "@@protobuf+//python/requirements.txt": "983be60d3cec4b319dcab6d48aeb3f5b2f7c3350f26b3a9e97486c37967c73c5", + "@@rules_fuzzing+//fuzzing/requirements.txt": "ab04664be026b632a0d2a2446c4f65982b7654f5b6851d2f9d399a19b7242a5b", + "@@rules_python+//tools/publish/requirements_darwin.txt": "2994136eab7e57b083c3de76faf46f70fad130bc8e7360a7fed2b288b69e79dc", + "@@rules_python+//tools/publish/requirements_linux.txt": "8175b4c8df50ae2f22d1706961884beeb54e7da27bd2447018314a175981997d", + "@@rules_python+//tools/publish/requirements_windows.txt": "7673adc71dc1a81d3661b90924d7a7c0fc998cd508b3cb4174337cef3f2de556" }, "recordedDirentsInputs": {}, "envVariables": { @@ -1275,238 +1239,217 @@ }, "generatedRepoSpecs": { "pip_deps_310_numpy": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@pip_deps//{name}:{target}", - "python_interpreter_target": "@@rules_python~~python~python_3_10_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_10_host//:python", "repo": "pip_deps_310", "requirement": "numpy<=1.26.1" } }, "pip_deps_310_setuptools": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@pip_deps//{name}:{target}", - "python_interpreter_target": "@@rules_python~~python~python_3_10_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_10_host//:python", "repo": "pip_deps_310", "requirement": "setuptools<=70.3.0" } }, "pip_deps_311_numpy": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@pip_deps//{name}:{target}", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "pip_deps_311", "requirement": "numpy<=1.26.1" } }, "pip_deps_311_setuptools": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@pip_deps//{name}:{target}", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "pip_deps_311", "requirement": "setuptools<=70.3.0" } }, "pip_deps_312_numpy": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@pip_deps//{name}:{target}", - "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_12_host//:python", "repo": "pip_deps_312", "requirement": "numpy<=1.26.1" } }, "pip_deps_312_setuptools": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@pip_deps//{name}:{target}", - "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_12_host//:python", "repo": "pip_deps_312", "requirement": "setuptools<=70.3.0" } }, "pip_deps_38_numpy": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@pip_deps//{name}:{target}", - "python_interpreter_target": "@@rules_python~~python~python_3_8_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_8_host//:python", "repo": "pip_deps_38", "requirement": "numpy<=1.26.1" } }, "pip_deps_38_setuptools": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@pip_deps//{name}:{target}", - "python_interpreter_target": "@@rules_python~~python~python_3_8_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_8_host//:python", "repo": "pip_deps_38", "requirement": "setuptools<=70.3.0" } }, "pip_deps_39_numpy": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@pip_deps//{name}:{target}", - "python_interpreter_target": "@@rules_python~~python~python_3_9_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_9_host//:python", "repo": "pip_deps_39", "requirement": "numpy<=1.26.1" } }, "pip_deps_39_setuptools": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@pip_deps//{name}:{target}", - "python_interpreter_target": "@@rules_python~~python~python_3_9_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_9_host//:python", "repo": "pip_deps_39", "requirement": "setuptools<=70.3.0" } }, "rules_fuzzing_py_deps_310_absl_py": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_fuzzing_py_deps//{name}:{target}", "extra_pip_args": [ "--require-hashes" ], - "python_interpreter_target": "@@rules_python~~python~python_3_10_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_10_host//:python", "repo": "rules_fuzzing_py_deps_310", "requirement": "absl-py==2.0.0 --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3" } }, "rules_fuzzing_py_deps_310_six": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_fuzzing_py_deps//{name}:{target}", "extra_pip_args": [ "--require-hashes" ], - "python_interpreter_target": "@@rules_python~~python~python_3_10_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_10_host//:python", "repo": "rules_fuzzing_py_deps_310", "requirement": "six==1.16.0 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" } }, "rules_fuzzing_py_deps_311_absl_py": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_fuzzing_py_deps//{name}:{target}", "extra_pip_args": [ "--require-hashes" ], - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_fuzzing_py_deps_311", "requirement": "absl-py==2.0.0 --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3" } }, "rules_fuzzing_py_deps_311_six": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_fuzzing_py_deps//{name}:{target}", "extra_pip_args": [ "--require-hashes" ], - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_fuzzing_py_deps_311", "requirement": "six==1.16.0 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" } }, "rules_fuzzing_py_deps_312_absl_py": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_fuzzing_py_deps//{name}:{target}", "extra_pip_args": [ "--require-hashes" ], - "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_12_host//:python", "repo": "rules_fuzzing_py_deps_312", "requirement": "absl-py==2.0.0 --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3" } }, "rules_fuzzing_py_deps_312_six": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_fuzzing_py_deps//{name}:{target}", "extra_pip_args": [ "--require-hashes" ], - "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_12_host//:python", "repo": "rules_fuzzing_py_deps_312", "requirement": "six==1.16.0 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" } }, "rules_fuzzing_py_deps_38_absl_py": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_fuzzing_py_deps//{name}:{target}", "extra_pip_args": [ "--require-hashes" ], - "python_interpreter_target": "@@rules_python~~python~python_3_8_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_8_host//:python", "repo": "rules_fuzzing_py_deps_38", "requirement": "absl-py==2.0.0 --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3" } }, "rules_fuzzing_py_deps_38_six": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_fuzzing_py_deps//{name}:{target}", "extra_pip_args": [ "--require-hashes" ], - "python_interpreter_target": "@@rules_python~~python~python_3_8_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_8_host//:python", "repo": "rules_fuzzing_py_deps_38", "requirement": "six==1.16.0 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" } }, "rules_fuzzing_py_deps_39_absl_py": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_fuzzing_py_deps//{name}:{target}", "extra_pip_args": [ "--require-hashes" ], - "python_interpreter_target": "@@rules_python~~python~python_3_9_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_9_host//:python", "repo": "rules_fuzzing_py_deps_39", "requirement": "absl-py==2.0.0 --hash=sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3" } }, "rules_fuzzing_py_deps_39_six": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_fuzzing_py_deps//{name}:{target}", "extra_pip_args": [ "--require-hashes" ], - "python_interpreter_target": "@@rules_python~~python~python_3_9_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_9_host//:python", "repo": "rules_fuzzing_py_deps_39", "requirement": "six==1.16.0 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" } }, "rules_python_publish_deps_311_backports_tarfile_py3_none_any_77e284d7": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1520,7 +1463,7 @@ "cp311_windows_x86_64" ], "filename": "backports.tarfile-1.2.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "backports-tarfile==1.2.0", "sha256": "77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", @@ -1530,8 +1473,7 @@ } }, "rules_python_publish_deps_311_backports_tarfile_sdist_d75e02c2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1549,7 +1491,7 @@ "https://pypi.org/simple" ], "filename": "backports_tarfile-1.2.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "backports-tarfile==1.2.0", "sha256": "d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991", @@ -1559,8 +1501,7 @@ } }, "rules_python_publish_deps_311_certifi_py3_none_any_922820b5": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1574,7 +1515,7 @@ "cp311_windows_x86_64" ], "filename": "certifi-2024.8.30-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "certifi==2024.8.30", "sha256": "922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", @@ -1584,8 +1525,7 @@ } }, "rules_python_publish_deps_311_certifi_sdist_bec941d2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1603,7 +1543,7 @@ "https://pypi.org/simple" ], "filename": "certifi-2024.8.30.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "certifi==2024.8.30", "sha256": "bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", @@ -1613,8 +1553,7 @@ } }, "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_aarch64_a1ed2dd2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1625,7 +1564,7 @@ "cp311_linux_x86_64" ], "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cffi==1.17.1", "sha256": "a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", @@ -1635,8 +1574,7 @@ } }, "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_ppc64le_46bf4316": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1647,7 +1585,7 @@ "cp311_linux_x86_64" ], "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cffi==1.17.1", "sha256": "46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", @@ -1657,8 +1595,7 @@ } }, "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_s390x_a24ed04c": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1669,7 +1606,7 @@ "cp311_linux_x86_64" ], "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cffi==1.17.1", "sha256": "a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", @@ -1679,8 +1616,7 @@ } }, "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_x86_64_610faea7": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1691,7 +1627,7 @@ "cp311_linux_x86_64" ], "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cffi==1.17.1", "sha256": "610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", @@ -1701,8 +1637,7 @@ } }, "rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_aarch64_a9b15d49": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1713,7 +1648,7 @@ "cp311_linux_x86_64" ], "filename": "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cffi==1.17.1", "sha256": "a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", @@ -1723,8 +1658,7 @@ } }, "rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_x86_64_fc48c783": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1735,7 +1669,7 @@ "cp311_linux_x86_64" ], "filename": "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cffi==1.17.1", "sha256": "fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", @@ -1745,8 +1679,7 @@ } }, "rules_python_publish_deps_311_cffi_sdist_1c39c601": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1761,7 +1694,7 @@ "https://pypi.org/simple" ], "filename": "cffi-1.17.1.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cffi==1.17.1", "sha256": "1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", @@ -1771,8 +1704,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_universal2_0d99dd8f": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1786,7 +1718,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", @@ -1796,8 +1728,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_x86_64_c57516e5": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1811,7 +1742,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", @@ -1821,8 +1752,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_11_0_arm64_6dba5d19": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1836,7 +1766,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", @@ -1846,8 +1776,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_aarch64_bf4475b8": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1861,7 +1790,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", @@ -1871,8 +1800,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_ppc64le_ce031db0": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1886,7 +1814,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", @@ -1896,8 +1824,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_s390x_8ff4e7cd": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1911,7 +1838,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", @@ -1921,8 +1848,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_x86_64_3710a975": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1936,7 +1862,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", @@ -1946,8 +1872,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_aarch64_47334db7": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1961,7 +1886,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", @@ -1971,8 +1896,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_ppc64le_f1a2f519": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -1986,7 +1910,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", @@ -1996,8 +1920,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_s390x_63bc5c4a": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2011,7 +1934,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", @@ -2021,8 +1944,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_x86_64_bcb4f8ea": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2036,7 +1958,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", @@ -2046,8 +1968,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_win_amd64_cee4373f": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2061,7 +1982,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", @@ -2071,8 +1992,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_py3_none_any_fe9f97fe": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2086,7 +2006,7 @@ "cp311_windows_x86_64" ], "filename": "charset_normalizer-3.4.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", @@ -2096,8 +2016,7 @@ } }, "rules_python_publish_deps_311_charset_normalizer_sdist_223217c3": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2115,7 +2034,7 @@ "https://pypi.org/simple" ], "filename": "charset_normalizer-3.4.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "charset-normalizer==3.4.0", "sha256": "223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", @@ -2125,8 +2044,7 @@ } }, "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_aarch64_846da004": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2137,7 +2055,7 @@ "cp311_linux_x86_64" ], "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cryptography==43.0.3", "sha256": "846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", @@ -2147,8 +2065,7 @@ } }, "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_x86_64_0f996e72": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2159,7 +2076,7 @@ "cp311_linux_x86_64" ], "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cryptography==43.0.3", "sha256": "0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", @@ -2169,8 +2086,7 @@ } }, "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_aarch64_f7b178f1": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2181,7 +2097,7 @@ "cp311_linux_x86_64" ], "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cryptography==43.0.3", "sha256": "f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", @@ -2191,8 +2107,7 @@ } }, "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_x86_64_c2e6fc39": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2203,7 +2118,7 @@ "cp311_linux_x86_64" ], "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cryptography==43.0.3", "sha256": "c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", @@ -2213,8 +2128,7 @@ } }, "rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_aarch64_e1be4655": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2225,7 +2139,7 @@ "cp311_linux_x86_64" ], "filename": "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cryptography==43.0.3", "sha256": "e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", @@ -2235,8 +2149,7 @@ } }, "rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_x86_64_df6b6c6d": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2247,7 +2160,7 @@ "cp311_linux_x86_64" ], "filename": "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cryptography==43.0.3", "sha256": "df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", @@ -2257,8 +2170,7 @@ } }, "rules_python_publish_deps_311_cryptography_sdist_315b9001": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2273,7 +2185,7 @@ "https://pypi.org/simple" ], "filename": "cryptography-43.0.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "cryptography==43.0.3", "sha256": "315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", @@ -2283,8 +2195,7 @@ } }, "rules_python_publish_deps_311_docutils_py3_none_any_dafca5b9": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2298,7 +2209,7 @@ "cp311_windows_x86_64" ], "filename": "docutils-0.21.2-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "docutils==0.21.2", "sha256": "dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", @@ -2308,8 +2219,7 @@ } }, "rules_python_publish_deps_311_docutils_sdist_3a6b1873": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2327,7 +2237,7 @@ "https://pypi.org/simple" ], "filename": "docutils-0.21.2.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "docutils==0.21.2", "sha256": "3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", @@ -2337,8 +2247,7 @@ } }, "rules_python_publish_deps_311_idna_py3_none_any_946d195a": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2352,7 +2261,7 @@ "cp311_windows_x86_64" ], "filename": "idna-3.10-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "idna==3.10", "sha256": "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", @@ -2362,8 +2271,7 @@ } }, "rules_python_publish_deps_311_idna_sdist_12f65c9b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2381,7 +2289,7 @@ "https://pypi.org/simple" ], "filename": "idna-3.10.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "idna==3.10", "sha256": "12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", @@ -2391,8 +2299,7 @@ } }, "rules_python_publish_deps_311_importlib_metadata_py3_none_any_45e54197": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2406,7 +2313,7 @@ "cp311_windows_x86_64" ], "filename": "importlib_metadata-8.5.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "importlib-metadata==8.5.0", "sha256": "45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", @@ -2416,8 +2323,7 @@ } }, "rules_python_publish_deps_311_importlib_metadata_sdist_71522656": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2435,7 +2341,7 @@ "https://pypi.org/simple" ], "filename": "importlib_metadata-8.5.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "importlib-metadata==8.5.0", "sha256": "71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", @@ -2445,8 +2351,7 @@ } }, "rules_python_publish_deps_311_jaraco_classes_py3_none_any_f662826b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2460,7 +2365,7 @@ "cp311_windows_x86_64" ], "filename": "jaraco.classes-3.4.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "jaraco-classes==3.4.0", "sha256": "f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", @@ -2470,8 +2375,7 @@ } }, "rules_python_publish_deps_311_jaraco_classes_sdist_47a024b5": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2489,7 +2393,7 @@ "https://pypi.org/simple" ], "filename": "jaraco.classes-3.4.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "jaraco-classes==3.4.0", "sha256": "47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", @@ -2499,8 +2403,7 @@ } }, "rules_python_publish_deps_311_jaraco_context_py3_none_any_f797fc48": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2514,7 +2417,7 @@ "cp311_windows_x86_64" ], "filename": "jaraco.context-6.0.1-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "jaraco-context==6.0.1", "sha256": "f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4", @@ -2524,8 +2427,7 @@ } }, "rules_python_publish_deps_311_jaraco_context_sdist_9bae4ea5": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2543,7 +2445,7 @@ "https://pypi.org/simple" ], "filename": "jaraco_context-6.0.1.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "jaraco-context==6.0.1", "sha256": "9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", @@ -2553,8 +2455,7 @@ } }, "rules_python_publish_deps_311_jaraco_functools_py3_none_any_ad159f13": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2568,7 +2469,7 @@ "cp311_windows_x86_64" ], "filename": "jaraco.functools-4.1.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "jaraco-functools==4.1.0", "sha256": "ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649", @@ -2578,8 +2479,7 @@ } }, "rules_python_publish_deps_311_jaraco_functools_sdist_70f7e0e2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2597,7 +2497,7 @@ "https://pypi.org/simple" ], "filename": "jaraco_functools-4.1.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "jaraco-functools==4.1.0", "sha256": "70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", @@ -2607,8 +2507,7 @@ } }, "rules_python_publish_deps_311_jeepney_py3_none_any_c0a454ad": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2619,7 +2518,7 @@ "cp311_linux_x86_64" ], "filename": "jeepney-0.8.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "jeepney==0.8.0", "sha256": "c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755", @@ -2629,8 +2528,7 @@ } }, "rules_python_publish_deps_311_jeepney_sdist_5efe48d2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2645,7 +2543,7 @@ "https://pypi.org/simple" ], "filename": "jeepney-0.8.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "jeepney==0.8.0", "sha256": "5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806", @@ -2655,8 +2553,7 @@ } }, "rules_python_publish_deps_311_keyring_py3_none_any_5426f817": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2670,7 +2567,7 @@ "cp311_windows_x86_64" ], "filename": "keyring-25.4.1-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "keyring==25.4.1", "sha256": "5426f817cf7f6f007ba5ec722b1bcad95a75b27d780343772ad76b17cb47b0bf", @@ -2680,8 +2577,7 @@ } }, "rules_python_publish_deps_311_keyring_sdist_b07ebc55": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2699,7 +2595,7 @@ "https://pypi.org/simple" ], "filename": "keyring-25.4.1.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "keyring==25.4.1", "sha256": "b07ebc55f3e8ed86ac81dd31ef14e81ace9dd9c3d4b5d77a6e9a2016d0d71a1b", @@ -2709,8 +2605,7 @@ } }, "rules_python_publish_deps_311_markdown_it_py_py3_none_any_35521684": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2724,7 +2619,7 @@ "cp311_windows_x86_64" ], "filename": "markdown_it_py-3.0.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "markdown-it-py==3.0.0", "sha256": "355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", @@ -2734,8 +2629,7 @@ } }, "rules_python_publish_deps_311_markdown_it_py_sdist_e3f60a94": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2753,7 +2647,7 @@ "https://pypi.org/simple" ], "filename": "markdown-it-py-3.0.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "markdown-it-py==3.0.0", "sha256": "e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", @@ -2763,8 +2657,7 @@ } }, "rules_python_publish_deps_311_mdurl_py3_none_any_84008a41": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2778,7 +2671,7 @@ "cp311_windows_x86_64" ], "filename": "mdurl-0.1.2-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "mdurl==0.1.2", "sha256": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", @@ -2788,8 +2681,7 @@ } }, "rules_python_publish_deps_311_mdurl_sdist_bb413d29": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2807,7 +2699,7 @@ "https://pypi.org/simple" ], "filename": "mdurl-0.1.2.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "mdurl==0.1.2", "sha256": "bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", @@ -2817,8 +2709,7 @@ } }, "rules_python_publish_deps_311_more_itertools_py3_none_any_037b0d32": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2832,7 +2723,7 @@ "cp311_windows_x86_64" ], "filename": "more_itertools-10.5.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "more-itertools==10.5.0", "sha256": "037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", @@ -2842,8 +2733,7 @@ } }, "rules_python_publish_deps_311_more_itertools_sdist_5482bfef": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2861,7 +2751,7 @@ "https://pypi.org/simple" ], "filename": "more-itertools-10.5.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "more-itertools==10.5.0", "sha256": "5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6", @@ -2871,8 +2761,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_14c5a72e": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2886,7 +2775,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86", @@ -2896,8 +2785,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_7b7c2a3c": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2911,7 +2799,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811", @@ -2921,8 +2809,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_aarch64_42c64511": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2936,7 +2823,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200", @@ -2946,8 +2833,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_armv7l_0411beb0": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2961,7 +2847,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164", @@ -2971,8 +2857,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64_5f36b271": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -2986,7 +2871,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189", @@ -2996,8 +2881,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64le_34c03fa7": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3011,7 +2895,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad", @@ -3021,8 +2905,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_s390x_19aaba96": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3036,7 +2919,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b", @@ -3046,8 +2929,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_x86_64_de3ceed6": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3061,7 +2943,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307", @@ -3071,8 +2953,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_aarch64_f0eca9ca": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3086,7 +2967,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe", @@ -3096,8 +2977,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_armv7l_3a157ab1": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3111,7 +2991,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a", @@ -3121,8 +3001,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_x86_64_36c95d4b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3136,7 +3015,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204", @@ -3146,8 +3025,7 @@ } }, "rules_python_publish_deps_311_nh3_cp37_abi3_win_amd64_8ce0f819": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3161,7 +3039,7 @@ "cp311_windows_x86_64" ], "filename": "nh3-0.2.18-cp37-abi3-win_amd64.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844", @@ -3171,8 +3049,7 @@ } }, "rules_python_publish_deps_311_nh3_sdist_94a16692": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3190,7 +3067,7 @@ "https://pypi.org/simple" ], "filename": "nh3-0.2.18.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "nh3==0.2.18", "sha256": "94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4", @@ -3200,8 +3077,7 @@ } }, "rules_python_publish_deps_311_pkginfo_py3_none_any_889a6da2": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3215,7 +3091,7 @@ "cp311_windows_x86_64" ], "filename": "pkginfo-1.10.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "pkginfo==1.10.0", "sha256": "889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097", @@ -3225,8 +3101,7 @@ } }, "rules_python_publish_deps_311_pkginfo_sdist_5df73835": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3244,7 +3119,7 @@ "https://pypi.org/simple" ], "filename": "pkginfo-1.10.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "pkginfo==1.10.0", "sha256": "5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297", @@ -3254,8 +3129,7 @@ } }, "rules_python_publish_deps_311_pycparser_py3_none_any_c3702b6d": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3266,7 +3140,7 @@ "cp311_linux_x86_64" ], "filename": "pycparser-2.22-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "pycparser==2.22", "sha256": "c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", @@ -3276,8 +3150,7 @@ } }, "rules_python_publish_deps_311_pycparser_sdist_491c8be9": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3292,7 +3165,7 @@ "https://pypi.org/simple" ], "filename": "pycparser-2.22.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "pycparser==2.22", "sha256": "491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", @@ -3302,8 +3175,7 @@ } }, "rules_python_publish_deps_311_pygments_py3_none_any_b8e6aca0": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3317,7 +3189,7 @@ "cp311_windows_x86_64" ], "filename": "pygments-2.18.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "pygments==2.18.0", "sha256": "b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", @@ -3327,8 +3199,7 @@ } }, "rules_python_publish_deps_311_pygments_sdist_786ff802": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3346,7 +3217,7 @@ "https://pypi.org/simple" ], "filename": "pygments-2.18.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "pygments==2.18.0", "sha256": "786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", @@ -3356,15 +3227,14 @@ } }, "rules_python_publish_deps_311_pywin32_ctypes_py3_none_any_8a151337": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ "cp311_windows_x86_64" ], "filename": "pywin32_ctypes-0.2.3-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "pywin32-ctypes==0.2.3", "sha256": "8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", @@ -3374,8 +3244,7 @@ } }, "rules_python_publish_deps_311_pywin32_ctypes_sdist_d162dc04": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3386,7 +3255,7 @@ "https://pypi.org/simple" ], "filename": "pywin32-ctypes-0.2.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "pywin32-ctypes==0.2.3", "sha256": "d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", @@ -3396,8 +3265,7 @@ } }, "rules_python_publish_deps_311_readme_renderer_py3_none_any_2fbca89b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3411,7 +3279,7 @@ "cp311_windows_x86_64" ], "filename": "readme_renderer-44.0-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "readme-renderer==44.0", "sha256": "2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151", @@ -3421,8 +3289,7 @@ } }, "rules_python_publish_deps_311_readme_renderer_sdist_8712034e": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3440,7 +3307,7 @@ "https://pypi.org/simple" ], "filename": "readme_renderer-44.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "readme-renderer==44.0", "sha256": "8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1", @@ -3450,8 +3317,7 @@ } }, "rules_python_publish_deps_311_requests_py3_none_any_70761cfe": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3465,7 +3331,7 @@ "cp311_windows_x86_64" ], "filename": "requests-2.32.3-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "requests==2.32.3", "sha256": "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", @@ -3475,8 +3341,7 @@ } }, "rules_python_publish_deps_311_requests_sdist_55365417": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3494,7 +3359,7 @@ "https://pypi.org/simple" ], "filename": "requests-2.32.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "requests==2.32.3", "sha256": "55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", @@ -3504,8 +3369,7 @@ } }, "rules_python_publish_deps_311_requests_toolbelt_py2_none_any_cccfdd66": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3519,7 +3383,7 @@ "cp311_windows_x86_64" ], "filename": "requests_toolbelt-1.0.0-py2.py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "requests-toolbelt==1.0.0", "sha256": "cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", @@ -3529,8 +3393,7 @@ } }, "rules_python_publish_deps_311_requests_toolbelt_sdist_7681a0a3": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3548,7 +3411,7 @@ "https://pypi.org/simple" ], "filename": "requests-toolbelt-1.0.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "requests-toolbelt==1.0.0", "sha256": "7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", @@ -3558,8 +3421,7 @@ } }, "rules_python_publish_deps_311_rfc3986_py2_none_any_50b1502b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3573,7 +3435,7 @@ "cp311_windows_x86_64" ], "filename": "rfc3986-2.0.0-py2.py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "rfc3986==2.0.0", "sha256": "50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", @@ -3583,8 +3445,7 @@ } }, "rules_python_publish_deps_311_rfc3986_sdist_97aacf9d": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3602,7 +3463,7 @@ "https://pypi.org/simple" ], "filename": "rfc3986-2.0.0.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "rfc3986==2.0.0", "sha256": "97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c", @@ -3612,8 +3473,7 @@ } }, "rules_python_publish_deps_311_rich_py3_none_any_9836f509": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3627,7 +3487,7 @@ "cp311_windows_x86_64" ], "filename": "rich-13.9.3-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "rich==13.9.3", "sha256": "9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283", @@ -3637,8 +3497,7 @@ } }, "rules_python_publish_deps_311_rich_sdist_bc1e01b8": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3656,7 +3515,7 @@ "https://pypi.org/simple" ], "filename": "rich-13.9.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "rich==13.9.3", "sha256": "bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e", @@ -3666,8 +3525,7 @@ } }, "rules_python_publish_deps_311_secretstorage_py3_none_any_f356e662": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3678,7 +3536,7 @@ "cp311_linux_x86_64" ], "filename": "SecretStorage-3.3.3-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "secretstorage==3.3.3", "sha256": "f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99", @@ -3688,8 +3546,7 @@ } }, "rules_python_publish_deps_311_secretstorage_sdist_2403533e": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3704,7 +3561,7 @@ "https://pypi.org/simple" ], "filename": "SecretStorage-3.3.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "secretstorage==3.3.3", "sha256": "2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", @@ -3714,8 +3571,7 @@ } }, "rules_python_publish_deps_311_twine_py3_none_any_215dbe7b": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3729,7 +3585,7 @@ "cp311_windows_x86_64" ], "filename": "twine-5.1.1-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "twine==5.1.1", "sha256": "215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997", @@ -3739,8 +3595,7 @@ } }, "rules_python_publish_deps_311_twine_sdist_9aa08251": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3758,7 +3613,7 @@ "https://pypi.org/simple" ], "filename": "twine-5.1.1.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "twine==5.1.1", "sha256": "9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db", @@ -3768,8 +3623,7 @@ } }, "rules_python_publish_deps_311_urllib3_py3_none_any_ca899ca0": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3783,7 +3637,7 @@ "cp311_windows_x86_64" ], "filename": "urllib3-2.2.3-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "urllib3==2.2.3", "sha256": "ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", @@ -3793,8 +3647,7 @@ } }, "rules_python_publish_deps_311_urllib3_sdist_e7d814a8": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3812,7 +3665,7 @@ "https://pypi.org/simple" ], "filename": "urllib3-2.2.3.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "urllib3==2.2.3", "sha256": "e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", @@ -3822,8 +3675,7 @@ } }, "rules_python_publish_deps_311_zipp_py3_none_any_a817ac80": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3837,7 +3689,7 @@ "cp311_windows_x86_64" ], "filename": "zipp-3.20.2-py3-none-any.whl", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "zipp==3.20.2", "sha256": "a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", @@ -3847,8 +3699,7 @@ } }, "rules_python_publish_deps_311_zipp_sdist_bc9eb26f": { - "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", - "ruleClassName": "whl_library", + "repoRuleId": "@@rules_python+//python/private/pypi:whl_library.bzl%whl_library", "attributes": { "dep_template": "@rules_python_publish_deps//{name}:{target}", "experimental_target_platforms": [ @@ -3866,7 +3717,7 @@ "https://pypi.org/simple" ], "filename": "zipp-3.20.2.tar.gz", - "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python", + "python_interpreter_target": "@@rules_python++python+python_3_11_host//:python", "repo": "rules_python_publish_deps_311", "requirement": "zipp==3.20.2", "sha256": "bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", @@ -3876,8 +3727,7 @@ } }, "pip_deps": { - "bzlFile": "@@rules_python~//python/private/pypi:hub_repository.bzl", - "ruleClassName": "hub_repository", + "repoRuleId": "@@rules_python+//python/private/pypi:hub_repository.bzl%hub_repository", "attributes": { "repo_name": "pip_deps", "extra_hub_aliases": {}, @@ -3893,8 +3743,7 @@ } }, "rules_fuzzing_py_deps": { - "bzlFile": "@@rules_python~//python/private/pypi:hub_repository.bzl", - "ruleClassName": "hub_repository", + "repoRuleId": "@@rules_python+//python/private/pypi:hub_repository.bzl%hub_repository", "attributes": { "repo_name": "rules_fuzzing_py_deps", "extra_hub_aliases": {}, @@ -3910,8 +3759,7 @@ } }, "rules_python_publish_deps": { - "bzlFile": "@@rules_python~//python/private/pypi:hub_repository.bzl", - "ruleClassName": "hub_repository", + "repoRuleId": "@@rules_python+//python/private/pypi:hub_repository.bzl%hub_repository", "attributes": { "repo_name": "rules_python_publish_deps", "extra_hub_aliases": {}, @@ -3983,149 +3831,148 @@ }, "recordedRepoMappingEntries": [ [ - "bazel_features~", + "bazel_features+", "bazel_features_globals", - "bazel_features~~version_extension~bazel_features_globals" + "bazel_features++version_extension+bazel_features_globals" ], [ - "bazel_features~", + "bazel_features+", "bazel_features_version", - "bazel_features~~version_extension~bazel_features_version" + "bazel_features++version_extension+bazel_features_version" ], [ - "rules_python~", + "rules_python+", "bazel_features", - "bazel_features~" + "bazel_features+" ], [ - "rules_python~", + "rules_python+", "bazel_skylib", - "bazel_skylib~" + "bazel_skylib+" ], [ - "rules_python~", + "rules_python+", "bazel_tools", "bazel_tools" ], [ - "rules_python~", + "rules_python+", "pypi__build", - "rules_python~~internal_deps~pypi__build" + "rules_python++internal_deps+pypi__build" ], [ - "rules_python~", + "rules_python+", "pypi__click", - "rules_python~~internal_deps~pypi__click" + "rules_python++internal_deps+pypi__click" ], [ - "rules_python~", + "rules_python+", "pypi__colorama", - "rules_python~~internal_deps~pypi__colorama" + "rules_python++internal_deps+pypi__colorama" ], [ - "rules_python~", + "rules_python+", "pypi__importlib_metadata", - "rules_python~~internal_deps~pypi__importlib_metadata" + "rules_python++internal_deps+pypi__importlib_metadata" ], [ - "rules_python~", + "rules_python+", "pypi__installer", - "rules_python~~internal_deps~pypi__installer" + "rules_python++internal_deps+pypi__installer" ], [ - "rules_python~", + "rules_python+", "pypi__more_itertools", - "rules_python~~internal_deps~pypi__more_itertools" + "rules_python++internal_deps+pypi__more_itertools" ], [ - "rules_python~", + "rules_python+", "pypi__packaging", - "rules_python~~internal_deps~pypi__packaging" + "rules_python++internal_deps+pypi__packaging" ], [ - "rules_python~", + "rules_python+", "pypi__pep517", - "rules_python~~internal_deps~pypi__pep517" + "rules_python++internal_deps+pypi__pep517" ], [ - "rules_python~", + "rules_python+", "pypi__pip", - "rules_python~~internal_deps~pypi__pip" + "rules_python++internal_deps+pypi__pip" ], [ - "rules_python~", + "rules_python+", "pypi__pip_tools", - "rules_python~~internal_deps~pypi__pip_tools" + "rules_python++internal_deps+pypi__pip_tools" ], [ - "rules_python~", + "rules_python+", "pypi__pyproject_hooks", - "rules_python~~internal_deps~pypi__pyproject_hooks" + "rules_python++internal_deps+pypi__pyproject_hooks" ], [ - "rules_python~", + "rules_python+", "pypi__setuptools", - "rules_python~~internal_deps~pypi__setuptools" + "rules_python++internal_deps+pypi__setuptools" ], [ - "rules_python~", + "rules_python+", "pypi__tomli", - "rules_python~~internal_deps~pypi__tomli" + "rules_python++internal_deps+pypi__tomli" ], [ - "rules_python~", + "rules_python+", "pypi__wheel", - "rules_python~~internal_deps~pypi__wheel" + "rules_python++internal_deps+pypi__wheel" ], [ - "rules_python~", + "rules_python+", "pypi__zipp", - "rules_python~~internal_deps~pypi__zipp" + "rules_python++internal_deps+pypi__zipp" ], [ - "rules_python~", + "rules_python+", "pythons_hub", - "rules_python~~python~pythons_hub" + "rules_python++python+pythons_hub" ], [ - "rules_python~~python~pythons_hub", + "rules_python++python+pythons_hub", "python_3_10_host", - "rules_python~~python~python_3_10_host" + "rules_python++python+python_3_10_host" ], [ - "rules_python~~python~pythons_hub", + "rules_python++python+pythons_hub", "python_3_11_host", - "rules_python~~python~python_3_11_host" + "rules_python++python+python_3_11_host" ], [ - "rules_python~~python~pythons_hub", + "rules_python++python+pythons_hub", "python_3_12_host", - "rules_python~~python~python_3_12_host" + "rules_python++python+python_3_12_host" ], [ - "rules_python~~python~pythons_hub", + "rules_python++python+pythons_hub", "python_3_8_host", - "rules_python~~python~python_3_8_host" + "rules_python++python+python_3_8_host" ], [ - "rules_python~~python~pythons_hub", + "rules_python++python+pythons_hub", "python_3_9_host", - "rules_python~~python~python_3_9_host" + "rules_python++python+python_3_9_host" ] ] } }, - "@@rules_sass~//src/toolchain:extensions.bzl%sass": { + "@@rules_sass+//src/toolchain:extensions.bzl%sass": { "general": { "bzlTransitiveDigest": "RA58Nyrsn03Z5YmQnpmBw3mqlVck++XIrx34amsqU/E=", - "usagesDigest": "FPXQ5+6+DFGdSdCMXLwFaruzstMFlLH6N0TRxi0sSH8=", + "usagesDigest": "R0KshhzIouLWuexMUCrl4HY+FUDwlVVgF9Z7UnwyUWA=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "linux_amd64_sass": { - "bzlFile": "@@rules_sass~//src/toolchain:configure_sass.bzl", - "ruleClassName": "configure_sass", + "repoRuleId": "@@rules_sass+//src/toolchain:configure_sass.bzl%configure_sass", "attributes": { "file": "@rules_sass//src/compiler/built:sass_linux_x64", "sha256": "", @@ -4136,8 +3983,7 @@ } }, "linux_arm64_sass": { - "bzlFile": "@@rules_sass~//src/toolchain:configure_sass.bzl", - "ruleClassName": "configure_sass", + "repoRuleId": "@@rules_sass+//src/toolchain:configure_sass.bzl%configure_sass", "attributes": { "file": "@rules_sass//src/compiler/built:sass_linux_arm", "sha256": "", @@ -4148,8 +3994,7 @@ } }, "darwin_amd64_sass": { - "bzlFile": "@@rules_sass~//src/toolchain:configure_sass.bzl", - "ruleClassName": "configure_sass", + "repoRuleId": "@@rules_sass+//src/toolchain:configure_sass.bzl%configure_sass", "attributes": { "file": "@rules_sass//src/compiler/built:sass_mac_x64", "sha256": "", @@ -4160,8 +4005,7 @@ } }, "darwin_arm64_sass": { - "bzlFile": "@@rules_sass~//src/toolchain:configure_sass.bzl", - "ruleClassName": "configure_sass", + "repoRuleId": "@@rules_sass+//src/toolchain:configure_sass.bzl%configure_sass", "attributes": { "file": "@rules_sass//src/compiler/built:sass_mac_arm", "sha256": "", @@ -4175,81 +4019,72 @@ "recordedRepoMappingEntries": [] } }, - "@@yq.bzl~//yq:extensions.bzl%yq": { + "@@yq.bzl+//yq:extensions.bzl%yq": { "general": { "bzlTransitiveDigest": "61Uz+o5PnlY0jJfPZEUNqsKxnM/UCLeWsn5VVCc8u5Y=", - "usagesDigest": "3Yefzt7ha1NB6ak4d2Xsxna4bkR35URwnEmIjuJOJbA=", + "usagesDigest": "d6fg0dBWZwXWFu5SLjcFy+tWZxMpARtKZldpwb6tlmI=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "yq_darwin_amd64": { - "bzlFile": "@@yq.bzl~//yq/toolchain:platforms.bzl", - "ruleClassName": "yq_platform_repo", + "repoRuleId": "@@yq.bzl+//yq/toolchain:platforms.bzl%yq_platform_repo", "attributes": { "platform": "darwin_amd64", "version": "4.45.1" } }, "yq_darwin_arm64": { - "bzlFile": "@@yq.bzl~//yq/toolchain:platforms.bzl", - "ruleClassName": "yq_platform_repo", + "repoRuleId": "@@yq.bzl+//yq/toolchain:platforms.bzl%yq_platform_repo", "attributes": { "platform": "darwin_arm64", "version": "4.45.1" } }, "yq_linux_amd64": { - "bzlFile": "@@yq.bzl~//yq/toolchain:platforms.bzl", - "ruleClassName": "yq_platform_repo", + "repoRuleId": "@@yq.bzl+//yq/toolchain:platforms.bzl%yq_platform_repo", "attributes": { "platform": "linux_amd64", "version": "4.45.1" } }, "yq_linux_arm64": { - "bzlFile": "@@yq.bzl~//yq/toolchain:platforms.bzl", - "ruleClassName": "yq_platform_repo", + "repoRuleId": "@@yq.bzl+//yq/toolchain:platforms.bzl%yq_platform_repo", "attributes": { "platform": "linux_arm64", "version": "4.45.1" } }, "yq_linux_s390x": { - "bzlFile": "@@yq.bzl~//yq/toolchain:platforms.bzl", - "ruleClassName": "yq_platform_repo", + "repoRuleId": "@@yq.bzl+//yq/toolchain:platforms.bzl%yq_platform_repo", "attributes": { "platform": "linux_s390x", "version": "4.45.1" } }, "yq_linux_riscv64": { - "bzlFile": "@@yq.bzl~//yq/toolchain:platforms.bzl", - "ruleClassName": "yq_platform_repo", + "repoRuleId": "@@yq.bzl+//yq/toolchain:platforms.bzl%yq_platform_repo", "attributes": { "platform": "linux_riscv64", "version": "4.45.1" } }, "yq_linux_ppc64le": { - "bzlFile": "@@yq.bzl~//yq/toolchain:platforms.bzl", - "ruleClassName": "yq_platform_repo", + "repoRuleId": "@@yq.bzl+//yq/toolchain:platforms.bzl%yq_platform_repo", "attributes": { "platform": "linux_ppc64le", "version": "4.45.1" } }, "yq_windows_amd64": { - "bzlFile": "@@yq.bzl~//yq/toolchain:platforms.bzl", - "ruleClassName": "yq_platform_repo", + "repoRuleId": "@@yq.bzl+//yq/toolchain:platforms.bzl%yq_platform_repo", "attributes": { "platform": "windows_amd64", "version": "4.45.1" } }, "yq_toolchains": { - "bzlFile": "@@yq.bzl~//yq/toolchain:toolchain.bzl", - "ruleClassName": "yq_toolchains_repo", + "repoRuleId": "@@yq.bzl+//yq/toolchain:toolchain.bzl%yq_toolchains_repo", "attributes": { "user_repository_name": "yq" } diff --git a/REPO.bazel b/REPO.bazel new file mode 100644 index 000000000000..a4d979963a93 --- /dev/null +++ b/REPO.bazel @@ -0,0 +1,9 @@ +ignore_directories([ + ".git", + "dist", + "integration/yarn-pnp-compat/.yarn/cache", + "integration/yarn-pnp-compat/.yarn/unplugged", + "integration/yarn-pnp-compat/.yarn/install-state.gz", + "**/.angular/**", + "**/node_modules/**", +]) diff --git a/docs/.nvmrc b/docs/.nvmrc index aa50a62f2194..5767036af0e2 100644 --- a/docs/.nvmrc +++ b/docs/.nvmrc @@ -1 +1 @@ -22.21.0 +22.21.1 diff --git a/docs/defs.bzl b/docs/defs.bzl index c02e5e57e0d5..aa9d3720a682 100644 --- a/docs/defs.bzl +++ b/docs/defs.bzl @@ -19,6 +19,7 @@ COMMON_CONFIG = [ # Project dependencies common across libs/tests DEPS = [ + "//docs:node_modules/zone.js", "//docs:node_modules/@angular/aria", "//docs:node_modules/@angular/cdk", "//docs:node_modules/@angular/cdk-experimental", @@ -36,7 +37,15 @@ APPLICATION_CONFIG = COMMON_CONFIG + [ TEST_DEPS = [ "@rules_browsers//browsers/chromium", "@rules_browsers//browsers/firefox", + "//docs:node_modules/@types/jasmine", + "//docs:node_modules/@types/node", + "//docs:node_modules/jasmine-core", + "//docs:node_modules/karma", + "//docs:node_modules/karma-chrome-launcher", + "//docs:node_modules/karma-coverage", "//docs:node_modules/karma-firefox-launcher", + "//docs:node_modules/karma-jasmine", + "//docs:node_modules/karma-jasmine-html-reporter", ] # Common dependencies of Angular CLI test suites diff --git a/docs/src/app/pages/component-category-list/component-category-list.html b/docs/src/app/pages/component-category-list/component-category-list.html index 3c0ea17085c0..5e3ec2b9efae 100644 --- a/docs/src/app/pages/component-category-list/component-category-list.html +++ b/docs/src/app/pages/component-category-list/component-category-list.html @@ -6,21 +6,31 @@ @if (items.length > 0) {
@for (component of items; track component) { - -
- @if (section === 'components') { - - } -
{{component.name}}
-
{{component.summary}}
-
-
+ @if (component.externalRedirect) { + + + + } @else { + + + + } }
} + + +
+ @if (section === 'components') { + + } +
{{component.name}}
+
{{component.summary}}
+
+
diff --git a/docs/src/app/pages/component-category-list/component-category-list.ts b/docs/src/app/pages/component-category-list/component-category-list.ts index 9f0588459e0e..7501dc3ab3ab 100644 --- a/docs/src/app/pages/component-category-list/component-category-list.ts +++ b/docs/src/app/pages/component-category-list/component-category-list.ts @@ -9,6 +9,7 @@ import {Component, OnDestroy, OnInit, inject} from '@angular/core'; import {ActivatedRoute, RouterLink} from '@angular/router'; import {MatRipple} from '@angular/material/core'; +import {NgTemplateOutlet} from '@angular/common'; import {combineLatest, Subscription} from 'rxjs'; import { @@ -24,7 +25,7 @@ import {ComponentPageTitle} from '../page-title/page-title'; selector: 'app-component-category-list', templateUrl: './component-category-list.html', styleUrls: ['./component-category-list.scss'], - imports: [NavigationFocus, RouterLink, MatRipple], + imports: [NavigationFocus, RouterLink, MatRipple, NgTemplateOutlet], }) export class ComponentCategoryList implements OnInit, OnDestroy { private readonly _docItems = inject(DocumentationItems); diff --git a/docs/src/app/pages/component-sidenav/component-nav.html b/docs/src/app/pages/component-sidenav/component-nav.html index 4e9b0a3c7d2e..c08350c3cb97 100644 --- a/docs/src/app/pages/component-sidenav/component-nav.html +++ b/docs/src/app/pages/component-sidenav/component-nav.html @@ -6,13 +6,17 @@
@for (component of items; track component) { - - {{component.name}} - + @if (component.externalRedirect) { + {{component.name}} + } @else { + + {{component.name}} + + } }
diff --git a/docs/src/app/pages/component-viewer/component-overview.html b/docs/src/app/pages/component-viewer/component-overview.html index 1404d543d260..a3397b3ed5e3 100644 --- a/docs/src/app/pages/component-viewer/component-overview.html +++ b/docs/src/app/pages/component-viewer/component-overview.html @@ -2,9 +2,12 @@

Overview for {{docItem.id}}

- + @if (showToc | async) { diff --git a/docs/src/app/pages/system-variables/system-variables.html b/docs/src/app/pages/system-variables/system-variables.html deleted file mode 100644 index 613e900b60d2..000000000000 --- a/docs/src/app/pages/system-variables/system-variables.html +++ /dev/null @@ -1,242 +0,0 @@ -

- Angular Material components depend on system variables defined as CSS variables through the - material.theme - Sass mixin. This page provides guidance and documentation for using these variables to - customize components. -

- -

Colors

- -

- Material Design uses color to create accessible, personal color schemes - that communicate your product's hierarchy, state, and brand. See Material - Design's Color System - page to learn more about its use and purpose. -

-

- The following colors are the most often used in Angular Material components. Use these - colors and follow their uses to add theme colors to your application's custom components. -

- -
-
-
-
Primary
-
--mat-sys-primary
-
-
-

- The most common color used by Angular Material components to - participate in the application theme. -

-

- Examples include the background color - of filled buttons, the icon color of selected radio buttons, and the - outline color of form fields. -

-

- Use the color --mat-sys-on-primary for - icons, text, and other visual elements placed on a primary background. This - color is calculated to be optimal for accessibility and legibility. -

-
-
- -
-
-
Surface
-
--mat-sys-surface
-
-
-

- A low-emphasis background color that provides a clear contrast for - both light and dark themes and their varied theme colors. -

-

- Examples include the background color of the application and most - components such as the dialog, card, table, and more. -

-

- Use the color --mat-sys-on-surface for - icons, text, and other visual elements placed on a surface background. This - color is calculated to be optimal for accessibility and legibility. -

-
-
- -
-
-
Error
-
--mat-sys-error
-
-
-

- High-contrast color meant to alert the user to attract immediate attention. -

-

- Examples include the background color of the badge and the text color of invalid - form fields inputs. -

-

- Use the color --mat-sys-on-error for - icons, text, and other visual elements placed on an error background. This - color is calculated to be optimal for accessibility and legibility. -

-
-
- -
-
-
Outline
-
--mat-sys-outline
-
-
-

- Used for borders and dividers to help provide visual separation between - and around elements. -

-

- Examples include the color of the divider and border color of an outlined - form field. -

-

- Use the color --mat-sys-outline-variant for a less - prominent outline. -

-
-
-
- - - Other available colors - -

- These colors are less commonly used in Angular Material components but - are available for adding color variety and creating additional emphasis - to components. -

-

- Colors may be paired with a --mat-sys-on- variable - that should be used for text and icons placed within a filled container. -

- -

Alternative Theme Colors

- - - -

Surface Colors

- -

- The following colors should be used for backgrounds and large, - low-emphasis areas of the screen. -

- -

- Containers filled with a surface color should apply the - --mat-sys-on-surface color to text - and icons placed within. -

- - - -

Fixed Colors

- -

- These colors are the same for both light and dark themes. They are unused - by any Angular Material components. -

- - - -
- -

Typography

- -

- There are five categories of font types defined by Material Design: body, display, headline, - label, and title. Each category has three sizes: small, medium, and large. -

-

- Learn more about how these categories and their sizes should be used in your application by - visiting Material Design's - Typography documentation. -

- - -@for (category of ['body', 'display', 'headline', 'label', 'title']; track $index) { -
-
{{category}}
- @for (size of ['small', 'medium', 'large']; track $index) { -
-
-
--mat-sys-{{category}}-{{size}}
-
-
Lorem ipsum dolor
-
- } -
-} - -

- Each system variable can be applied to the "font" CSS style. Additionally, the parts of the variable definition - can be accessed individually by appending the keywords "font", "line-height", "size", "tracking", and "weight". -

-

- For example, the values for medium body text may be defined as follows: -

-
---mat-sys-body-medium: 400 0.875rem / 1.25rem Roboto, sans-serif;
---mat-sys-body-medium-font: Roboto, sans-serif;
---mat-sys-body-medium-line-height: 1.25rem;
---mat-sys-body-medium-size: 0.875rem;
---mat-sys-body-medium-tracking: 0.016rem;
---mat-sys-body-medium-weight: 400;
-
- -

Elevation

- -

- Material Design provides six levels of elevation that can be used to provide - a sense of depth and organization to an application's UI. Learn more at Material Design's - Elevation guide. -

- -

- These levels are defined as CSS box-shadow values that can be styled to an element. -

- -@for (level of [0, 1, 2, 3, 4, 5]; track $index) { -
- box-shadow: var(--mat-sys-level{{level}}) -
-} - -

Overrides

- -

- The mat.theme-overrides mixin - can be included to emit different definitions for the system variables and - override the definitions emitted from mat.theme. -

- -
- This example container has several system variables overridden by including the - following Sass code: - -
-  @include mat.theme-overrides((
-    primary: #ebdcff,
-    on-primary: #230f46,
-    body-medium: 500 1.15rem/1.3rem Arial,
-    corner-large: 32px,
-    level3: 0 4px 6px 1px var(--mat-sys-surface-dim),
-  ));
-
diff --git a/docs/src/app/pages/system-variables/system-variables.scss b/docs/src/app/pages/system-variables/system-variables.scss deleted file mode 100644 index 87193de7efe4..000000000000 --- a/docs/src/app/pages/system-variables/system-variables.scss +++ /dev/null @@ -1,196 +0,0 @@ -@use '@angular/material' as mat; - -:host { - display: block; - max-width: 1000px; -} - -h1 { - font: var(--mat-sys-title-large); - font-size: 28px; - padding-top: 32px; -} - -h2 { - font: var(--mat-sys-title-large); -} - -a { - color: var(--mat-sys-primary); -} - -.demo-warn { - background: var(--mat-sys-error-container); - color: var(--mat-sys-on-error-container); - border: 1px solid var(--mat-sys-outline-variant); - border-radius: var(--mat-sys-corner-extra-small); - padding: 8px; -} - -.demo-group { - display: grid; - grid-template-columns: 1fr 1fr; - grid-gap: 24px; - margin-top: 24px; -} - -@media (max-width: 1000px) { - .demo-group { grid-template-columns: auto;} -} - -.demo-color-container { - border-radius: var(--mat-sys-corner-small); - display: inline-block; - font: var(--mat-sys-body-medium); - vertical-align: top; -} - -.demo-heading { - color: var(--mat-sys-on-primary); - background: var(--mat-sys-primary); - border: 1px solid var(--mat-sys-outline); - border-top-right-radius: var(--mat-sys-corner-small); - border-top-left-radius: var(--mat-sys-corner-small); - border-bottom: none; - padding: 16px; - display: flex; - align-items: center; - justify-content: space-between; -} - -.demo-name { - font: var(--mat-sys-title-medium); -} - -.demo-variable { - font: var(--mat-sys-title-small); - font-family: monospace; - text-align: right; -} - -.demo-description { - border: 1px solid var(--mat-sys-outline); - border-bottom-right-radius: var(--mat-sys-corner-small); - border-bottom-left-radius: var(--mat-sys-corner-small); - padding: 0 16px; -} - -.demo-code { - font-family: monospace; -} - -.demo-surface-variable { - display: inline-block; - font-family: monospace; - background: var(--mat-sys-primary-container); - color: var(--mat-sys-on-primary-container); - padding: 2px 6px; - margin: 0 2px; - border-radius: 4px; -} - -mat-expansion-panel { - margin-top: 24px; - overflow: visible; - @include mat.expansion-overrides(( - 'container-text-font': var(--mat-sys-body-medium-font), - 'container-text-size': var(--mat-sys-body-medium-size), - 'container-text-weight': var(--mat-sys-body-medium-weight), - 'container-text-line-height': var(--mat-sys-body-medium-line-height), - 'container-text-tracking': var(--mat-sys-body-medium-tracking), - )); -} - -.demo-compact-color-container { - border-radius: var(--mat-sys-corner-small); - border: 1px solid var(--mat-sys-outline); - overflow: hidden; // Hide child heading background color - margin-top: 24px; - - .demo-heading { - border: none; - border-radius: 0; - - &:not(:nth-child(1)) { - border-top: 1px solid var(--mat-sys-outline); - } - } - - .demo-variables { - text-align: end; - } -} - -.demo-typography-group { - border: 1px solid var(--mat-sys-outline); - border-radius: var(--mat-sys-corner-small); - margin-top: 40px; - overflow: hidden; -} - -.demo-typography-title { - text-transform: capitalize; - font: var(--mat-sys-title-medium); - padding: 16px; - border-bottom: 1px solid var(--mat-sys-outline); - background: var(--mat-sys-primary-container); - color: var(--mat-sys-on-primary-container); -} - -.demo-typography-variable { - min-width: 240px; -} - -.demo-typography-example { - padding: 16px; - display: flex; - align-items: baseline; - border-top: 1px solid var(--mat-sys-outline-variant); - - &:nth-child(1) { - border: none; - } - .demo-surface-variable { - margin-right: 16px; - } -} - -.demo-typography-text { - display: inline-block; -} - -.demo-elevation { - height: 40px; - width: 300px; - margin: 32px 0; - display: flex; - align-items: center; - justify-content: center; - background: var(--mat-sys-surface-container); - color: var(--mat-sys-on-surface); - border-radius: var(--mat-sys-corner-extra-small); -} - -.demo-code-block { - background: var(--mat-sys-surface-container-low); - padding: 16px; - border-radius: var(--mat-sys-corner-small); - border: 1px solid var(--mat-sys-outline); -} - -.demo-overrides { - background-color: var(--mat-sys-primary); - color: var(--mat-sys-on-primary); - font: var(--mat-sys-body-medium); - border-radius: var(--mat-sys-corner-small); - box-shadow: var(--mat-sys-level3); - padding: 16px; - - @include mat.theme-overrides(( - primary: #ebdcff, - on-primary: #230f46, - body-medium: 500 1.15rem/1.3rem Arial, - corner-large: 32px, - level3: 0 4px 6px 1px var(--mat-sys-surface-dim), - )); -} diff --git a/docs/src/app/pages/system-variables/system-variables.ts b/docs/src/app/pages/system-variables/system-variables.ts deleted file mode 100644 index e5b17ffb9cf9..000000000000 --- a/docs/src/app/pages/system-variables/system-variables.ts +++ /dev/null @@ -1,162 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {ChangeDetectionStrategy, Component, input} from '@angular/core'; -import {MatExpansionPanel, MatExpansionPanelHeader} from '@angular/material/expansion'; - -interface Color { - name: string; - background: string; - text: string; - hideText?: boolean; -} - -@Component({ - selector: 'theme-demo-colors', - template: ` -
- @for (color of colors(); track $index) { -
-
{{color.name}}
-
-
{{color.background}}
- @if (!color.hideText) { -
{{color.text}}
- } -
-
- } -
- `, - styleUrl: 'system-variables.scss', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ThemeDemoColors { - colors = input(); -} - -@Component({ - selector: 'app-system-variables', - templateUrl: './system-variables.html', - styleUrls: ['./system-variables.scss'], - imports: [MatExpansionPanel, MatExpansionPanelHeader, ThemeDemoColors], -}) -export class SystemVariables { - alternativeThemeColors: Color[] = [ - { - name: 'Primary Container', - background: '--mat-sys-primary-container', - text: '--mat-sys-on-primary-container', - }, - { - name: 'Secondary', - background: '--mat-sys-secondary', - text: '--mat-sys-on-secondary', - }, - { - name: 'Secondary Container', - background: '--mat-sys-secondary-container', - text: '--mat-sys-on-secondary-container', - }, - { - name: 'Tertiary', - background: '--mat-sys-tertiary', - text: '--mat-sys-on-tertiary', - }, - { - name: 'Tertiary Container', - background: '--mat-sys-tertiary-container', - text: '--mat-sys-on-tertiary-container', - }, - { - name: 'Error Container', - background: '--mat-sys-error-container', - text: '--mat-sys-on-error-container', - }, - ]; - - surfaceColors: Color[] = [ - { - name: 'Surface Dim', - background: '--mat-sys-surface-dim', - text: '--mat-sys-on-surface', - hideText: true, - }, - { - name: 'Surface Bright', - background: '--mat-sys-surface-bright', - text: '--mat-sys-on-surface', - hideText: true, - }, - { - name: 'Surface Container Lowest', - background: '--mat-sys-surface-container-lowest', - text: '--mat-sys-on-surface', - hideText: true, - }, - { - name: 'Surface Container Low', - background: '--mat-sys-surface-container-low', - text: '--mat-sys-on-surface', - hideText: true, - }, - { - name: 'Surface Container', - background: '--mat-sys-surface-container', - text: '--mat-sys-on-surface', - hideText: true, - }, - { - name: 'Surface Container High', - background: '--mat-sys-surface-container-high', - text: '--mat-sys-on-surface', - hideText: true, - }, - { - name: 'Surface Container Highest', - background: '--mat-sys-surface-container-highest', - text: '--mat-sys-on-surface', - hideText: true, - }, - ]; - - fixedColors: Color[] = [ - { - name: 'Primary Fixed', - background: '--mat-sys-primary-fixed', - text: '--mat-sys-on-primary-fixed', - }, - { - name: 'Primary Fixed Dim', - background: '--mat-sys-primary-fixed-dim', - text: '--mat-sys-on-primary-fixed', - }, - { - name: 'Secondary Fixed', - background: '--mat-sys-secondary-fixed', - text: '--mat-sys-on-secondary-fixed', - }, - { - name: 'Secondary Fixed Dim', - background: '--mat-sys-secondary-fixed-dim', - text: '--mat-sys-on-secondary-fixed', - }, - { - name: 'Tertiary Fixed', - background: '--mat-sys-tertiary-fixed', - text: '--mat-sys-on-tertiary-fixed', - }, - { - name: 'Tertiary Fixed Dim', - background: '--mat-sys-tertiary-fixed-dim', - text: '--mat-sys-on-tertiary-fixed', - }, - ]; -} diff --git a/docs/src/app/routes.ts b/docs/src/app/routes.ts index af7844550f20..0732941578aa 100644 --- a/docs/src/app/routes.ts +++ b/docs/src/app/routes.ts @@ -6,13 +6,23 @@ * found in the LICENSE file at https://angular.dev/license */ -import {Routes} from '@angular/router'; +import {Component} from '@angular/core'; +import {Route, Routes} from '@angular/router'; import {CanActivateComponentSidenav} from './pages/component-sidenav/component-sidenav-can-load-guard'; -function externalRedirect(target: string) { - return () => { - window.location.href = target; - return ''; // unused due to redirect above +@Component({template: ''}) +export class RedirectPlaceholder {} + +function externalRedirect(target: string): Partial { + return { + // The router requires a `component`. + component: RedirectPlaceholder, + canActivate: [ + () => { + window.location.href = target; + return false; + }, + ], }; } @@ -35,32 +45,32 @@ export const MATERIAL_DOCS_ROUTES: Routes = [ // Component harness, drag & drop docs have moved to angular.dev { path: 'cdk/testing', - redirectTo: externalRedirect('https://angular.dev/guide/testing/component-harnesses-overview'), + ...externalRedirect('https://angular.dev/guide/testing/component-harnesses-overview'), }, { path: 'cdk/testing/api', - redirectTo: externalRedirect('https://angular.dev/api#angular_cdk_testing'), + ...externalRedirect('https://angular.dev/api#angular_cdk_testing'), }, { path: 'cdk/testing/:tab', - redirectTo: externalRedirect('https://angular.dev/guide/testing/component-harnesses-overview'), + ...externalRedirect('https://angular.dev/guide/testing/component-harnesses-overview'), }, { path: 'cdk/drag-drop', - redirectTo: externalRedirect('https://angular.dev/guide/drag-drop'), + ...externalRedirect('https://angular.dev/guide/drag-drop'), }, { path: 'cdk/drag-drop/api', - redirectTo: externalRedirect('https://angular.dev/api#angular_cdk_drag-drop'), + ...externalRedirect('https://angular.dev/api#angular_cdk_drag-drop'), }, { path: 'cdk/drag-drop/:tab', - redirectTo: externalRedirect('https://angular.dev/guide/drag-drop'), + ...externalRedirect('https://angular.dev/guide/drag-drop'), }, + {path: 'guide/system-variables', redirectTo: '/guide/theming-your-components'}, // In v19, the theming system became based on system variables and the mat.theme mixin. // The following guides were consolidated into the main theming guide, which redirects // users to v18 docs if they are looking for this content. - {path: 'guide/theming-your-components', redirectTo: '/guide/theming'}, {path: 'guide/typography', redirectTo: '/guide/theming'}, {path: 'guide/customizing-component-styles', redirectTo: '/guide/theming'}, {path: 'guide/elevation', redirectTo: '/guide/theming'}, diff --git a/docs/src/app/shared/doc-viewer/angular-aria-banner/angular-aria-banner.css b/docs/src/app/shared/doc-viewer/angular-aria-banner/angular-aria-banner.css new file mode 100644 index 000000000000..5bc996314758 --- /dev/null +++ b/docs/src/app/shared/doc-viewer/angular-aria-banner/angular-aria-banner.css @@ -0,0 +1,46 @@ +.docs-angular-aria-banner { + display: flex; + align-items: flex-start; + gap: 12px; + padding: 16px; + margin-bottom: 24px; + background-color: color-mix(in srgb, var(--mat-sys-primary) 10%, transparent); + border-left: 4px solid var(--mat-sys-primary); + border-radius: 4px; + font-size: 14px; + line-height: 1.6; +} + +mat-icon { + flex-shrink: 0; + color: var(--mat-sys-primary); +} + +.docs-angular-aria-banner-content { + flex: 1; +} + +strong { + color: var(--mat-sys-primary); +} + +a { + color: var(--mat-sys-primary); + text-decoration: underline; + font-weight: 500; +} + +p { + margin: 0; +} + +@media (max-width: 600px) { + .docs-angular-aria-banner { + padding: 12px; + gap: 8px; + } + + mat-icon { + font-size: 18px; + } +} diff --git a/docs/src/app/shared/doc-viewer/angular-aria-banner/angular-aria-banner.html b/docs/src/app/shared/doc-viewer/angular-aria-banner/angular-aria-banner.html new file mode 100644 index 000000000000..e98063aa474e --- /dev/null +++ b/docs/src/app/shared/doc-viewer/angular-aria-banner/angular-aria-banner.html @@ -0,0 +1,13 @@ +
+ info + +
+ Now Available in Angular Aria! +

+ The Angular team has introduced a new low-level component library called Angular Aria. + Consider using the + Angular Aria {{ componentName }} + component as an alternative to this CDK component. +

+
+
diff --git a/docs/src/app/shared/doc-viewer/angular-aria-banner/angular-aria-banner.ts b/docs/src/app/shared/doc-viewer/angular-aria-banner/angular-aria-banner.ts new file mode 100644 index 000000000000..4a23a0288986 --- /dev/null +++ b/docs/src/app/shared/doc-viewer/angular-aria-banner/angular-aria-banner.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Component, Input} from '@angular/core'; +import {MatIcon} from '@angular/material/icon'; + +/** + * Mapping of CDK component names to their Angular Aria documentation URLs. + */ +const ANGULAR_ARIA_LINKS: Record = { + 'listbox': 'https://angular.dev/guide/aria/listbox', + 'tree': 'https://angular.dev/guide/aria/tree', + 'accordion': 'https://angular.dev/guide/aria/accordion', + 'menu': 'https://angular.dev/guide/aria/menu', +}; + +/** + * Banner component that guides users to use the new Angular Aria components for CDK components + * that have equivalent Angular Aria components. + */ +@Component({ + selector: 'angular-aria-banner', + templateUrl: 'angular-aria-banner.html', + styleUrl: 'angular-aria-banner.css', + imports: [MatIcon], +}) +export class AngularAriaBanner { + @Input() componentName: string = ''; + + get ariaLink(): string { + return ANGULAR_ARIA_LINKS[this.componentName.toLowerCase()] || ''; + } +} diff --git a/docs/src/app/shared/doc-viewer/doc-viewer.ts b/docs/src/app/shared/doc-viewer/doc-viewer.ts index 93eb369c1227..2fcc06ce5c29 100644 --- a/docs/src/app/shared/doc-viewer/doc-viewer.ts +++ b/docs/src/app/shared/doc-viewer/doc-viewer.ts @@ -38,6 +38,7 @@ import {ExampleViewer} from '../example-viewer/example-viewer'; import {HeaderLink} from './header-link'; import {DeprecatedFieldComponent} from './deprecated-tooltip'; import {ModuleImportCopyButton} from './module-import-copy-button'; +import {AngularAriaBanner} from './angular-aria-banner/angular-aria-banner'; @Injectable({providedIn: 'root'}) class DocFetcher { @@ -80,6 +81,7 @@ export class DocViewer implements OnDestroy { protected portal: Portal | undefined; readonly name = input(); + readonly packageName = input(); /** The document to display, either as a URL to a markdown file or a component to create. */ @Input() @@ -154,6 +156,9 @@ export class DocViewer implements OnDestroy { this._loadComponents('material-docs-example', ExampleViewer); this._loadComponents('header-link', HeaderLink); + // Inject Angular Aria banner for specific CDK components + this._injectAngularAriaBanner(); + // Create tooltips for the deprecated fields this._createTooltipsForDeprecated(); @@ -267,4 +272,36 @@ export class DocViewer implements OnDestroy { this._portalHosts.push(elementPortalOutlet); }); } + + /** + * Injects the Angular Aria migration banner for specific CDK components. + */ + private _injectAngularAriaBanner() { + const componentName = this.name(); + const packageName = this.packageName(); + + if ( + !componentName || + packageName !== 'cdk' || + !['listbox', 'tree', 'accordion', 'menu'].includes(componentName.toLowerCase()) + ) { + return; + } + + // Create a container div for the banner at the beginning of the document + const bannerContainer = document.createElement('div'); + bannerContainer.setAttribute('angular-aria-banner', ''); + bannerContainer.setAttribute('componentName', componentName); + + // Insert the banner at the beginning of the document content + this._elementRef.nativeElement.prepend(bannerContainer); + + // Create and attach the banner component + const portalHost = new DomPortalOutlet(bannerContainer, this._appRef, this._injector); + const bannerPortal = new ComponentPortal(AngularAriaBanner, this._viewContainerRef); + const bannerComponent = portalHost.attach(bannerPortal); + bannerComponent.instance.componentName = componentName; + + this._portalHosts.push(portalHost); + } } diff --git a/docs/src/app/shared/documentation-items/documentation-items.spec.ts b/docs/src/app/shared/documentation-items/documentation-items.spec.ts index 5ea9d7ae11f5..2ef9aa419ed0 100644 --- a/docs/src/app/shared/documentation-items/documentation-items.spec.ts +++ b/docs/src/app/shared/documentation-items/documentation-items.spec.ts @@ -8,7 +8,6 @@ describe('DocViewer', () => { let docsItems: DocumentationItems; beforeEach(() => { - TestBed.configureTestingModule({}); docsItems = TestBed.inject(DocumentationItems); }); diff --git a/docs/src/app/shared/documentation-items/documentation-items.ts b/docs/src/app/shared/documentation-items/documentation-items.ts index d73c2ab4c510..26cb3d2b7dee 100644 --- a/docs/src/app/shared/documentation-items/documentation-items.ts +++ b/docs/src/app/shared/documentation-items/documentation-items.ts @@ -40,6 +40,8 @@ export interface DocItem { additionalApiDocs?: AdditionalApiDoc[]; /** Whether the doc item can display styling information. */ hasStyling?: boolean; + /** External URL to the item's docs. */ + externalRedirect?: string; } export interface DocSection { @@ -462,6 +464,7 @@ const DOCS: {[key: string]: DocItem[]} = { id: 'drag-drop', name: 'Drag and Drop', summary: 'Directives enabling drag-and-drop interactions', + externalRedirect: 'https://angular.dev/guide/drag-drop', exampleSpecs: { prefix: 'cdk-drag-drop-', }, diff --git a/docs/src/app/shared/guide-items/guide-items.spec.ts b/docs/src/app/shared/guide-items/guide-items.spec.ts index 703c79165d52..cd899651364c 100644 --- a/docs/src/app/shared/guide-items/guide-items.spec.ts +++ b/docs/src/app/shared/guide-items/guide-items.spec.ts @@ -5,7 +5,6 @@ describe('GuideItems', () => { let guideItems: GuideItems; beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({}); guideItems = TestBed.inject(GuideItems); })); diff --git a/docs/src/app/shared/guide-items/guide-items.ts b/docs/src/app/shared/guide-items/guide-items.ts index feb5aac17361..0ef4cd047d5b 100644 --- a/docs/src/app/shared/guide-items/guide-items.ts +++ b/docs/src/app/shared/guide-items/guide-items.ts @@ -7,7 +7,6 @@ */ import {Injectable} from '@angular/core'; -import {SystemVariables} from '../../pages/system-variables'; import {ComponentType} from '@angular/cdk/portal'; export interface GuideItem { @@ -24,12 +23,6 @@ const GUIDES: GuideItem[] = [ document: '/docs-content/guides/getting-started.md.html', overview: 'Add Angular Material to your project!', }, - { - id: 'schematics', - name: 'Schematics', - document: '/docs-content/guides/schematics.md.html', - overview: 'Use schematics to quickly generate views with Material Design components.', - }, { id: 'theming', name: 'Theming Angular Material', @@ -37,10 +30,16 @@ const GUIDES: GuideItem[] = [ overview: "Customize your application with Angular Material's theming system.", }, { - id: 'system-variables', - name: 'System Variables', - document: SystemVariables, - overview: 'Understand the system variables available to use in your application.', + id: 'theming-your-components', + name: 'Theming your components', + document: '/docs-content/guides/theming-your-components.md.html', + overview: 'Applying Angular Material theming to your own components', + }, + { + id: 'schematics', + name: 'Schematics', + document: '/docs-content/guides/schematics.md.html', + overview: 'Use schematics to quickly generate views with Material Design components.', }, { id: 'creating-a-custom-form-field-control', diff --git a/docs/src/app/shared/stackblitz/stackblitz-writer.spec.ts b/docs/src/app/shared/stackblitz/stackblitz-writer.spec.ts index 772427a49b4f..51651b0a43dd 100644 --- a/docs/src/app/shared/stackblitz/stackblitz-writer.spec.ts +++ b/docs/src/app/shared/stackblitz/stackblitz-writer.spec.ts @@ -102,7 +102,6 @@ describe('StackBlitzWriter', () => { const expectedFiles = jasmine.objectContaining({ 'angular.json': 'fake', 'src/main.ts': `import {ExampleComponent} from './test';`, - 'src/test.ts': 'fake', 'src/index.html': ``, 'src/example/test.ts': `ExampleComponent diff --git a/docs/src/app/shared/stackblitz/stackblitz-writer.ts b/docs/src/app/shared/stackblitz/stackblitz-writer.ts index c62142999dd1..02e80c662cb4 100644 --- a/docs/src/app/shared/stackblitz/stackblitz-writer.ts +++ b/docs/src/app/shared/stackblitz/stackblitz-writer.ts @@ -40,7 +40,6 @@ const TEMPLATE_PATH = '/assets/stackblitz/'; */ export const TEMPLATE_FILES = [ 'angular.json', - 'karma.conf.js', 'package.json', 'package-lock.json', 'tsconfig.app.json', @@ -49,7 +48,6 @@ export const TEMPLATE_FILES = [ 'src/index.html', 'src/main.ts', 'src/styles.css', - 'src/test.ts', ]; /** @@ -215,8 +213,8 @@ export class StackBlitzWriter { // Replace `bootstrapApplication(MaterialDocsExample,` // will be replaced as `bootstrapApplication(ButtonDemo,` fileContent = fileContent.replace( - /bootstrapApplication\(MaterialDocsExample,/g, - `bootstrapApplication(${mainComponentName},`, + /bootstrapApplication\(MaterialDocsExample/g, + `bootstrapApplication(${mainComponentName}`, ); const dotIndex = data.indexFilename.lastIndexOf('.'); diff --git a/docs/src/assets/stackblitz/angular.json b/docs/src/assets/stackblitz/angular.json index 50b3897f59a6..22f238bc4efd 100644 --- a/docs/src/assets/stackblitz/angular.json +++ b/docs/src/assets/stackblitz/angular.json @@ -21,7 +21,7 @@ "prefix": "app", "architect": { "build": { - "builder": "@angular-devkit/build-angular:application", + "builder": "@angular/build:application", "options": { "outputPath": "dist/example-app", "index": "src/index.html", @@ -65,7 +65,7 @@ "defaultConfiguration": "production" }, "serve": { - "builder": "@angular-devkit/build-angular:dev-server", + "builder": "@angular/build:dev-server", "configurations": { "production": { "buildTarget": "example-app:build:production" @@ -76,19 +76,11 @@ }, "defaultConfiguration": "development" }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "example-app:build" - } - }, "test": { - "builder": "@angular-devkit/build-angular:karma", + "builder": "@angular/build:karma", "options": { - "main": "src/test.ts", "polyfills": ["zone.js", "zone.js/testing"], "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", "inlineStyleLanguage": "css", "assets": ["src/assets"], "styles": ["src/styles.css", "@angular/material/prebuilt-themes/azure-blue.css"], diff --git a/docs/src/assets/stackblitz/karma.conf.js b/docs/src/assets/stackblitz/karma.conf.js deleted file mode 100644 index c82069f17d49..000000000000 --- a/docs/src/assets/stackblitz/karma.conf.js +++ /dev/null @@ -1,41 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - require('@angular-devkit/build-angular/plugins/karma'), - ], - client: { - jasmine: { - // you can add configuration options for Jasmine here - // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html - // for example, you can disable the random execution with `random: false` - // or set a specific seed with `seed: 4321` - }, - clearContext: false, // leave Jasmine Spec Runner output visible in browser - }, - jasmineHtmlReporter: { - suppressAll: true, // removes the duplicated traces - }, - coverageReporter: { - dir: require('path').join(__dirname, './coverage/example-app'), - subdir: '.', - reporters: [{type: 'html'}, {type: 'text-summary'}], - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false, - restartOnFileChange: true, - }); -}; diff --git a/docs/src/assets/stackblitz/package-lock.json b/docs/src/assets/stackblitz/package-lock.json index aad077fc2f57..aafdfb45f15b 100644 --- a/docs/src/assets/stackblitz/package-lock.json +++ b/docs/src/assets/stackblitz/package-lock.json @@ -8,26 +8,25 @@ "name": "example-app", "version": "0.0.0", "dependencies": { - "@angular/cdk": "^20.2.0", - "@angular/common": "^20.2.0", - "@angular/compiler": "^20.2.0", - "@angular/core": "^20.2.0", - "@angular/forms": "^20.2.0", - "@angular/localize": "^20.2.0", - "@angular/material": "^20.2.0", - "@angular/material-luxon-adapter": "^20.2.0", - "@angular/platform-browser": "^20.2.0", - "@angular/platform-browser-dynamic": "^20.2.0", - "@angular/router": "^20.2.0", + "@angular/cdk": "^21.0.0", + "@angular/common": "^21.0.0", + "@angular/compiler": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/forms": "^21.0.0", + "@angular/localize": "^21.0.0", + "@angular/material": "^21.0.0", + "@angular/material-luxon-adapter": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "@angular/router": "^21.0.0", "luxon": "^3.7.2", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" }, "devDependencies": { - "@angular-devkit/build-angular": "^20.2.0", - "@angular/cli": "^20.2.0", - "@angular/compiler-cli": "^20.2.0", + "@angular/build": "^21.0.0", + "@angular/cli": "^21.0.0", + "@angular/compiler-cli": "^21.0.0", "@types/jasmine": "~5.1.0", "@types/luxon": "^3.0.0", "@types/node": "^12.11.1", @@ -41,57 +40,57 @@ } }, "node_modules/@algolia/abtesting": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.1.0.tgz", - "integrity": "sha512-sEyWjw28a/9iluA37KLGu8vjxEIlb60uxznfTUmXImy7H5NvbpSO6yYgmgH5KiD7j+zTUUihiST0jEP12IoXow==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.6.1.tgz", + "integrity": "sha512-wV/gNRkzb7sI9vs1OneG129hwe3Q5zPj7zigz3Ps7M5Lpo2hSorrOnXNodHEOV+yXE/ks4Pd+G3CDFIjFTWhMQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" + "@algolia/client-common": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-abtesting": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.35.0.tgz", - "integrity": "sha512-uUdHxbfHdoppDVflCHMxRlj49/IllPwwQ2cQ8DLC4LXr3kY96AHBpW0dMyi6ygkn2MtFCc6BxXCzr668ZRhLBQ==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.40.1.tgz", + "integrity": "sha512-cxKNATPY5t+Mv8XAVTI57altkaPH+DZi4uMrnexPxPHODMljhGYY+GDZyHwv9a+8CbZHcY372OkxXrDMZA4Lnw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" + "@algolia/client-common": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.35.0.tgz", - "integrity": "sha512-SunAgwa9CamLcRCPnPHx1V2uxdQwJGqb1crYrRWktWUdld0+B2KyakNEeVn5lln4VyeNtW17Ia7V7qBWyM/Skw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.40.1.tgz", + "integrity": "sha512-XP008aMffJCRGAY8/70t+hyEyvqqV7YKm502VPu0+Ji30oefrTn2al7LXkITz7CK6I4eYXWRhN6NaIUi65F1OA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" + "@algolia/client-common": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.35.0.tgz", - "integrity": "sha512-ipE0IuvHu/bg7TjT2s+187kz/E3h5ssfTtjpg1LbWMgxlgiaZIgTTbyynM7NfpSJSKsgQvCQxWjGUO51WSCu7w==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.40.1.tgz", + "integrity": "sha512-gWfQuQUBtzUboJv/apVGZMoxSaB0M4Imwl1c9Ap+HpCW7V0KhjBddqF2QQt5tJZCOFsfNIgBbZDGsEPaeKUosw==", "dev": true, "license": "MIT", "engines": { @@ -99,151 +98,151 @@ } }, "node_modules/@algolia/client-insights": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.35.0.tgz", - "integrity": "sha512-UNbCXcBpqtzUucxExwTSfAe8gknAJ485NfPN6o1ziHm6nnxx97piIbcBQ3edw823Tej2Wxu1C0xBY06KgeZ7gA==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.40.1.tgz", + "integrity": "sha512-RTLjST/t+lsLMouQ4zeLJq2Ss+UNkLGyNVu+yWHanx6kQ3LT5jv8UvPwyht9s7R6jCPnlSI77WnL80J32ZuyJg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" + "@algolia/client-common": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.35.0.tgz", - "integrity": "sha512-/KWjttZ6UCStt4QnWoDAJ12cKlQ+fkpMtyPmBgSS2WThJQdSV/4UWcqCUqGH7YLbwlj3JjNirCu3Y7uRTClxvA==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.40.1.tgz", + "integrity": "sha512-2FEK6bUomBzEYkTKzD0iRs7Ljtjb45rKK/VSkyHqeJnG+77qx557IeSO0qVFE3SfzapNcoytTofnZum0BQ6r3Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" + "@algolia/client-common": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.35.0.tgz", - "integrity": "sha512-8oCuJCFf/71IYyvQQC+iu4kgViTODbXDk3m7yMctEncRSRV+u2RtDVlpGGfPlJQOrAY7OONwJlSHkmbbm2Kp/w==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.40.1.tgz", + "integrity": "sha512-Nju4NtxAvXjrV2hHZNLKVJLXjOlW6jAXHef/CwNzk1b2qIrCWDO589ELi5ZHH1uiWYoYyBXDQTtHmhaOVVoyXg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" + "@algolia/client-common": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.35.0.tgz", - "integrity": "sha512-FfmdHTrXhIduWyyuko1YTcGLuicVbhUyRjO3HbXE4aP655yKZgdTIfMhZ/V5VY9bHuxv/fGEh3Od1Lvv2ODNTg==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.40.1.tgz", + "integrity": "sha512-Mw6pAUF121MfngQtcUb5quZVqMC68pSYYjCRZkSITC085S3zdk+h/g7i6FxnVdbSU6OztxikSDMh1r7Z+4iPlA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" + "@algolia/client-common": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/ingestion": { - "version": "1.35.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.35.0.tgz", - "integrity": "sha512-gPzACem9IL1Co8mM1LKMhzn1aSJmp+Vp434An4C0OBY4uEJRcqsLN3uLBlY+bYvFg8C8ImwM9YRiKczJXRk0XA==", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.40.1.tgz", + "integrity": "sha512-z+BPlhs45VURKJIxsR99NNBWpUEEqIgwt10v/fATlNxc4UlXvALdOsWzaFfe89/lbP5Bu4+mbO59nqBC87ZM/g==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" + "@algolia/client-common": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.35.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.35.0.tgz", - "integrity": "sha512-w9MGFLB6ashI8BGcQoVt7iLgDIJNCn4OIu0Q0giE3M2ItNrssvb8C0xuwJQyTy1OFZnemG0EB1OvXhIHOvQwWw==", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.40.1.tgz", + "integrity": "sha512-VJMUMbO0wD8Rd2VVV/nlFtLJsOAQvjnVNGkMkspFiFhpBA7s/xJOb+fJvvqwKFUjbKTUA7DjiSi1ljSMYBasXg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" + "@algolia/client-common": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.35.0.tgz", - "integrity": "sha512-AhrVgaaXAb8Ue0u2nuRWwugt0dL5UmRgS9LXe0Hhz493a8KFeZVUE56RGIV3hAa6tHzmAV7eIoqcWTQvxzlJeQ==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.40.1.tgz", + "integrity": "sha512-ehvJLadKVwTp9Scg9NfzVSlBKH34KoWOQNTaN8i1Ac64AnO6iH2apJVSP6GOxssaghZ/s8mFQsDH3QIZoluFHA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" + "@algolia/client-common": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.35.0.tgz", - "integrity": "sha512-diY415KLJZ6x1Kbwl9u96Jsz0OstE3asjXtJ9pmk1d+5gPuQ5jQyEsgC+WmEXzlec3iuVszm8AzNYYaqw6B+Zw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.40.1.tgz", + "integrity": "sha512-PbidVsPurUSQIr6X9/7s34mgOMdJnn0i6p+N6Ab+lsNhY5eiu+S33kZEpZwkITYBCIbhzDLOvb7xZD3gDi+USA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0" + "@algolia/client-common": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.35.0.tgz", - "integrity": "sha512-uydqnSmpAjrgo8bqhE9N1wgcB98psTRRQXcjc4izwMB7yRl9C8uuAQ/5YqRj04U0mMQ+fdu2fcNF6m9+Z1BzDQ==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.40.1.tgz", + "integrity": "sha512-ThZ5j6uOZCF11fMw9IBkhigjOYdXGXQpj6h4k+T9UkZrF2RlKcPynFzDeRgaLdpYk8Yn3/MnFbwUmib7yxj5Lw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0" + "@algolia/client-common": "5.40.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.35.0.tgz", - "integrity": "sha512-RgLX78ojYOrThJHrIiPzT4HW3yfQa0D7K+MQ81rhxqaNyNBu4F1r+72LNHYH/Z+y9I1Mrjrd/c/Ue5zfDgAEjQ==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.40.1.tgz", + "integrity": "sha512-H1gYPojO6krWHnUXu/T44DrEun/Wl95PJzMXRcM/szstNQczSbwq6wIFJPI9nyE95tarZfUNU3rgorT+wZ6iCQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.35.0" + "@algolia/client-common": "5.40.1" }, "engines": { "node": ">= 14.0.0" @@ -253,6 +252,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -263,13 +263,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2003.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.4.tgz", - "integrity": "sha512-OKT6QuoG+rZZmRQ9mSZoh1pCGB5jBrkb45CzI8VdaLFhrZ7Uqg1wri1tj5KpSQYLAd22uUFNIE0uzMmGwXHbYA==", + "version": "0.2100.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2100.0.tgz", + "integrity": "sha512-BNt6Rw53WauCw31ku/r/ksVIY+Pi8XZptsSUIHiDUeqB2iZOWu4L3c5kuDGmoGkGByY588H48hfR2MgIpBhgAg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.3.4", + "@angular-devkit/core": "21.0.0", "rxjs": "7.8.2" }, "engines": { @@ -278,171 +278,86 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/build-angular": { - "version": "20.3.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-20.3.4.tgz", - "integrity": "sha512-Lc/Hi4A0xBDbPb0tg7JHofIkqTigwKFOTU4Y/y/sN/9BQ7z3M/cHylaFceCtTjwnqybOzWyR58bStLO1wIN8Gw==", + "node_modules/@angular-devkit/core": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.0.0.tgz", + "integrity": "sha512-d3n5GvrwqN1AUkWE3Wd8rrdY2u6/5bzorlZVT5W4CcH7ekAIoMu4SBTbSJ7bfRe/l2z/A1WZ6hFlnQzLclOjJA==", "dev": true, "license": "MIT", "dependencies": { - "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2003.4", - "@angular-devkit/build-webpack": "0.2003.4", - "@angular-devkit/core": "20.3.4", - "@angular/build": "20.3.4", - "@babel/core": "7.28.3", - "@babel/generator": "7.28.3", - "@babel/helper-annotate-as-pure": "7.27.3", - "@babel/helper-split-export-declaration": "7.24.7", - "@babel/plugin-transform-async-generator-functions": "7.28.0", - "@babel/plugin-transform-async-to-generator": "7.27.1", - "@babel/plugin-transform-runtime": "7.28.3", - "@babel/preset-env": "7.28.3", - "@babel/runtime": "7.28.3", - "@discoveryjs/json-ext": "0.6.3", - "@ngtools/webpack": "20.3.4", - "ansi-colors": "4.1.3", - "autoprefixer": "10.4.21", - "babel-loader": "10.0.0", - "browserslist": "^4.21.5", - "copy-webpack-plugin": "13.0.1", - "css-loader": "7.1.2", - "esbuild-wasm": "0.25.9", - "fast-glob": "3.3.3", - "http-proxy-middleware": "3.0.5", - "istanbul-lib-instrument": "6.0.3", + "ajv": "8.17.1", + "ajv-formats": "3.0.1", "jsonc-parser": "3.3.1", - "karma-source-map-support": "1.4.0", - "less": "4.4.0", - "less-loader": "12.3.0", - "license-webpack-plugin": "4.0.2", - "loader-utils": "3.3.1", - "mini-css-extract-plugin": "2.9.4", - "open": "10.2.0", - "ora": "8.2.0", "picomatch": "4.0.3", - "piscina": "5.1.3", - "postcss": "8.5.6", - "postcss-loader": "8.1.1", - "resolve-url-loader": "5.0.0", "rxjs": "7.8.2", - "sass": "1.90.0", - "sass-loader": "16.0.5", - "semver": "7.7.2", - "source-map-loader": "5.0.0", - "source-map-support": "0.5.21", - "terser": "5.43.1", - "tree-kill": "1.2.2", - "tslib": "2.8.1", - "webpack": "5.101.2", - "webpack-dev-middleware": "7.4.2", - "webpack-dev-server": "5.2.2", - "webpack-merge": "6.0.1", - "webpack-subresource-integrity": "5.1.0" + "source-map": "0.7.6" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, - "optionalDependencies": { - "esbuild": "0.25.9" - }, "peerDependencies": { - "@angular/compiler-cli": "^20.0.0", - "@angular/core": "^20.0.0", - "@angular/localize": "^20.0.0", - "@angular/platform-browser": "^20.0.0", - "@angular/platform-server": "^20.0.0", - "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.3.4", - "@web/test-runner": "^0.20.0", - "browser-sync": "^3.0.2", - "jest": "^29.5.0", - "jest-environment-jsdom": "^29.5.0", - "karma": "^6.3.0", - "ng-packagr": "^20.0.0", - "protractor": "^7.0.0", - "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", - "typescript": ">=5.8 <6.0" + "chokidar": "^4.0.0" }, "peerDependenciesMeta": { - "@angular/core": { - "optional": true - }, - "@angular/localize": { - "optional": true - }, - "@angular/platform-browser": { - "optional": true - }, - "@angular/platform-server": { - "optional": true - }, - "@angular/service-worker": { - "optional": true - }, - "@angular/ssr": { - "optional": true - }, - "@web/test-runner": { - "optional": true - }, - "browser-sync": { - "optional": true - }, - "jest": { - "optional": true - }, - "jest-environment-jsdom": { - "optional": true - }, - "karma": { - "optional": true - }, - "ng-packagr": { - "optional": true - }, - "protractor": { - "optional": true - }, - "tailwindcss": { + "chokidar": { "optional": true } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { - "version": "20.3.4", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.4.tgz", - "integrity": "sha512-2ZPyEQxg9FCM7gv5NZHZVCec6ubb7HM/fkzr7wcYQArN8E8EknlyfXn6G5AoqkEsQZGqtJOD8sfti0m4kYiwkQ==", + "node_modules/@angular-devkit/schematics": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.0.0.tgz", + "integrity": "sha512-8zwXp8OTzJO3IY3Ge3lLqXokNAtQy6kM1FeTyPT20M+0AQHTX9WJlGaYEWdLYI9WwNPWy1/Iq6AaZNcR5phPpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "21.0.0", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.19", + "ora": "9.0.0", + "rxjs": "7.8.2" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/build": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.0.0.tgz", + "integrity": "sha512-TobXT9fXZVee1yULlcOVowOurCUoJlku8st5vzkRZekP520qRjBSEbIk8V2emkFbzgzOeJUtXv1pvrBY7yAYhQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2003.4", - "@babel/core": "7.28.3", + "@angular-devkit/architect": "0.2100.0", + "@babel/core": "7.28.4", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", - "@inquirer/confirm": "5.1.14", + "@inquirer/confirm": "5.1.19", "@vitejs/plugin-basic-ssl": "2.1.0", "beasties": "0.3.5", - "browserslist": "^4.23.0", - "esbuild": "0.25.9", + "browserslist": "^4.26.0", + "esbuild": "0.26.0", "https-proxy-agent": "7.0.6", "istanbul-lib-instrument": "6.0.3", "jsonc-parser": "3.3.1", - "listr2": "9.0.1", - "magic-string": "0.30.17", + "listr2": "9.0.5", + "magic-string": "0.30.19", "mrmime": "2.0.1", "parse5-html-rewriting-stream": "8.0.0", "picomatch": "4.0.3", "piscina": "5.1.3", - "rollup": "4.52.3", - "sass": "1.90.0", - "semver": "7.7.2", + "rolldown": "1.0.0-beta.47", + "sass": "1.93.2", + "semver": "7.7.3", "source-map-support": "0.5.21", - "tinyglobby": "0.2.14", - "vite": "7.1.5", + "tinyglobby": "0.2.15", + "undici": "7.16.0", + "vite": "7.2.2", "watchpack": "2.4.4" }, "engines": { @@ -451,25 +366,25 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "lmdb": "3.4.2" + "lmdb": "3.4.3" }, "peerDependencies": { - "@angular/compiler": "^20.0.0", - "@angular/compiler-cli": "^20.0.0", - "@angular/core": "^20.0.0", - "@angular/localize": "^20.0.0", - "@angular/platform-browser": "^20.0.0", - "@angular/platform-server": "^20.0.0", - "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.3.4", + "@angular/compiler": "^21.0.0", + "@angular/compiler-cli": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/localize": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "@angular/platform-server": "^21.0.0", + "@angular/service-worker": "^21.0.0", + "@angular/ssr": "^21.0.0", "karma": "^6.4.0", "less": "^4.2.0", - "ng-packagr": "^20.0.0", + "ng-packagr": "^21.0.0", "postcss": "^8.4.0", "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", "tslib": "^2.3.0", - "typescript": ">=5.8 <6.0", - "vitest": "^3.1.1" + "typescript": ">=5.9 <6.0", + "vitest": "^4.0.8" }, "peerDependenciesMeta": { "@angular/core": { @@ -510,638 +425,457 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular/build/node_modules/@vitejs/plugin-basic-ssl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.0.tgz", - "integrity": "sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==", + "node_modules/@angular/build/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "peerDependencies": { - "vite": "^6.0.0 || ^7.0.0" + "node": ">=18" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular/build/node_modules/tinyglobby": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", - "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "node_modules/@angular/build/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "fdir": "^6.4.4", - "picomatch": "^4.0.2" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "node": ">=18" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular/build/node_modules/vite": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz", - "integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==", + "node_modules/@angular/build/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular/build/node_modules/vite/node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "node_modules/@angular/build/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "node": ">=18" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@inquirer/confirm": { - "version": "5.1.14", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", - "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", + "node_modules/@angular/build/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@inquirer/core": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.2.tgz", - "integrity": "sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==", + "node_modules/@angular/build/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.0", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", - "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@inquirer/type": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", - "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "node_modules/@angular/build/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@types/node": { - "version": "24.7.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz", - "integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==", + "node_modules/@angular/build/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", "optional": true, - "peer": true, - "dependencies": { - "undici-types": "~7.14.0" + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@angular-devkit/build-angular/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@angular/build/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@angular-devkit/build-angular/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@angular/build/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=18" } }, - "node_modules/@angular-devkit/build-angular/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular-devkit/build-angular/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/@angular/build/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@angular-devkit/build-angular/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/@angular/build/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@angular-devkit/build-angular/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/@angular/build/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@angular-devkit/build-angular/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/@angular/build/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.2003.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2003.4.tgz", - "integrity": "sha512-p5nBSTu9ijz+v3ku+eWc8m+nYjn8q36dkupoKUCgaG1UkPTeHvgI341xPqvY1uxyYzCaxuUms44XIkdAJbmzww==", + "node_modules/@angular/build/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@angular-devkit/architect": "0.2003.4", - "rxjs": "7.8.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^5.0.2" + "node": ">=18" } }, - "node_modules/@angular-devkit/core": { - "version": "20.3.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.4.tgz", - "integrity": "sha512-r83jn9yVdPh618oGgoKPggMsQGOkQqJbxEutd4CE9mnotPCE2uRTIyaFMh8sohNUeoQNRmj9rbr2pWGVlgERpg==", + "node_modules/@angular/build/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.3", - "rxjs": "7.8.2", - "source-map": "0.7.6" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^4.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@angular-devkit/schematics": { - "version": "20.3.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.4.tgz", - "integrity": "sha512-JYlcmVBKNT9+cQ6T2tmu+yVQ2bJk8tG0mXvPHWXrl/M4c6NObhSSThK50tJHy0Xo3gl8WgogOxUeJNnBq67cIQ==", + "node_modules/@angular/build/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@angular-devkit/core": "20.3.4", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.17", - "ora": "8.2.0", - "rxjs": "7.8.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=18" } }, - "node_modules/@angular/cdk": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.7.tgz", - "integrity": "sha512-QTqxPJSMXyjaswtpUrziwdoKRhqT2P9/Ascwzjg8T/SofV1850pc3YmonoOFrurYrmd4plZzWdr7raGcBWIh/Q==", + "node_modules/@angular/build/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "parse5": "^8.0.0", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/common": "^20.0.0 || ^21.0.0", - "@angular/core": "^20.0.0 || ^21.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@angular/cli": { - "version": "20.3.4", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.4.tgz", - "integrity": "sha512-aNPk9ljY2PTc+ZoA7M67rxNvhbUJvzkuYcAdJuHbAIDoWcr2HhyFM2aGrLH3DVemY39xN/haJHj3FYJ8rCdXNw==", + "node_modules/@angular/build/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@angular-devkit/architect": "0.2003.4", - "@angular-devkit/core": "20.3.4", - "@angular-devkit/schematics": "20.3.4", - "@inquirer/prompts": "7.8.2", - "@listr2/prompt-adapter-inquirer": "3.0.1", - "@modelcontextprotocol/sdk": "1.17.3", - "@schematics/angular": "20.3.4", - "@yarnpkg/lockfile": "1.1.0", - "algoliasearch": "5.35.0", - "ini": "5.0.0", - "jsonc-parser": "3.3.1", - "listr2": "9.0.1", - "npm-package-arg": "13.0.0", - "pacote": "21.0.0", - "resolve": "1.22.10", - "semver": "7.7.2", - "yargs": "18.0.0", - "zod": "3.25.76" - }, - "bin": { - "ng": "bin/ng.js" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=18" } }, - "node_modules/@angular/cli/node_modules/@inquirer/checkbox": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.4.tgz", - "integrity": "sha512-2n9Vgf4HSciFq8ttKXk+qy+GsyTXPV1An6QAwe/8bkbbqvG4VW1I/ZY1pNu2rf+h9bdzMLPbRSfcNxkHBy/Ydw==", + "node_modules/@angular/build/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.0", - "@inquirer/core": "^10.2.2", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@angular/cli/node_modules/@inquirer/confirm": { - "version": "5.1.18", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.18.tgz", - "integrity": "sha512-MilmWOzHa3Ks11tzvuAmFoAd/wRuaP3SwlT1IZhyMke31FKLxPiuDWcGXhU+PKveNOpAc4axzAgrgxuIJJRmLw==", + "node_modules/@angular/build/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@angular/cli/node_modules/@inquirer/core": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.2.tgz", - "integrity": "sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==", + "node_modules/@angular/build/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.0", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", - "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@angular/cli/node_modules/@inquirer/editor": { - "version": "4.2.20", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.20.tgz", - "integrity": "sha512-7omh5y5bK672Q+Brk4HBbnHNowOZwrb/78IFXdrEB9PfdxL3GudQyDk8O9vQ188wj3xrEebS2M9n18BjJoI83g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/external-editor": "^1.0.2", - "@inquirer/type": "^3.0.8" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@angular/cli/node_modules/@inquirer/expand": { - "version": "4.0.20", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.20.tgz", - "integrity": "sha512-Dt9S+6qUg94fEvgn54F2Syf0Z3U8xmnBI9ATq2f5h9xt09fs2IJXSCIXyyVHwvggKWFXEY/7jATRo2K6Dkn6Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@angular/cli/node_modules/@inquirer/external-editor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", - "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", + "node_modules/@angular/build/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "chardet": "^2.1.0", - "iconv-lite": "^0.7.0" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@angular/cli/node_modules/@inquirer/input": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.4.tgz", - "integrity": "sha512-cwSGpLBMwpwcZZsc6s1gThm0J+it/KIJ+1qFL2euLmSKUMGumJ5TcbMgxEjMjNHRGadouIYbiIgruKoDZk7klw==", + "node_modules/@angular/build/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@angular/cli/node_modules/@inquirer/number": { - "version": "3.0.20", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.20.tgz", - "integrity": "sha512-bbooay64VD1Z6uMfNehED2A2YOPHSJnQLs9/4WNiV/EK+vXczf/R988itL2XLDGTgmhMF2KkiWZo+iEZmc4jqg==", + "node_modules/@angular/build/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@angular/cli/node_modules/@inquirer/password": { - "version": "4.0.20", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.20.tgz", - "integrity": "sha512-nxSaPV2cPvvoOmRygQR+h0B+Av73B01cqYLcr7NXcGXhbmsYfUb8fDdw2Us1bI2YsX+VvY7I7upgFYsyf8+Nug==", + "node_modules/@angular/build/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.0", - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@angular/cli/node_modules/@inquirer/prompts": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.2.tgz", - "integrity": "sha512-nqhDw2ZcAUrKNPwhjinJny903bRhI0rQhiDz1LksjeRxqa36i3l75+4iXbOy0rlDpLJGxqtgoPavQjmmyS5UJw==", + "node_modules/@angular/build/node_modules/@inquirer/confirm": { + "version": "5.1.19", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.19.tgz", + "integrity": "sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.2.1", - "@inquirer/confirm": "^5.1.14", - "@inquirer/editor": "^4.2.17", - "@inquirer/expand": "^4.0.17", - "@inquirer/input": "^4.2.1", - "@inquirer/number": "^3.0.17", - "@inquirer/password": "^4.0.17", - "@inquirer/rawlist": "^4.1.5", - "@inquirer/search": "^3.1.0", - "@inquirer/select": "^4.3.1" + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -1155,16 +889,21 @@ } } }, - "node_modules/@angular/cli/node_modules/@inquirer/rawlist": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.8.tgz", - "integrity": "sha512-CQ2VkIASbgI2PxdzlkeeieLRmniaUU1Aoi5ggEdm6BIyqopE9GuDXdDOj9XiwOqK5qm72oI2i6J+Gnjaa26ejg==", + "node_modules/@angular/build/node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -1178,18 +917,12 @@ } } }, - "node_modules/@angular/cli/node_modules/@inquirer/search": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.3.tgz", - "integrity": "sha512-D5T6ioybJJH0IiSUK/JXcoRrrm8sXwzrVMjibuPs+AgxmogKslaafy1oxFiorNI4s3ElSkeQZbhYQgLqiL8h6Q==", + "node_modules/@angular/build/node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" - }, "engines": { "node": ">=18" }, @@ -1202,79 +935,32 @@ } } }, - "node_modules/@angular/cli/node_modules/@inquirer/select": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.4.tgz", - "integrity": "sha512-Qp20nySRmfbuJBBsgPU7E/cL62Hf250vMZRzYDcBHty2zdD1kKCnoDFWRr0WO2ZzaXp3R7a4esaVGJUx0E6zvA==", + "node_modules/@angular/build/node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@inquirer/ansi": "^1.0.0", - "@inquirer/core": "^10.2.2", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@angular/cli/node_modules/@inquirer/type": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", - "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "undici-types": "~7.16.0" } }, - "node_modules/@angular/cli/node_modules/@listr2/prompt-adapter-inquirer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.1.tgz", - "integrity": "sha512-3XFmGwm3u6ioREG+ynAQB7FoxfajgQnMhIu8wC5eo/Lsih4aKDg0VuIMGaOsYn7hJSJagSeaD4K8yfpkEoDEmA==", + "node_modules/@angular/build/node_modules/@vitejs/plugin-basic-ssl": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.0.tgz", + "integrity": "sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==", "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/type": "^3.0.7" - }, "engines": { - "node": ">=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "peerDependencies": { - "@inquirer/prompts": ">= 3 < 8", - "listr2": "9.0.1" - } - }, - "node_modules/@angular/cli/node_modules/@types/node": { - "version": "24.7.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz", - "integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": "~7.14.0" + "vite": "^6.0.0 || ^7.0.0" } }, - "node_modules/@angular/cli/node_modules/ansi-regex": { + "node_modules/@angular/build/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", @@ -1284,7 +970,7 @@ "node": ">=8" } }, - "node_modules/@angular/cli/node_modules/ansi-styles": { + "node_modules/@angular/build/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -1300,31 +986,7 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@angular/cli/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular/cli/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@angular/cli/node_modules/is-fullwidth-code-point": { + "node_modules/@angular/build/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", @@ -1334,7 +996,7 @@ "node": ">=8" } }, - "node_modules/@angular/cli/node_modules/string-width": { + "node_modules/@angular/build/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", @@ -1349,7 +1011,7 @@ "node": ">=8" } }, - "node_modules/@angular/cli/node_modules/strip-ansi": { + "node_modules/@angular/build/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -1362,1884 +1024,1775 @@ "node": ">=8" } }, - "node_modules/@angular/cli/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/@angular/build/node_modules/vite": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz", + "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@angular/common": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.3.tgz", - "integrity": "sha512-iArFCXvgYJCpxLZv8o6rV7Cxuqv1hbndoeUmQgL7ekXwVS6BA49VErXbTPM+pfhAJ+v1fc/DG3rzBwXk3eW2lw==", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, - "peerDependencies": { - "@angular/core": "20.3.3", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/compiler": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.3.tgz", - "integrity": "sha512-7AUtF7PO8xo+jOgrhLRPXmt65M/KFuYIsVZGVLB1FTCUAPByFJEUYOSnUuHyvFQQqHesK4aYSP27slDpHH/PSA==", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/@angular/compiler-cli": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.3.tgz", - "integrity": "sha512-kSIE6hkTiZGiJLyisp5Q6NXOHiDNOItp7N2HVNPrK1bqzM8foN6H6BE1a+LYO3Lwy3PkwQFzx03BnzxkM4sWng==", - "license": "MIT", - "dependencies": { - "@babel/core": "7.28.3", - "@jridgewell/sourcemap-codec": "^1.4.14", - "chokidar": "^4.0.0", - "convert-source-map": "^1.5.1", - "reflect-metadata": "^0.2.0", - "semver": "^7.0.0", - "tslib": "^2.3.0", - "yargs": "^18.0.0" + "node": "^20.19.0 || >=22.12.0" }, - "bin": { - "ng-xi18n": "bundles/src/bin/ng_xi18n.js", - "ngc": "bundles/src/bin/ngc.js" + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "@angular/compiler": "20.3.3", - "typescript": ">=5.8 <6.0" + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { - "typescript": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } }, - "node_modules/@angular/core": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.3.tgz", - "integrity": "sha512-AWBCixxw4N9VgKT1uwrRPr1dH3CpT/ffcCsXJQ8TjzsKYjVBkXVht5OjtxJOWOQ2KaHwsGFEmDMv9fc1BHDFhQ==", + "node_modules/@angular/build/node_modules/vite/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": ">=18" }, - "peerDependencies": { - "@angular/compiler": "20.3.3", - "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.15.0" + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/@angular/build/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, - "peerDependenciesMeta": { - "@angular/compiler": { - "optional": true - }, - "zone.js": { - "optional": true - } + "engines": { + "node": ">=8" } }, - "node_modules/@angular/forms": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.3.tgz", - "integrity": "sha512-Rv3sO1vOAbw03IRK30CB45eucxZ1rI0Jyaa6QVmDlOzQ4bktkanbGxQtaxBdc9bKPBO1SVx27eTbStR7i3BNRg==", + "node_modules/@angular/cdk": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.0.0.tgz", + "integrity": "sha512-wCr5D3mEC+p69IMDC7vf8bWx18mfUNNRdsiK3XD0m1PqfeNfnCJb+Bnkks37MC/SU01uCNrAokRaTbWL6pk1Wg==", "license": "MIT", "dependencies": { + "parse5": "^8.0.0", "tslib": "^2.3.0" }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, "peerDependencies": { - "@angular/common": "20.3.3", - "@angular/core": "20.3.3", - "@angular/platform-browser": "20.3.3", + "@angular/common": "^21.0.0 || ^22.0.0", + "@angular/core": "^21.0.0 || ^22.0.0", "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/localize": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-20.3.3.tgz", - "integrity": "sha512-myToeQiFPzOxXu5CBoQPnMPCpM4HtQh9m+tiL5RsMtZs5NrD3DX9QxzVJl2Y4nozpphfQejoI1t2fbS7yM5qAQ==", + "node_modules/@angular/cli": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.0.0.tgz", + "integrity": "sha512-713DfTD/ThIy/BOmZ+8zhXo/OhPE9jYaAS0UhXVhtp2ptqzRqSzLvW9fWgtqP4ITAqulOoitiWPLXxOEQ2Cixw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "7.28.3", - "@types/babel__core": "7.20.5", - "tinyglobby": "^0.2.12", - "yargs": "^18.0.0" + "@angular-devkit/architect": "0.2100.0", + "@angular-devkit/core": "21.0.0", + "@angular-devkit/schematics": "21.0.0", + "@inquirer/prompts": "7.9.0", + "@listr2/prompt-adapter-inquirer": "3.0.5", + "@modelcontextprotocol/sdk": "1.20.1", + "@schematics/angular": "21.0.0", + "@yarnpkg/lockfile": "1.1.0", + "algoliasearch": "5.40.1", + "ini": "5.0.0", + "jsonc-parser": "3.3.1", + "listr2": "9.0.5", + "npm-package-arg": "13.0.1", + "pacote": "21.0.3", + "parse5-html-rewriting-stream": "8.0.0", + "resolve": "1.22.11", + "semver": "7.7.3", + "yargs": "18.0.0", + "zod": "3.25.76" }, "bin": { - "localize-extract": "tools/bundles/src/extract/cli.js", - "localize-migrate": "tools/bundles/src/migrate/cli.js", - "localize-translate": "tools/bundles/src/translate/cli.js" + "ng": "bin/ng.js" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "@angular/compiler": "20.3.3", - "@angular/compiler-cli": "20.3.3" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, - "node_modules/@angular/material": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-20.2.7.tgz", - "integrity": "sha512-VXsP5qkQQ3sCGkSHsgDku/OVlunGsqssOM057foOKJuajECsI3ZpGuLJ13nvLm9Z147UZOZfP463ixZIjd4XuQ==", + "node_modules/@angular/cli/node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "dev": true, "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" }, "peerDependencies": { - "@angular/cdk": "20.2.7", - "@angular/common": "^20.0.0 || ^21.0.0", - "@angular/core": "^20.0.0 || ^21.0.0", - "@angular/forms": "^20.0.0 || ^21.0.0", - "@angular/platform-browser": "^20.0.0 || ^21.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@angular/material-luxon-adapter": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/@angular/material-luxon-adapter/-/material-luxon-adapter-20.2.7.tgz", - "integrity": "sha512-6L6NU1q7OWzxQ2uLQtNAGHOp4M1p/lAB2UKc5Z/F3myWx6njJMgAtxuuq7xvaCY2TyDUP7n5bFAPmGB9fmiyZQ==", + "node_modules/@angular/cli/node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "dev": true, "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" }, "peerDependencies": { - "@angular/core": "^20.0.0 || ^21.0.0", - "@angular/material": "20.2.7", - "luxon": "^3.0.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@angular/platform-browser": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.3.tgz", - "integrity": "sha512-RUWpg49GnXdINjomRFrE/SRioxEehYqUzDVskDWddNeNhV9Z21zeC6Ao2i5q8UKq0y/oq2ShX7XFLprxqLoLnQ==", + "node_modules/@angular/cli/node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "dev": true, "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": ">=18" }, "peerDependencies": { - "@angular/animations": "20.3.3", - "@angular/common": "20.3.3", - "@angular/core": "20.3.3" + "@types/node": ">=18" }, "peerDependenciesMeta": { - "@angular/animations": { + "@types/node": { "optional": true } } }, - "node_modules/@angular/platform-browser-dynamic": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.3.3.tgz", - "integrity": "sha512-QzJUeHgzUWpNrPF4tgqwO3jzmDGlM8aLwbA7BJBp2BOJZKg34BF4CzTngK5Z6LWcZ4gofTSzDOw9TIrk8U8g6Q==", + "node_modules/@angular/cli/node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", + "dev": true, "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": ">=18" }, "peerDependencies": { - "@angular/common": "20.3.3", - "@angular/compiler": "20.3.3", - "@angular/core": "20.3.3", - "@angular/platform-browser": "20.3.3" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@angular/router": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.3.tgz", - "integrity": "sha512-IrO5GY/vmaWwNdfR51xswNnBSxeEuvQAUqK3H0UNxhZlIE9gUS6pbbSidGGrQOZK+i0nd/rDz7j+RV7h2NK9aA==", + "node_modules/@angular/cli/node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", + "dev": true, "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": ">=18" }, "peerDependencies": { - "@angular/common": "20.3.3", - "@angular/core": "20.3.3", - "@angular/platform-browser": "20.3.3", - "rxjs": "^6.5.3 || ^7.4.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "node_modules/@angular/cli/node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "node_modules/@angular/cli/node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", + "dev": true, "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/core": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", - "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", + "node_modules/@angular/cli/node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", + "dev": true, "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.3", - "@babel/parser": "^7.28.3", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "license": "MIT" - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "node_modules/@angular/cli/node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "node_modules/@angular/cli/node_modules/@inquirer/prompts": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.9.0.tgz", + "integrity": "sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@inquirer/checkbox": "^4.3.0", + "@inquirer/confirm": "^5.1.19", + "@inquirer/editor": "^4.2.21", + "@inquirer/expand": "^4.0.21", + "@inquirer/input": "^4.2.5", + "@inquirer/number": "^3.0.21", + "@inquirer/password": "^4.0.21", + "@inquirer/rawlist": "^4.1.9", + "@inquirer/search": "^3.2.0", + "@inquirer/select": "^4.4.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "node_modules/@angular/cli/node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", - "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "node_modules/@angular/cli/node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.3", - "semver": "^6.3.1" + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", - "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "node_modules/@angular/cli/node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "regexpu-core": "^6.2.0", - "semver": "^6.3.1" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "node_modules/@angular/cli/node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" + "engines": { + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "node_modules/@angular/cli/node_modules/@listr2/prompt-adapter-inquirer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.5.tgz", + "integrity": "sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==", + "dev": true, "license": "MIT", + "dependencies": { + "@inquirer/type": "^3.0.8" + }, "engines": { - "node": ">=6.9.0" + "node": ">=20.0.0" + }, + "peerDependencies": { + "@inquirer/prompts": ">= 3 < 8", + "listr2": "9.0.5" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", - "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "node_modules/@angular/cli/node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "undici-types": "~7.16.0" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "node_modules/@angular/cli/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "node_modules/@angular/cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=6.9.0" + "node": ">=8" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "node_modules/@angular/cli/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "node_modules/@angular/cli/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "node_modules/@angular/cli/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=8" } }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "node_modules/@angular/cli/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=8" } }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "node_modules/@angular/cli/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, + "node_modules/@angular/common": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.0.0.tgz", + "integrity": "sha512-uFvQDYU5X5nEnI9C4Bkdxcu4aIzNesGLJzmFlnwChVxB4BxIRF0uHL0oRhdkInGTIzPDJPH4nF6B/22c5gDVqA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/core": "21.0.0", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "node_modules/@angular/compiler": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.0.0.tgz", + "integrity": "sha512-6jCH3UYga5iokj5F40SR4dlwo9ZRMkT8YzHCTijwZuDX9zvugp9jPof092RvIeNsTvCMVfGWuM9yZ1DRUsU/yg==", "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "node_modules/@angular/compiler-cli": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.0.0.tgz", + "integrity": "sha512-KTXp+e2UPGyfFew6Wq95ULpHWQ20dhqkAMZ6x6MCYfOe2ccdnGYsAbLLmnWGmSg5BaOI4B0x/1XCFZf/n6WDgA==", "license": "MIT", + "dependencies": { + "@babel/core": "7.28.4", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^4.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.2.0", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^18.0.0" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js" + }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/compiler": "21.0.0", + "typescript": ">=5.9 <6.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", - "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", - "dev": true, + "node_modules/@angular/core": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.0.0.tgz", + "integrity": "sha512-bqi8fT4csyITeX8vdN5FJDBWx5wuWzdCg4mKSjHd+onVzZLyZ8bcnuAKz4mklgvjvwuXoRYukmclUurLwfq3Rg==", "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/compiler": "21.0.0", + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.15.0" + }, + "peerDependenciesMeta": { + "@angular/compiler": { + "optional": true + }, + "zone.js": { + "optional": true + } } }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "node_modules/@angular/forms": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.0.0.tgz", + "integrity": "sha512-kcudwbZs/ddKqaELz4eEW9kOGCsX61qsf9jkQsGTARBEOUcU2K+rM6mX5sTf9azHvQ9wlX4N36h0eYzBA4Y4Qg==", "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/common": "21.0.0", + "@angular/core": "21.0.0", + "@angular/platform-browser": "21.0.0", + "@standard-schema/spec": "^1.0.0", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "node_modules/@angular/localize": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-21.0.0.tgz", + "integrity": "sha512-SHK/D6nYkbn3VrM7sZtipiayICc8S6IZyjd4/5ARLeZJ/giYAxqv++bV0EV1MEayAZi4g6t0qsUY4KolDClphQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" + "@babel/core": "7.28.4", + "@types/babel__core": "7.20.5", + "tinyglobby": "^0.2.12", + "yargs": "^18.0.0" }, "bin": { - "parser": "bin/babel-parser.js" + "localize-extract": "tools/bundles/src/extract/cli.js", + "localize-migrate": "tools/bundles/src/migrate/cli.js", + "localize-translate": "tools/bundles/src/translate/cli.js" }, "engines": { - "node": ">=6.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/compiler": "21.0.0", + "@angular/compiler-cli": "21.0.0" } }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", - "dev": true, + "node_modules/@angular/material": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-21.0.0.tgz", + "integrity": "sha512-s3+fhN7F5T1TAltZXYXOgY1wuVbICCrBJpV2TN8nJXDT0wroTYAljgBmsr6ZjDwYJewwP0OPvcj2NlOGDpa6oA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "tslib": "^2.3.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@angular/cdk": "21.0.0", + "@angular/common": "^21.0.0 || ^22.0.0", + "@angular/core": "^21.0.0 || ^22.0.0", + "@angular/forms": "^21.0.0 || ^22.0.0", + "@angular/platform-browser": "^21.0.0 || ^22.0.0", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", - "dev": true, + "node_modules/@angular/material-luxon-adapter": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/material-luxon-adapter/-/material-luxon-adapter-21.0.0.tgz", + "integrity": "sha512-83oof7/D2XFsgscrTvVhDNnUKqECTNDVpPFXcbLXwNTQZ+ZUXvpPcVpon99UJMj3+nZlwWHyOQsycxBMO2WGTw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "tslib": "^2.3.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@angular/core": "^21.0.0 || ^22.0.0", + "@angular/material": "21.0.0", + "luxon": "^3.7.2" } }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", - "dev": true, + "node_modules/@angular/platform-browser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.0.0.tgz", + "integrity": "sha512-KQrANla4RBLhcGkwlndqsKzBwVFOWQr1640CfBVjj2oz4M3dW5hyMtXivBACvuwyUhYU/qJbqlDMBXl/OUSudQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@angular/animations": "21.0.0", + "@angular/common": "21.0.0", + "@angular/core": "21.0.0" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } } }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "dev": true, + "node_modules/@angular/router": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.0.0.tgz", + "integrity": "sha512-ARx1R2CmTgAezlMkUpV40V4T/IbXhL7dm4SuMVKbuEOsCKZC0TLOSSTsGYY7HKem45JHlJaByv819cJnabFgBg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.13.0" + "@angular/common": "21.0.0", + "@angular/core": "21.0.0", + "@angular/platform-browser": "21.0.0", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", - "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", - "dev": true, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "license": "MIT", "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", - "dev": true, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "dev": true, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", - "dev": true, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-async-generator-functions": { + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", - "dev": true, + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-async-to-generator": { + "node_modules/@babel/helper-module-imports": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", - "dev": true, + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", - "dev": true, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz", - "integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-class-properties": { + "node_modules/@babel/helper-string-parser": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", - "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", - "dev": true, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" } }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", - "dev": true, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" - }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", - "dev": true, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", - "dev": true, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/types": "^7.28.5" }, - "engines": { - "node": ">=6.9.0" + "bin": { + "parser": "bin/babel-parser.js" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", - "dev": true, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", - "dev": true, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", - "dev": true, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", - "dev": true, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" - }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=0.1.90" } }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", - "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "node_modules/@emnapi/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "tslib": "^2.4.0" } }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.26.0.tgz", + "integrity": "sha512-hj0sKNCQOOo2fgyII3clmJXP28VhgDfU5iy3GNHlWO76KG6N7x4D9ezH5lJtQTG+1J6MFDAJXC1qsI+W+LvZoA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "node_modules/@esbuild/android-arm": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.26.0.tgz", + "integrity": "sha512-C0hkDsYNHZkBtPxxDx177JN90/1MiCpvBNjz1f5yWJo1+5+c5zr8apjastpEG+wtPjo9FFtGG7owSsAxyKiHxA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "node_modules/@esbuild/android-arm64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.26.0.tgz", + "integrity": "sha512-DDnoJ5eoa13L8zPh87PUlRd/IyFaIKOlRbxiwcSbeumcJ7UZKdtuMCHa1Q27LWQggug6W4m28i4/O2qiQQ5NZQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "node_modules/@esbuild/android-x64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.26.0.tgz", + "integrity": "sha512-bKDkGXGZnj0T70cRpgmv549x38Vr2O3UWLbjT2qmIkdIWcmlg8yebcFWoT9Dku7b5OV3UqPEuNKRzlNhjwUJ9A==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.26.0.tgz", + "integrity": "sha512-6Z3naJgOuAIB0RLlJkYc81An3rTlQ/IeRdrU3dOea8h/PvZSgitZV+thNuIccw0MuK1GmIAnAmd5TrMZad8FTQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.26.0.tgz", + "integrity": "sha512-OPnYj0zpYW0tHusMefyaMvNYQX5pNQuSsHFTHUBNp3vVXupwqpxofcjVsUx11CQhGVkGeXjC3WLjh91hgBG2xw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.26.0.tgz", + "integrity": "sha512-jix2fa6GQeZhO1sCKNaNMjfj5hbOvoL2F5t+w6gEPxALumkpOV/wq7oUBMHBn2hY2dOm+mEV/K+xfZy3mrsxNQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.26.0.tgz", + "integrity": "sha512-tccJaH5xHJD/239LjbVvJwf6T4kSzbk6wPFerF0uwWlkw/u7HL+wnAzAH5GB2irGhYemDgiNTp8wJzhAHQ64oA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "node_modules/@esbuild/linux-arm": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.26.0.tgz", + "integrity": "sha512-JY8NyU31SyRmRpuc5W8PQarAx4TvuYbyxbPIpHAZdr/0g4iBr8KwQBS4kiiamGl2f42BBecHusYCsyxi7Kn8UQ==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.26.0.tgz", + "integrity": "sha512-IMJYN7FSkLttYyTbsbme0Ra14cBO5z47kpamo16IwggzzATFY2lcZAwkbcNkWiAduKrTgFJP7fW5cBI7FzcuNQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.26.0.tgz", + "integrity": "sha512-XITaGqGVLgk8WOHw8We9Z1L0lbLFip8LyQzKYFKO4zFo1PFaaSKsbNjvkb7O8kEXytmSGRkYpE8LLVpPJpsSlw==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.26.0.tgz", + "integrity": "sha512-MkggfbDIczStUJwq9wU7gQ7kO33d8j9lWuOCDifN9t47+PeI+9m2QVh51EI/zZQ1spZtFMC1nzBJ+qNGCjJnsg==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.26.0.tgz", + "integrity": "sha512-fUYup12HZWAeccNLhQ5HwNBPr4zXCPgUWzEq2Rfw7UwqwfQrFZ0SR/JljaURR8xIh9t+o1lNUFTECUTmaP7yKA==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", - "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.26.0.tgz", + "integrity": "sha512-MzRKhM0Ip+//VYwC8tialCiwUQ4G65WfALtJEFyU0GKJzfTYoPBw5XNWf0SLbCUYQbxTKamlVwPmcw4DgZzFxg==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.4" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.26.0.tgz", + "integrity": "sha512-QhCc32CwI1I4Jrg1enCv292sm3YJprW8WHHlyxJhae/dVs+KRWkbvz2Nynl5HmZDW/m9ZxrXayHzjzVNvQMGQA==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.26.0.tgz", + "integrity": "sha512-1D6vi6lfI18aNT1aTf2HV+RIlm6fxtlAp8eOJ4mmnbYmZ4boz8zYDar86sIYNh0wmiLJEbW/EocaKAX6Yso2fw==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "node_modules/@esbuild/linux-x64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.26.0.tgz", + "integrity": "sha512-rnDcepj7LjrKFvZkx+WrBv6wECeYACcFjdNPvVPojCPJD8nHpb3pv3AuR9CXgdnjH1O23btICj0rsp0L9wAnHA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.26.0.tgz", + "integrity": "sha512-FSWmgGp0mDNjEXXFcsf12BmVrb+sZBBBlyh3LwB/B9ac3Kkc8x5D2WimYW9N7SUkolui8JzVnVlWh7ZmjCpnxw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.26.0.tgz", + "integrity": "sha512-0QfciUDFryD39QoSPUDshj4uNEjQhp73+3pbSAaxjV2qGOEDsM67P7KbJq7LzHoVl46oqhIhJ1S+skKGR7lMXA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.26.0.tgz", + "integrity": "sha512-vmAK+nHhIZWImwJ3RNw9hX3fU4UGN/OqbSE0imqljNbUQC3GvVJ1jpwYoTfD6mmXmQaxdJY6Hn4jQbLGJKg5Yw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.26.0.tgz", + "integrity": "sha512-GPXF7RMkJ7o9bTyUsnyNtrFMqgM3X+uM/LWw4CeHIjqc32fm0Ir6jKDnWHpj8xHFstgWDUYseSABK9KCkHGnpg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", - "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.26.0.tgz", + "integrity": "sha512-nUHZ5jEYqbBthbiBksbmHTlbb5eElyVfs/s1iHQ8rLBq1eWsd5maOnDpCocw1OM8kFK747d1Xms8dXJHtduxSw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.26.0.tgz", + "integrity": "sha512-TMg3KCTCYYaVO+R6P5mSORhcNDDlemUVnUbb8QkboUtOhb5JWKAzd5uMIMECJQOxHZ/R+N8HHtDF5ylzLfMiLw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.26.0.tgz", + "integrity": "sha512-apqYgoAUd6ZCb9Phcs8zN32q6l0ZQzQBdVXOofa6WvHDlSOhwCWgSfVQabGViThS40Y1NA4SCvQickgZMFZRlA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.3.tgz", - "integrity": "sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.26.0.tgz", + "integrity": "sha512-FGJAcImbJNZzLWu7U6WB0iKHl4RuY4TsXEwxJPl9UZLS47agIZuILZEX3Pagfw7I4J3ddflomt9f0apfaJSbaw==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "semver": "^6.3.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@esbuild/win32-x64": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.26.0.tgz", + "integrity": "sha512-WAckBKaVnmFqbEhbymrPK7M086DQMpL1XoRbpmN0iW8k5JSXjDRQBhcZNa0VweItknLq9eAeCL34jK7/CDcw7A==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "20 || >=22" } }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@isaacs/balanced-match": "^4.0.1" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "20 || >=22" } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "minipass": "^7.0.4" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=8" } }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", - "dev": true, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", - "dev": true, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@babel/preset-env": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", - "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", - "dev": true, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.0", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.0", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.3", - "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-dotall-regex": "^7.27.1", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.0", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.3", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", - "semver": "^6.3.1" - }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + "node": ">=6.0.0" } }, - "node_modules/@babel/runtime": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", - "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" }, - "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.1.90" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", - "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.4.3.tgz", + "integrity": "sha512-zR6Y45VNtW5s+A+4AyhrJk0VJKhXdkLhrySCpCu7PSdnakebsOzNxf58p5Xoq66vOSuueGAxlqDAF49HwdrSTQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "engines": { - "node": ">=14.17.0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", - "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.4.3.tgz", + "integrity": "sha512-nfGm5pQksBGfaj9uMbjC0YyQreny/Pl7mIDtHtw6g7WQuCgeLullr9FNRsYyKplaEJBPrCVpEjpAznxTBIrXBw==", "cpu": [ - "ppc64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } + "darwin" + ] }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", - "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.4.3.tgz", + "integrity": "sha512-Kjqomp7i0rgSbYSUmv9JnXpS55zYT/YcW3Bdf9oqOTjcH0/8tFAP8MLhu/i9V2pMKIURDZk63Ww49DTK0T3c/Q==", "cpu": [ "arm" ], @@ -3247,16 +2800,13 @@ "license": "MIT", "optional": true, "os": [ - "android" - ], - "engines": { - "node": ">=18" - } + "linux" + ] }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", - "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.4.3.tgz", + "integrity": "sha512-uX9eaPqWb740wg5D3TCvU/js23lSRSKT7lJrrQ8IuEG/VLgpPlxO3lHDywU44yFYdGS7pElBn6ioKFKhvALZlw==", "cpu": [ "arm64" ], @@ -3264,16 +2814,13 @@ "license": "MIT", "optional": true, "os": [ - "android" - ], - "engines": { - "node": ">=18" - } + "linux" + ] }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", - "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.4.3.tgz", + "integrity": "sha512-7/8l20D55CfwdMupkc3fNxNJdn4bHsti2X0cp6PwiXlLeSFvAfWs5kCCx+2Cyje4l4GtN//LtKWjTru/9hDJQg==", "cpu": [ "x64" ], @@ -3281,16 +2828,13 @@ "license": "MIT", "optional": true, "os": [ - "android" - ], - "engines": { - "node": ">=18" - } + "linux" + ] }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", - "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "node_modules/@lmdb/lmdb-win32-arm64": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.4.3.tgz", + "integrity": "sha512-yWVR0e5Gl35EGJBsAuqPOdjtUYuN8CcTLKrqpQFoM+KsMadViVCulhKNhkcjSGJB88Am5bRPjMro4MBB9FS23Q==", "cpu": [ "arm64" ], @@ -3298,33 +2842,75 @@ "license": "MIT", "optional": true, "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } + "win32" + ] }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", - "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", - "cpu": [ + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.4.3.tgz", + "integrity": "sha512-1JdBkcO0Vrua4LUgr4jAe4FUyluwCeq/pDkBrlaVjX3/BBWP1TzVjCL+TibWNQtPAL1BITXPAhlK5Ru4FBd/hg==", + "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" - ], + "win32" + ] + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.20.1.tgz", + "integrity": "sha512-j/P+yuxXfgxb+mW7OEoRCM3G47zCTDqUPivJo/VzpjbG8I9csTXtOprCf5FfOfHK4whOJny0aHuBEON+kS7CCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.6", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.24.1" + }, "engines": { "node": ">=18" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", - "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", "cpu": [ "arm64" ], @@ -3332,16 +2918,13 @@ "license": "MIT", "optional": true, "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } + "darwin" + ] }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", - "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", "cpu": [ "x64" ], @@ -3349,16 +2932,13 @@ "license": "MIT", "optional": true, "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } + "darwin" + ] }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", - "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", "cpu": [ "arm" ], @@ -3367,15 +2947,12 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", - "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", "cpu": [ "arm64" ], @@ -3384,117 +2961,142 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", - "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", "cpu": [ - "ia32" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=18" - } + ] }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", - "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", "cpu": [ - "loong64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" - ], + "win32" + ] + }, + "node_modules/@napi-rs/nice": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", + "dev": true, + "license": "MIT", + "optional": true, "engines": { - "node": ">=18" + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/nice-android-arm-eabi": "1.1.1", + "@napi-rs/nice-android-arm64": "1.1.1", + "@napi-rs/nice-darwin-arm64": "1.1.1", + "@napi-rs/nice-darwin-x64": "1.1.1", + "@napi-rs/nice-freebsd-x64": "1.1.1", + "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/nice-linux-arm64-gnu": "1.1.1", + "@napi-rs/nice-linux-arm64-musl": "1.1.1", + "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", + "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", + "@napi-rs/nice-linux-s390x-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-musl": "1.1.1", + "@napi-rs/nice-openharmony-arm64": "1.1.1", + "@napi-rs/nice-win32-arm64-msvc": "1.1.1", + "@napi-rs/nice-win32-ia32-msvc": "1.1.1", + "@napi-rs/nice-win32-x64-msvc": "1.1.1" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", - "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "node_modules/@napi-rs/nice-android-arm-eabi": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", + "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", "cpu": [ - "mips64el" + "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", - "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "node_modules/@napi-rs/nice-android-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", + "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", "cpu": [ - "ppc64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", - "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "node_modules/@napi-rs/nice-darwin-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", + "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", "cpu": [ - "riscv64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", - "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "node_modules/@napi-rs/nice-darwin-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", + "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", "cpu": [ - "s390x" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", - "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "node_modules/@napi-rs/nice-freebsd-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", + "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", "cpu": [ "x64" ], @@ -3502,50 +3104,50 @@ "license": "MIT", "optional": true, "os": [ - "linux" + "freebsd" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", - "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", "cpu": [ - "arm64" + "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "netbsd" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", - "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "node_modules/@napi-rs/nice-linux-arm64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "netbsd" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", - "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "node_modules/@napi-rs/nice-linux-arm64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", "cpu": [ "arm64" ], @@ -3553,473 +3155,627 @@ "license": "MIT", "optional": true, "os": [ - "openbsd" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", - "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "node_modules/@napi-rs/nice-linux-ppc64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", "cpu": [ - "x64" + "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "openbsd" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", - "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "node_modules/@napi-rs/nice-linux-riscv64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", + "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", "cpu": [ - "arm64" + "riscv64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "openharmony" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", - "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "node_modules/@napi-rs/nice-linux-s390x-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", "cpu": [ - "x64" + "s390x" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "sunos" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", - "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "node_modules/@napi-rs/nice-linux-x64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", - "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "node_modules/@napi-rs/nice-linux-x64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", + "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", "cpu": [ - "ia32" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", - "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "node_modules/@napi-rs/nice-openharmony-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", + "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "openharmony" ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@inquirer/ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz", - "integrity": "sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==", + "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@inquirer/figures": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", - "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", + "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", + "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=18" + "node": ">= 10" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "node_modules/@napi-rs/nice-win32-x64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "20 || >=22" + "node": ">= 10" } }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", + "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@npmcli/agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz", + "integrity": "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==", "dev": true, "license": "ISC", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^8.0.3" }, "engines": { - "node": ">=12" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", "dev": true, - "license": "MIT" + "license": "ISC", + "engines": { + "node": "20 || >=22" + } }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/@npmcli/fs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz", + "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "semver": "^7.3.5" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@npmcli/git": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.1.tgz", + "integrity": "sha512-+XTFxK2jJF/EJJ5SoAzXk3qwIDfvFc5/g+bD274LZ7uY7LE8sTfG6Z8rOanPl2ZEvZWqNvmEdtXC25cE54VcoA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "@npmcli/promise-spawn": "^9.0.0", + "ini": "^6.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^11.0.1", + "proc-log": "^6.0.0", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^6.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "node_modules/@npmcli/git/node_modules/@npmcli/promise-spawn": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz", + "integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^7.0.4" + "which": "^6.0.0" }, "engines": { - "node": ">=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@npmcli/git/node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "license": "ISC", "engines": { - "node": ">=6.0.0" + "node": ">=16" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "license": "ISC", + "engines": { + "node": "20 || >=22" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "node_modules/@npmcli/git/node_modules/proc-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", + "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@jsonjoy.com/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "node_modules/@npmcli/git/node_modules/which": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", + "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" + "bin": { + "node-which": "bin/which.js" }, - "peerDependencies": { - "tslib": "2" + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@jsonjoy.com/buffers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.0.0.tgz", - "integrity": "sha512-NDigYR3PHqCnQLXYyoLbnEdzMMvzeiCWo1KOut7Q0CoIqg9tUAPKJ1iq/2nFhc5kZtexzutNY0LFjdwWL3Dw3Q==", + "node_modules/@npmcli/installed-package-contents": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-3.0.0.tgz", + "integrity": "sha512-fkxoPuFGvxyrH+OQzyTkX2LUEamrF4jZSmxjAtPPHHGO0dqsQ8tTKjnIS8SAnPHdk2I03BDtSMR5K/4loKg79Q==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" + "license": "ISC", + "dependencies": { + "npm-bundled": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" + "bin": { + "installed-package-contents": "bin/index.js" }, - "peerDependencies": { - "tslib": "2" + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/@jsonjoy.com/codegen": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", - "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", + "node_modules/@npmcli/node-gyp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-5.0.0.tgz", + "integrity": "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==", "dev": true, - "license": "Apache-2.0", + "license": "ISC", "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@jsonjoy.com/json-pack": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.14.0.tgz", - "integrity": "sha512-LpWbYgVnKzphN5S6uss4M25jJ/9+m6q6UJoeN6zTkK4xAGhKsiBRPVeF7OYMWonn5repMQbE5vieRXcMUrKDKw==", + "node_modules/@npmcli/package-json": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.4.tgz", + "integrity": "sha512-0wInJG3j/K40OJt/33ax47WfWMzZTm6OQxB9cDhTt5huCP2a9g2GnlsxmfN+PulItNPIpPrZ+kfwwUil7eHcZQ==", "dev": true, - "license": "Apache-2.0", + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "glob": "^13.0.0", + "hosted-git-info": "^9.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.5.3", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/glob": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", + "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@jsonjoy.com/base64": "^1.1.2", - "@jsonjoy.com/buffers": "^1.0.0", - "@jsonjoy.com/codegen": "^1.0.0", - "@jsonjoy.com/json-pointer": "^1.0.1", - "@jsonjoy.com/util": "^1.9.0", - "hyperdyperid": "^1.2.0", - "thingies": "^2.5.0" + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.0" }, "engines": { - "node": ">=10.0" + "node": "20 || >=22" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@jsonjoy.com/json-pointer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", - "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", + "node_modules/@npmcli/package-json/node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", "dev": true, - "license": "Apache-2.0", + "license": "BlueOak-1.0.0", "dependencies": { - "@jsonjoy.com/codegen": "^1.0.0", - "@jsonjoy.com/util": "^1.9.0" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { - "node": ">=10.0" + "node": "20 || >=22" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/package-json/node_modules/proc-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", + "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-8.0.3.tgz", + "integrity": "sha512-Yb00SWaL4F8w+K8YGhQ55+xE4RUNdMHV43WZGsiTM92gS+lC0mGsn7I4hLug7pbao035S6bj3Y3w0cUNGLfmkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^5.0.0" }, - "peerDependencies": { - "tslib": "2" + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/@jsonjoy.com/util": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", - "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "Apache-2.0", + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", "dependencies": { - "@jsonjoy.com/buffers": "^1.0.0", - "@jsonjoy.com/codegen": "^1.0.0" + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" }, "engines": { - "node": ">=10.0" + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz", + "integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.3.tgz", + "integrity": "sha512-ER2N6itRkzWbbtVmZ9WKaWxVlKlOeBFF1/7xx+KA5J1xKa4JjUwBdb6tDpk0v1qA+d+VDwHI9qmLcXSWcmi+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "node-gyp": "^12.1.0", + "proc-log": "^6.0.0", + "which": "^6.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/@npmcli/promise-spawn": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz", + "integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^6.0.0" }, - "peerDependencies": { - "tslib": "2" + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "MIT" + "license": "ISC", + "engines": { + "node": ">=16" + } }, - "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.4.2.tgz", - "integrity": "sha512-NK80WwDoODyPaSazKbzd3NEJ3ygePrkERilZshxBViBARNz21rmediktGHExoj9n5t9+ChlgLlxecdFKLCuCKg==", - "cpu": [ - "arm64" - ], + "node_modules/@npmcli/run-script/node_modules/proc-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", + "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", + "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.96.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.96.0.tgz", + "integrity": "sha512-r/xkmoXA0xEpU6UGtn18CNVjXH6erU3KCpCDbpLmbVxBFor1U9MqN5Z2uMmCHJuXjJzlnDR+hWY+yPoLo8oHDw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", "dev": true, + "hasInstallScript": true, "license": "MIT", "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } }, - "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.4.2.tgz", - "integrity": "sha512-zevaowQNmrp3U7Fz1s9pls5aIgpKRsKb3dZWDINtLiozh3jZI9fBrI19lYYBxqdyiIyNdlyiidPnwPShj4aK+w==", + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" - ] + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@lmdb/lmdb-linux-arm": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.4.2.tgz", - "integrity": "sha512-OmHCULY17rkx/RoCoXlzU7LyR8xqrksgdYWwtYa14l/sseezZ8seKWXcogHcjulBddER5NnEFV4L/Jtr2nyxeg==", + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", "cpu": [ - "arm" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" - ] + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.4.2.tgz", - "integrity": "sha512-ZBEfbNZdkneebvZs98Lq30jMY8V9IJzckVeigGivV7nTHJc+89Ctomp1kAIWKlwIG0ovCDrFI448GzFPORANYg==", + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" - ] + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@lmdb/lmdb-linux-x64": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.4.2.tgz", - "integrity": "sha512-vL9nM17C77lohPYE4YaAQvfZCSVJSryE4fXdi8M7uWPBnU+9DJabgKVAeyDb84ZM2vcFseoBE4/AagVtJeRE7g==", + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", "cpu": [ "x64" ], @@ -4027,89 +3783,62 @@ "license": "MIT", "optional": true, "os": [ - "linux" - ] + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@lmdb/lmdb-win32-arm64": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.4.2.tgz", - "integrity": "sha512-SXWjdBfNDze4ZPeLtYIzsIeDJDJ/SdsA0pEXcUBayUIMO0FQBHfVZZyHXQjjHr4cvOAzANBgIiqaXRwfMhzmLw==", + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", "cpu": [ - "arm64" + "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ] + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@lmdb/lmdb-win32-x64": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.4.2.tgz", - "integrity": "sha512-IY+r3bxKW6Q6sIPiMC0L533DEfRJSXibjSI3Ft/w9Q8KQBNqEIvUFXt+09wV8S5BRk0a8uSF19YWxuRwEfI90g==", + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", "cpu": [ - "x64" + "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ] - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz", - "integrity": "sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.6", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.24.1" - }, + "linux" + ], "engines": { - "node": ">=18" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "node": ">= 10.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", - "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", "cpu": [ "arm64" ], @@ -4117,55 +3846,62 @@ "license": "MIT", "optional": true, "os": [ - "darwin" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", - "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", - "cpu": [ - "x64" + "linux" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", - "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", "cpu": [ - "arm" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", - "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", - "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", "cpu": [ "x64" ], @@ -4174,77 +3910,82 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", - "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@napi-rs/nice": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", - "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 10" + "node": ">= 10.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "optionalDependencies": { - "@napi-rs/nice-android-arm-eabi": "1.1.1", - "@napi-rs/nice-android-arm64": "1.1.1", - "@napi-rs/nice-darwin-arm64": "1.1.1", - "@napi-rs/nice-darwin-x64": "1.1.1", - "@napi-rs/nice-freebsd-x64": "1.1.1", - "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", - "@napi-rs/nice-linux-arm64-gnu": "1.1.1", - "@napi-rs/nice-linux-arm64-musl": "1.1.1", - "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", - "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", - "@napi-rs/nice-linux-s390x-gnu": "1.1.1", - "@napi-rs/nice-linux-x64-gnu": "1.1.1", - "@napi-rs/nice-linux-x64-musl": "1.1.1", - "@napi-rs/nice-openharmony-arm64": "1.1.1", - "@napi-rs/nice-win32-arm64-msvc": "1.1.1", - "@napi-rs/nice-win32-ia32-msvc": "1.1.1", - "@napi-rs/nice-win32-x64-msvc": "1.1.1" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@napi-rs/nice-android-arm-eabi": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", - "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", "cpu": [ - "arm" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "android" + "win32" ], "engines": { - "node": ">= 10" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@napi-rs/nice-android-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", - "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.47.tgz", + "integrity": "sha512-vPP9/MZzESh9QtmvQYojXP/midjgkkc1E4AdnPPAzQXo668ncHJcVLKjJKzoBdsQmaIvNjrMdsCwES8vTQHRQw==", "cpu": [ "arm64" ], @@ -4255,13 +3996,13 @@ "android" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-darwin-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", - "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.47.tgz", + "integrity": "sha512-Lc3nrkxeaDVCVl8qR3qoxh6ltDZfkQ98j5vwIr5ALPkgjZtDK4BGCrrBoLpGVMg+csWcaqUbwbKwH5yvVa0oOw==", "cpu": [ "arm64" ], @@ -4272,13 +4013,13 @@ "darwin" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-darwin-x64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", - "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.47.tgz", + "integrity": "sha512-eBYxQDwP0O33plqNVqOtUHqRiSYVneAknviM5XMawke3mwMuVlAsohtOqEjbCEl/Loi/FWdVeks5WkqAkzkYWQ==", "cpu": [ "x64" ], @@ -4289,13 +4030,13 @@ "darwin" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-freebsd-x64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", - "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.47.tgz", + "integrity": "sha512-Ns+kgp2+1Iq/44bY/Z30DETUSiHY7ZuqaOgD5bHVW++8vme9rdiWsN4yG4rRPXkdgzjvQ9TDHmZZKfY4/G11AA==", "cpu": [ "x64" ], @@ -4306,13 +4047,13 @@ "freebsd" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", - "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.47.tgz", + "integrity": "sha512-4PecgWCJhTA2EFOlptYJiNyVP2MrVP4cWdndpOu3WmXqWqZUmSubhb4YUAIxAxnXATlGjC1WjxNPhV7ZllNgdA==", "cpu": [ "arm" ], @@ -4323,13 +4064,13 @@ "linux" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-linux-arm64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", - "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.47.tgz", + "integrity": "sha512-CyIunZ6D9U9Xg94roQI1INt/bLkOpPsZjZZkiaAZ0r6uccQdICmC99M9RUPlMLw/qg4yEWLlQhG73W/mG437NA==", "cpu": [ "arm64" ], @@ -4340,13 +4081,13 @@ "linux" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-linux-arm64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", - "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.47.tgz", + "integrity": "sha512-doozc/Goe7qRCSnzfJbFINTHsMktqmZQmweull6hsZZ9sjNWQ6BWQnbvOlfZJe4xE5NxM1NhPnY5Giqnl3ZrYQ==", "cpu": [ "arm64" ], @@ -4357,15 +4098,15 @@ "linux" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-linux-ppc64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", - "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.47.tgz", + "integrity": "sha512-fodvSMf6Aqwa0wEUSTPewmmZOD44rc5Tpr5p9NkwQ6W1SSpUKzD3SwpJIgANDOhwiYhDuiIaYPGB7Ujkx1q0UQ==", "cpu": [ - "ppc64" + "x64" ], "dev": true, "license": "MIT", @@ -4374,15 +4115,15 @@ "linux" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-linux-riscv64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", - "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.47.tgz", + "integrity": "sha512-Rxm5hYc0mGjwLh5sjlGmMygxAaV2gnsx7CNm2lsb47oyt5UQyPDZf3GP/ct8BEcwuikdqzsrrlIp8+kCSvMFNQ==", "cpu": [ - "riscv64" + "x64" ], "dev": true, "license": "MIT", @@ -4391,83 +4132,83 @@ "linux" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-linux-s390x-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", - "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.47.tgz", + "integrity": "sha512-YakuVe+Gc87jjxazBL34hbr8RJpRuFBhun7NEqoChVDlH5FLhLXjAPHqZd990TVGVNkemourf817Z8u2fONS8w==", "cpu": [ - "s390x" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "openharmony" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-linux-x64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", - "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.47.tgz", + "integrity": "sha512-ak2GvTFQz3UAOw8cuQq8pWE+TNygQB6O47rMhvevvTzETh7VkHRFtRUwJynX5hwzFvQMP6G0az5JrBGuwaMwYQ==", "cpu": [ - "x64" + "wasm32" ], "dev": true, "license": "MIT", "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.7" + }, "engines": { - "node": ">= 10" + "node": ">=14.0.0" } }, - "node_modules/@napi-rs/nice-linux-x64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", - "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.47.tgz", + "integrity": "sha512-o5BpmBnXU+Cj+9+ndMcdKjhZlPb79dVPBZnWwMnI4RlNSSq5yOvFZqvfPYbyacvnW03Na4n5XXQAPhu3RydZ0w==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-openharmony-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", - "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", + "node_modules/@rolldown/binding-win32-ia32-msvc": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.47.tgz", + "integrity": "sha512-FVOmfyYehNE92IfC9Kgs913UerDog2M1m+FADJypKz0gmRg3UyTt4o1cZMCAl7MiR89JpM9jegNO1nXuP1w1vw==", "cpu": [ - "arm64" + "ia32" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "openharmony" + "win32" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-win32-arm64-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", - "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.47.tgz", + "integrity": "sha512-by/70F13IUE101Bat0oeH8miwWX5mhMFPk1yjCdxoTNHTyTdLgb0THNaebRM6AP7Kz+O3O2qx87sruYuF5UxHg==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", @@ -4476,286 +4217,470 @@ "win32" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/nice-win32-ia32-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", - "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz", + "integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", + "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", "cpu": [ - "ia32" + "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } + "android" + ] }, - "node_modules/@napi-rs/nice-win32-x64-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", - "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", + "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } + "android" + ] }, - "node_modules/@ngtools/webpack": { - "version": "20.3.4", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-20.3.4.tgz", - "integrity": "sha512-5G2Q9VguR73RaSbqVpsW1LumITsPxceLL0+L94IOHoV4eYlFciJTXLWgcRUoChh73bt0wLMgdwUVWKjaVtjOLQ==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", + "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "@angular/compiler-cli": "^20.0.0", - "typescript": ">=5.8 <6.0", - "webpack": "^5.54.0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", + "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", + "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "engines": { - "node": ">= 8" - } + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", + "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@npmcli/agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", - "integrity": "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", + "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@npmcli/fs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", - "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", + "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@npmcli/git": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-6.0.3.tgz", - "integrity": "sha512-GUYESQlxZRAdhs3UhbB6pVRNUELQOHXwK9ruDkwmCv2aZ5y0SApQzUJCg02p3A7Ue2J5hxvlk1YI53c00NmRyQ==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", + "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/promise-spawn": "^8.0.0", - "ini": "^5.0.0", - "lru-cache": "^10.0.1", - "npm-pick-manifest": "^10.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@npmcli/git/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", + "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "engines": { - "node": ">=16" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", + "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", + "cpu": [ + "loong64" + ], "dev": true, - "license": "ISC" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", + "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", + "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", + "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", + "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", + "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", + "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", + "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", + "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", + "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", + "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", + "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@schematics/angular": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.0.0.tgz", + "integrity": "sha512-50eEsBaT++Gwr+5FAhaKIzTUjpE1DJAwmE5QwtogbTnr2viZc8CsbFOfuMrokQbgdcXRvbkBDPXgO15STMcDRQ==", + "dev": true, + "license": "MIT", "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "@angular-devkit/core": "21.0.0", + "@angular-devkit/schematics": "21.0.0", + "jsonc-parser": "3.3.1" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, - "node_modules/@npmcli/installed-package-contents": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-3.0.0.tgz", - "integrity": "sha512-fkxoPuFGvxyrH+OQzyTkX2LUEamrF4jZSmxjAtPPHHGO0dqsQ8tTKjnIS8SAnPHdk2I03BDtSMR5K/4loKg79Q==", + "node_modules/@sigstore/bundle": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz", + "integrity": "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "npm-bundled": "^4.0.0", - "npm-normalize-package-bin": "^4.0.0" - }, - "bin": { - "installed-package-contents": "bin/index.js" + "@sigstore/protobuf-specs": "^0.5.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@npmcli/node-gyp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-4.0.0.tgz", - "integrity": "sha512-+t5DZ6mO/QFh78PByMq1fGSAub/agLJZDRfJRMeOSNCt8s9YVlTjmGpIPwPhvXTGUIJk+WszlT0rQa1W33yzNA==", + "node_modules/@sigstore/core": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.0.0.tgz", + "integrity": "sha512-NgbJ+aW9gQl/25+GIEGYcCyi8M+ng2/5X04BMuIgoDfgvp18vDcoNHOQjQsG9418HGNYRxG3vfEXaR1ayD37gg==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.0.tgz", + "integrity": "sha512-MM8XIwUjN2bwvCg1QvrMtbBmpcSHrkhFSCu1D11NyPvDQ25HEc4oG5/OcQfd/Tlf/OxmKWERDj0zGE23jQaMwA==", + "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/@npmcli/package-json": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-6.2.0.tgz", - "integrity": "sha512-rCNLSB/JzNvot0SEyXqWZ7tX2B5dD2a1br2Dp0vSYVo5jh8Z0EZ7lS9TsZ1UtziddB1UfNUaMCc538/HztnJGA==", + "node_modules/@sigstore/sign": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-4.0.1.tgz", + "integrity": "sha512-KFNGy01gx9Y3IBPG/CergxR9RZpN43N+lt3EozEfeoyqm8vEiLxwRl3ZO5sPx3Obv1ix/p7FWOlPc2Jgwfp9PA==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "@npmcli/git": "^6.0.0", - "glob": "^10.2.2", - "hosted-git-info": "^8.0.0", - "json-parse-even-better-errors": "^4.0.0", + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.0.0", + "@sigstore/protobuf-specs": "^0.5.0", + "make-fetch-happen": "^15.0.2", "proc-log": "^5.0.0", - "semver": "^7.5.3", - "validate-npm-package-license": "^3.0.4" + "promise-retry": "^2.0.1" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@npmcli/package-json/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/@sigstore/tuf": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.0.tgz", + "integrity": "sha512-0QFuWDHOQmz7t66gfpfNO6aEjoFrdhkJaej/AOqb4kqWZVbPWFZifXZzkxyQBB1OwTbkhdT3LNpMFxwkTvf+2w==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "balanced-match": "^1.0.0" + "@sigstore/protobuf-specs": "^0.5.0", + "tuf-js": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@npmcli/package-json/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "node_modules/@sigstore/verify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.0.0.tgz", + "integrity": "sha512-moXtHH33AobOhTZF8xcX1MpOFqdvfCk7v6+teJL8zymBiDXwEsQH6XG9HGx2VIxnJZNm4cNSzflTLDnQLmIdmw==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.0.0", + "@sigstore/protobuf-specs": "^0.5.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@npmcli/package-json/node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT", + "peer": true + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-4.0.0.tgz", + "integrity": "sha512-h5x5ga/hh82COe+GoD4+gKUeV4T3iaYOxqLt41GRKApinPI7DMidhCmNVTjKfhCWFJIGXaFJee07XczdT4jdZQ==", + "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^10.0.1" + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.5" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@npmcli/package-json/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } }, - "node_modules/@npmcli/package-json/node_modules/minimatch": { + "node_modules/@tufjs/models/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", @@ -4771,5916 +4696,1317 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@npmcli/promise-spawn": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-8.0.3.tgz", - "integrity": "sha512-Yb00SWaL4F8w+K8YGhQ55+xE4RUNdMHV43WZGsiTM92gS+lC0mGsn7I4hLug7pbao035S6bj3Y3w0cUNGLfmkg==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, "dependencies": { - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" + "tslib": "^2.4.0" } }, - "node_modules/@npmcli/promise-spawn/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jasmine": { + "version": "5.1.13", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.13.tgz", + "integrity": "sha512-MYCcDkruFc92LeYZux5BC0dmqo2jk+M5UIZ4/oFnAPCXN9mCcQhLyj7F3/Za7rocVyt5YRr1MmqJqFlvQ9LVcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/luxon": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.1.tgz", + "integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/abbrev": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", + "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", "dev": true, "license": "ISC", "engines": { - "node": ">=16" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "isexe": "^3.1.1" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "bin": { - "node-which": "bin/which.js" + "acorn": "bin/acorn" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=0.4.0" } }, - "node_modules/@npmcli/redact": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-3.2.2.tgz", - "integrity": "sha512-7VmYAmk4csGv08QzrDKScdzn11jHPFGyqJW39FyPgPuAp3zIaUmuCo1yxw9aGs+NEJuTGQ9Gwqpt93vtJubucg==", + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">= 14" } }, - "node_modules/@npmcli/run-script": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-9.1.0.tgz", - "integrity": "sha512-aoNSbxtkePXUlbZB+anS1LqsJdctG5n3UVhfU47+CDdwMi6uNTBMF9gPcQRnqghQd2FGzcwwIFBruFMxjhBewg==", + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/node-gyp": "^4.0.0", - "@npmcli/package-json": "^6.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "node-gyp": "^11.0.0", - "proc-log": "^5.0.0", - "which": "^5.0.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, - "engines": { - "node": "^18.17.0 || >=20.5.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@npmcli/run-script/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=16" + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "node_modules/algoliasearch": { + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.40.1.tgz", + "integrity": "sha512-iUNxcXUNg9085TJx0HJLjqtDE0r1RZ0GOGrt8KNQqQT5ugu8lZsHuMUYW/e0lHhq6xBvmktU9Bw4CXP9VQeKrg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "@algolia/abtesting": "1.6.1", + "@algolia/client-abtesting": "5.40.1", + "@algolia/client-analytics": "5.40.1", + "@algolia/client-common": "5.40.1", + "@algolia/client-insights": "5.40.1", + "@algolia/client-personalization": "5.40.1", + "@algolia/client-query-suggestions": "5.40.1", + "@algolia/client-search": "5.40.1", + "@algolia/ingestion": "1.40.1", + "@algolia/monitoring": "1.40.1", + "@algolia/recommend": "5.40.1", + "@algolia/requester-browser-xhr": "5.40.1", + "@algolia/requester-fetch": "5.40.1", + "@algolia/requester-node-http": "5.40.1" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">= 14.0.0" } }, - "node_modules/@parcel/watcher": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "node_modules/ansi-escapes": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, "dependencies": { - "detect-libc": "^1.0.3", - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" + "environment": "^1.0.0" }, "engines": { - "node": ">= 10.0.0" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">= 10.0.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">= 10.0.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.3.tgz", - "integrity": "sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.3.tgz", - "integrity": "sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.3.tgz", - "integrity": "sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.3.tgz", - "integrity": "sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.3.tgz", - "integrity": "sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.3.tgz", - "integrity": "sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.3.tgz", - "integrity": "sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.3.tgz", - "integrity": "sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.3.tgz", - "integrity": "sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.3.tgz", - "integrity": "sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.3.tgz", - "integrity": "sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.3.tgz", - "integrity": "sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.3.tgz", - "integrity": "sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.3.tgz", - "integrity": "sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.3.tgz", - "integrity": "sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.3.tgz", - "integrity": "sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.3.tgz", - "integrity": "sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.3.tgz", - "integrity": "sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.3.tgz", - "integrity": "sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.3.tgz", - "integrity": "sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.3.tgz", - "integrity": "sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.3.tgz", - "integrity": "sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@schematics/angular": { - "version": "20.3.4", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.4.tgz", - "integrity": "sha512-aIgeRAfSJdxVfsES521vNb6Nuy+Uei7xE85hD+mQHX+62bN7vJhM/tmMFIYS7UF8d0rRnMPiGEr2Rfx6Om5iPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "20.3.4", - "@angular-devkit/schematics": "20.3.4", - "jsonc-parser": "3.3.1" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@sigstore/bundle": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-3.1.0.tgz", - "integrity": "sha512-Mm1E3/CmDDCz3nDhFKTuYdB47EdRFRQMOE/EAbiG1MJW77/w1b3P7Qx7JSrVJs8PfwOLOVcKQCHErIwCTyPbag==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.4.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@sigstore/core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-2.0.0.tgz", - "integrity": "sha512-nYxaSb/MtlSI+JWcwTHQxyNmWeWrUXJJ/G4liLrGG7+tS4vAz6LF3xRXqLH6wPIVUoZQel2Fs4ddLx4NCpiIYg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.4.3.tgz", - "integrity": "sha512-fk2zjD9117RL9BjqEwF7fwv7Q/P9yGsMV4MUJZ/DocaQJ6+3pKr+syBq1owU5Q5qGw5CUbXzm+4yJ2JVRDQeSA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@sigstore/sign": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-3.1.0.tgz", - "integrity": "sha512-knzjmaOHOov1Ur7N/z4B1oPqZ0QX5geUfhrVaqVlu+hl0EAoL4o+l0MSULINcD5GCWe3Z0+YJO8ues6vFlW0Yw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.1.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.4.0", - "make-fetch-happen": "^14.0.2", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@sigstore/tuf": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-3.1.1.tgz", - "integrity": "sha512-eFFvlcBIoGwVkkwmTi/vEQFSva3xs5Ot3WmBcjgjVdiaoelBLQaQ/ZBfhlG0MnG0cmTYScPpk7eDdGDWUcFUmg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.4.1", - "tuf-js": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@sigstore/verify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-2.1.1.tgz", - "integrity": "sha512-hVJD77oT67aowHxwT4+M6PGOp+E2LtLdTK3+FC0lBO9T7sYwItDMXZ7Z07IDCvR1M717a4axbIWckrW67KMP/w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.1.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.4.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", - "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@tufjs/models": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-3.0.1.tgz", - "integrity": "sha512-UUYHISyhCU3ZgN8yaear3cGATHb3SMuKHsQ/nVbHXcmnBf+LzQ/cQfhNG+rfaSHgqGKNEm2cOCLVLELStUQ1JA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "node_modules/@types/cors": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", - "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/express": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", - "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", - "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/http-proxy": { - "version": "1.17.16", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", - "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/jasmine": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.9.tgz", - "integrity": "sha512-8t4HtkW4wxiPVedMpeZ63n3vlWxEIquo/zc1Tm8ElU+SqVV7+D3Na2PWaJUp179AzTragMWVwkMv7mvty0NfyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/luxon": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.1.tgz", - "integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node-forge": { - "version": "1.3.14", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", - "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/retry": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", - "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.0.tgz", - "integrity": "sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.9.tgz", - "integrity": "sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" - } - }, - "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", - "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/abbrev": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", - "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "acorn": "^8.14.0" - } - }, - "node_modules/adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/algoliasearch": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.35.0.tgz", - "integrity": "sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@algolia/abtesting": "1.1.0", - "@algolia/client-abtesting": "5.35.0", - "@algolia/client-analytics": "5.35.0", - "@algolia/client-common": "5.35.0", - "@algolia/client-insights": "5.35.0", - "@algolia/client-personalization": "5.35.0", - "@algolia/client-query-suggestions": "5.35.0", - "@algolia/client-search": "5.35.0", - "@algolia/ingestion": "1.35.0", - "@algolia/monitoring": "1.35.0", - "@algolia/recommend": "5.35.0", - "@algolia/requester-browser-xhr": "5.35.0", - "@algolia/requester-fetch": "5.35.0", - "@algolia/requester-node-http": "5.35.0" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.1.1.tgz", - "integrity": "sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "license": "Apache-2.0", - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/autoprefixer": { - "version": "10.4.21", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", - "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.4", - "caniuse-lite": "^1.0.30001702", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/babel-loader": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", - "integrity": "sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": "^18.20.0 || ^20.10.0 || >=22.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0", - "webpack": ">=5.61.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.12.tgz", - "integrity": "sha512-vAPMQdnyKCBtkmQA6FMCBvU9qFIppS3nzyXnEM+Lo2IAhG4Mpjv9cCxMudhgV3YdNNJv6TNqXy97dfRVL2LmaQ==", - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true, - "license": "MIT" - }, - "node_modules/beasties": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.3.5.tgz", - "integrity": "sha512-NaWu+f4YrJxEttJSm16AzMIFtVldCvaJ68b1L098KpqXmxt9xOLtKoLkKxb8ekhOrLqEJAbvT6n6SEvB/sac7A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "css-select": "^6.0.0", - "css-what": "^7.0.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "htmlparser2": "^10.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.49", - "postcss-media-query-parser": "^0.2.3" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/bonjour-service": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", - "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, - "license": "ISC" - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.26.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", - "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.8.9", - "caniuse-lite": "^1.0.30001746", - "electron-to-chromium": "^1.5.227", - "node-releases": "^2.0.21", - "update-browserslist-db": "^1.1.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "run-applescript": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "19.0.1", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", - "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^4.0.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^12.0.0", - "tar": "^7.4.3", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/tar": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", - "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", - "dev": true, - "license": "ISC", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cacache/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001748", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001748.tgz", - "integrity": "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chardet": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", - "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", - "dev": true, - "license": "MIT" - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", - "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 12" - } - }, - "node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/clone-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/compression/node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/connect/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/connect/node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/connect/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/connect/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-what": "^3.14.1" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/copy-webpack-plugin": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-13.0.1.tgz", - "integrity": "sha512-J+YV3WfhY6W/Xf9h+J1znYuqTye2xkBUIGyTPWuBAT27qajBa5mR4f8WBmfDY3YjRftT2kqZZiLi1qf0H+UOFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "glob-parent": "^6.0.1", - "normalize-path": "^3.0.0", - "schema-utils": "^4.2.0", - "serialize-javascript": "^6.0.2", - "tinyglobby": "^0.2.12" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - } - }, - "node_modules/core-js-compat": { - "version": "3.45.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz", - "integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.25.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-loader": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", - "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", - "dev": true, - "license": "MIT", - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.1.0", - "postcss-modules-local-by-default": "^4.0.5", - "postcss-modules-scope": "^3.2.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.27.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/css-select": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", - "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^7.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.2.2", - "nth-check": "^2.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", - "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", - "dev": true, - "license": "MIT" - }, - "node_modules/date-format": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/default-browser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", - "dev": true, - "license": "MIT", - "dependencies": { - "bundle-name": "^4.1.0", - "default-browser-id": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "license": "MIT" - }, - "node_modules/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", - "dev": true, - "license": "MIT" - }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/dom-serializer/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.230", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.230.tgz", - "integrity": "sha512-A6A6Fd3+gMdaed9wX83CvHYJb4UuapPD5X5SLq72VZJzxHSY0/LUweGXRWmQlh2ln7KV7iw7jnwXK7dlPoOnHQ==", - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", - "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", - "license": "MIT" - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/engine.io": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", - "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.7.2", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/engine.io-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", - "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/engine.io/node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/engine.io/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/engine.io/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/engine.io/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/ent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz", - "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "punycode": "^1.4.1", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true, - "license": "MIT" - }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", - "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.9", - "@esbuild/android-arm": "0.25.9", - "@esbuild/android-arm64": "0.25.9", - "@esbuild/android-x64": "0.25.9", - "@esbuild/darwin-arm64": "0.25.9", - "@esbuild/darwin-x64": "0.25.9", - "@esbuild/freebsd-arm64": "0.25.9", - "@esbuild/freebsd-x64": "0.25.9", - "@esbuild/linux-arm": "0.25.9", - "@esbuild/linux-arm64": "0.25.9", - "@esbuild/linux-ia32": "0.25.9", - "@esbuild/linux-loong64": "0.25.9", - "@esbuild/linux-mips64el": "0.25.9", - "@esbuild/linux-ppc64": "0.25.9", - "@esbuild/linux-riscv64": "0.25.9", - "@esbuild/linux-s390x": "0.25.9", - "@esbuild/linux-x64": "0.25.9", - "@esbuild/netbsd-arm64": "0.25.9", - "@esbuild/netbsd-x64": "0.25.9", - "@esbuild/openbsd-arm64": "0.25.9", - "@esbuild/openbsd-x64": "0.25.9", - "@esbuild/openharmony-arm64": "0.25.9", - "@esbuild/sunos-x64": "0.25.9", - "@esbuild/win32-arm64": "0.25.9", - "@esbuild/win32-ia32": "0.25.9", - "@esbuild/win32-x64": "0.25.9" - } - }, - "node_modules/esbuild-wasm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.25.9.tgz", - "integrity": "sha512-Jpv5tCSwQg18aCqCRD3oHIX/prBhXMDapIoG//A+6+dV0e7KQMGFg85ihJ5T1EeMjbZjON3TqFy0VrGAnIHLDA==", - "dev": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true, - "license": "MIT" - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", - "integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", - "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob-to-regex.js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", - "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hosted-git-info": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.0.tgz", - "integrity": "sha512-gEf705MZLrDPkbbhi8PnoO4ZwYgKoNL+ISZ3AjZMht2r3N5tuTwncyDi6Fv2/qDnMmZxgs0yI8WDOyR8q3G+SQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^11.1.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/htmlparser2": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", - "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.2.1", - "entities": "^6.0.0" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http-proxy-middleware": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.5.tgz", - "integrity": "sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-proxy": "^1.17.15", - "debug": "^4.3.6", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.3", - "is-plain-object": "^5.0.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/hyperdyperid": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", - "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.18" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/ignore-walk": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz", - "integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==", - "dev": true, - "license": "ISC", - "dependencies": { - "minimatch": "^10.0.3" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/ignore-walk/node_modules/minimatch": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", - "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", - "dev": true, - "license": "ISC", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", - "dev": true, - "license": "MIT", - "optional": true, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/immutable": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", - "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", - "dev": true, - "license": "MIT" - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ini": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-5.0.0.tgz", - "integrity": "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-network-error": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.0.tgz", - "integrity": "sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isbinaryfile": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC", "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/jasmine-core": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.8.0.tgz", - "integrity": "sha512-Q9dqmpUAfptwyueW3+HqBOkSuYd9I/clZSSfN97wXE/Nr2ROFNCwIBEC1F6kb3QXS9Fcz0LjFYSDQT+BiwjuhA==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, "license": "MIT" }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": "^4.5.0 || >= 5.9" } }, - "node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "dev": true, - "license": "MIT", + "node_modules/baseline-browser-mapping": { + "version": "2.8.30", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.30.tgz", + "integrity": "sha512-aTUKW4ptQhS64+v2d6IkPzymEzzhw+G0bA1g3uBRV3+ntkH+svttKseW5IOR4Ed6NUVKqnY7qT3dKvzQ7io4AA==", + "license": "Apache-2.0", "bin": { - "jiti": "bin/jiti.js" + "baseline-browser-mapping": "dist/cli.js" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/beasties": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.3.5.tgz", + "integrity": "sha512-NaWu+f4YrJxEttJSm16AzMIFtVldCvaJ68b1L098KpqXmxt9xOLtKoLkKxb8ekhOrLqEJAbvT6n6SEvB/sac7A==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "css-select": "^6.0.0", + "css-what": "^7.0.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "htmlparser2": "^10.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", + "postcss-media-query-parser": "^0.2.3" }, "engines": { - "node": ">=6" + "node": ">=14.0.0" } }, - "node_modules/json-parse-even-better-errors": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", - "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "license": "MIT", - "bin": { - "json5": "lib/cli.js" + "node": ">=8" }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "license": "MIT" - }, - "node_modules/karma": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", - "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", "dev": true, "license": "MIT", "dependencies": { - "@colors/colors": "1.5.0", - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.5.1", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.7", - "graceful-fs": "^4.2.6", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.8", - "lodash": "^4.17.21", - "log4js": "^6.4.1", - "mime": "^2.5.2", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.5", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^4.7.2", - "source-map": "^0.6.1", - "tmp": "^0.2.1", - "ua-parser-js": "^0.7.30", - "yargs": "^16.1.1" - }, - "bin": { - "karma": "bin/karma" + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" }, "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/karma-chrome-launcher": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", - "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { - "which": "^1.2.1" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/karma-chrome-launcher/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" + "fill-range": "^7.1.1" }, - "bin": { - "which": "bin/which" + "engines": { + "node": ">=8" } }, - "node_modules/karma-coverage": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", - "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", - "dev": true, + "node_modules/browserslist": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.1", - "istanbul-reports": "^3.0.5", - "minimatch": "^3.0.4" + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" }, "engines": { - "node": ">=10.0.0" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/karma-coverage/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/karma-coverage/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/cacache": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.3.tgz", + "integrity": "sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==", "dev": true, "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0", + "unique-filename": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/karma-jasmine": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.0.1.tgz", - "integrity": "sha512-FkL1Kk+JAKmim8VWU8RXKZBpl0lLI7J8LijM0/q7oP7emfB6QMZV1Az+JgqGKSLpF0tYaav+KUVFQroZUxQTHA==", + "node_modules/cacache/node_modules/glob": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", + "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "jasmine-core": "^4.1.0" + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.0" }, "engines": { - "node": ">=12" + "node": "20 || >=22" }, - "peerDependencies": { - "karma": "^6.0.0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/karma-jasmine-html-reporter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", - "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", + "node_modules/cacache/node_modules/lru-cache": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", "dev": true, - "license": "MIT", - "peerDependencies": { - "jasmine-core": "^4.0.0 || ^5.0.0", - "karma": "^6.0.0", - "karma-jasmine": "^5.0.0" + "license": "ISC", + "engines": { + "node": "20 || >=22" } }, - "node_modules/karma-jasmine/node_modules/jasmine-core": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.1.tgz", - "integrity": "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/karma-source-map-support": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", - "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "node_modules/cacache/node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "source-map-support": "^0.5.5" - } - }, - "node_modules/karma/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", + "@isaacs/brace-expansion": "^5.0.0" + }, "engines": { - "node": ">=8" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/karma/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/cacache/node_modules/ssri": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.0.tgz", + "integrity": "sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "color-convert": "^2.0.1" + "minipass": "^7.0.3" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/karma/node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">= 0.4" } }, - "node_modules/karma/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 0.4" }, "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/karma/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } + "node_modules/caniuse-lite": { + "version": "1.0.30001756", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001756.tgz", + "integrity": "sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" }, - "node_modules/karma/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/karma/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", "dev": true, "license": "MIT" }, - "node_modules/karma/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 6" + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/karma/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/karma/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/cli-spinners": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.3.0.tgz", + "integrity": "sha512-/+40ljC3ONVnYIttjMWrlL51nItDAbBrq2upN8BPyvGU/2n5Oxw3tbNwORCaNuNqLJnxGqOfjUuhsv7l5Q4IsQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/karma/node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "node_modules/cli-truncate": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", + "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", "dev": true, "license": "MIT", + "dependencies": { + "slice-ansi": "^7.1.0", + "string-width": "^8.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/karma/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">= 0.6" + "node": ">= 12" } }, - "node_modules/karma/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "license": "ISC", "dependencies": { - "mime-db": "1.52.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=20" } }, - "node_modules/karma/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, - "node_modules/karma/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">=8.6" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/karma/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "side-channel": "^1.0.6" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=7.0.0" } }, - "node_modules/karma/node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10.0" } }, - "node_modules/karma/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" + "ms": "2.0.0" } }, - "node_modules/karma/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/connect/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/karma/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/karma/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ee-first": "1.1.1" }, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/karma/node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, "engines": { "node": ">= 0.6" } }, - "node_modules/karma/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/karma/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, "engines": { - "node": ">=10" + "node": ">= 0.6" } }, - "node_modules/karma/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/launch-editor": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz", - "integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==", + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "dev": true, "license": "MIT", - "dependencies": { - "picocolors": "^1.1.1", - "shell-quote": "^1.8.3" - } - }, - "node_modules/less": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/less/-/less-4.4.0.tgz", - "integrity": "sha512-kdTwsyRuncDfjEs0DlRILWNvxhDG/Zij4YLO4TMJgDLW+8OzpfkdPnRgrsRuY1o+oaxJGWsps5f/RVBgGmmN0w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "copy-anything": "^2.0.1", - "parse-node-version": "^1.0.1", - "tslib": "^2.3.0" - }, - "bin": { - "lessc": "bin/lessc" - }, "engines": { - "node": ">=14" - }, - "optionalDependencies": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^3.1.0", - "source-map": "~0.6.0" + "node": ">=6.6.0" } }, - "node_modules/less-loader": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-12.3.0.tgz", - "integrity": "sha512-0M6+uYulvYIWs52y0LqN4+QM9TqWAohYSNTo4htE8Z7Cn3G/qQMEmktfHmyJT23k+20kU9zHH2wrfFXkxNLtVw==", + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 18.12.0" + "optional": true, + "peer": true, + "dependencies": { + "is-what": "^3.14.1" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "less": "^3.5.0 || ^4.0.0", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } + "url": "https://github.com/sponsors/mesqueeb" } }, - "node_modules/less/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "object-assign": "^4", + "vary": "^1" }, "engines": { - "node": ">=6" + "node": ">= 0.10" } }, - "node_modules/less/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", - "optional": true, - "bin": { - "mime": "cli.js" + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">= 8" } }, - "node_modules/less/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/css-select": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", "dev": true, - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver" + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/less/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/css-what": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", "dev": true, - "license": "BSD-3-Clause", - "optional": true, + "license": "BSD-2-Clause", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/license-webpack-plugin": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", - "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", - "dev": true, - "license": "ISC", - "dependencies": { - "webpack-sources": "^3.0.0" + "node": ">= 6" }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-sources": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true, "license": "MIT" }, - "node_modules/listr2": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz", - "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, "license": "MIT", - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, "engines": { - "node": ">=20.0.0" + "node": ">=4.0" } }, - "node_modules/listr2/node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true, - "license": "MIT" - }, - "node_modules/lmdb": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.4.2.tgz", - "integrity": "sha512-nwVGUfTBUwJKXd6lRV8pFNfnrCC1+l49ESJRM19t/tFb/97QfJEixe5DYRvug5JO7DSFKoKaVy7oGMt5rVqZvg==", - "dev": true, - "hasInstallScript": true, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", - "optional": true, "dependencies": { - "msgpackr": "^1.11.2", - "node-addon-api": "^6.1.0", - "node-gyp-build-optional-packages": "5.2.2", - "ordered-binary": "^1.5.3", - "weak-lru-cache": "^1.2.2" + "ms": "^2.1.3" }, - "bin": { - "download-lmdb-prebuilds": "bin/download-prebuilds.js" + "engines": { + "node": ">=6.0" }, - "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "3.4.2", - "@lmdb/lmdb-darwin-x64": "3.4.2", - "@lmdb/lmdb-linux-arm": "3.4.2", - "@lmdb/lmdb-linux-arm64": "3.4.2", - "@lmdb/lmdb-linux-x64": "3.4.2", - "@lmdb/lmdb-win32-arm64": "3.4.2", - "@lmdb/lmdb-win32-x64": "3.4.2" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/lmdb/node_modules/node-addon-api": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", - "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "license": "MIT", "engines": { - "node": ">=6.11.5" + "node": ">= 0.8" } }, - "node_modules/loader-utils": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", - "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 12.13.0" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true, "license": "MIT" }, - "node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" } }, - "node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=18" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, - "license": "MIT", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "get-east-asian-width": "^1.3.1" + "domelementtype": "^2.3.0" }, "engines": { - "node": ">=18" + "node": ">= 4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" }, "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/log4js": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, "engines": { - "node": ">=8.0" + "node": ">= 0.4" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" }, - "node_modules/luxon": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", - "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", - "license": "MIT", - "engines": { - "node": ">=12" - } + "node_modules/electron-to-chromium": { + "version": "1.5.259", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.259.tgz", + "integrity": "sha512-I+oLXgpEJzD6Cwuwt1gYjxsDmu/S/Kd41mmLA3O+/uH2pFRO/DvOjUyGozL8j3KeLV6WyZ7ssPwELMsXCcsJAQ==", + "license": "ISC" }, - "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" - } + "license": "MIT" }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.8" } }, - "node_modules/make-fetch-happen": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", - "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, "dependencies": { - "@npmcli/agent": "^3.0.0", - "cacache": "^19.0.1", - "http-cache-semantics": "^4.1.1", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^1.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" + "iconv-lite": "^0.6.2" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", "dev": true, "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, "engines": { - "node": ">= 0.4" + "node": ">=10.2.0" } }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=10.0.0" } }, - "node_modules/memfs": { - "version": "4.48.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.48.1.tgz", - "integrity": "sha512-vWO+1ROkhOALF1UnT9aNOOflq5oFDlqwTXaPg6duo07fBLxSH0+bcF0TY1lbA1zTNKyGgDxgaDdKx5MaewLX5A==", + "node_modules/engine.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@jsonjoy.com/json-pack": "^1.11.0", - "@jsonjoy.com/util": "^1.9.0", - "glob-to-regex.js": "^1.0.1", - "thingies": "^2.5.0", - "tree-dump": "^1.0.3", - "tslib": "^2.0.0" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.6" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, "engines": { - "node": ">= 8" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "node_modules/engine.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "node_modules/engine.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" + "mime-db": "1.52.0" }, "engines": { - "node": ">=8.6" + "node": ">= 0.6" } }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/engine.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": ">= 0.6" } }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "node_modules/ent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz", + "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==", "dev": true, "license": "MIT", - "bin": { - "mime": "cli.js" + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "punycode": "^1.4.1", + "safe-regex-test": "^1.1.0" }, "engines": { - "node": ">=4.0.0" + "node": ">= 0.4" } }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.6" + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, "engines": { - "node": ">= 0.6" + "node": ">=6" } }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "dev": true, "license": "MIT", "engines": { @@ -10690,784 +6016,880 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mini-css-extract-plugin": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.4.tgz", - "integrity": "sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ==", + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "schema-utils": "^4.0.0", - "tapable": "^2.2.1" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "prr": "~1.0.1" }, - "peerDependencies": { - "webpack": "^5.0.0" + "bin": { + "errno": "cli.js" } }, - "node_modules/minimalistic-assert": { + "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", "engines": { - "node": "*" + "node": ">= 0.4" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 0.4" } }, - "node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^7.0.3" + "es-errors": "^1.3.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 0.4" } }, - "node_modules/minipass-fetch": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", - "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", + "node_modules/esbuild": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.26.0.tgz", + "integrity": "sha512-3Hq7jri+tRrVWha+ZeIVhl4qJRha/XjRNSopvTsOaCvfPHrflTYTcUFcEjMKdxofsXXsdc4zjg5NOTnL4Gl57Q==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^3.0.1" + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=18" }, "optionalDependencies": { - "encoding": "^0.1.13" + "@esbuild/aix-ppc64": "0.26.0", + "@esbuild/android-arm": "0.26.0", + "@esbuild/android-arm64": "0.26.0", + "@esbuild/android-x64": "0.26.0", + "@esbuild/darwin-arm64": "0.26.0", + "@esbuild/darwin-x64": "0.26.0", + "@esbuild/freebsd-arm64": "0.26.0", + "@esbuild/freebsd-x64": "0.26.0", + "@esbuild/linux-arm": "0.26.0", + "@esbuild/linux-arm64": "0.26.0", + "@esbuild/linux-ia32": "0.26.0", + "@esbuild/linux-loong64": "0.26.0", + "@esbuild/linux-mips64el": "0.26.0", + "@esbuild/linux-ppc64": "0.26.0", + "@esbuild/linux-riscv64": "0.26.0", + "@esbuild/linux-s390x": "0.26.0", + "@esbuild/linux-x64": "0.26.0", + "@esbuild/netbsd-arm64": "0.26.0", + "@esbuild/netbsd-x64": "0.26.0", + "@esbuild/openbsd-arm64": "0.26.0", + "@esbuild/openbsd-x64": "0.26.0", + "@esbuild/openharmony-arm64": "0.26.0", + "@esbuild/sunos-x64": "0.26.0", + "@esbuild/win32-arm64": "0.26.0", + "@esbuild/win32-ia32": "0.26.0", + "@esbuild/win32-x64": "0.26.0" } }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=6" } }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "eventsource-parser": "^3.0.1" }, "engines": { - "node": ">=8" + "node": ">=18.0.0" } }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18.0.0" } }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", "dev": true, - "license": "ISC" + "license": "Apache-2.0" }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" }, "engines": { - "node": ">=8" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" } }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/minizlib": { + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, "engines": { - "node": ">= 18" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.6" + "to-regex-range": "^5.0.1" }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": ">=8" } }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", "dev": true, "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">= 0.8" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/msgpackr": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.5.tgz", - "integrity": "sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==", + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, - "license": "MIT", - "optional": true, - "optionalDependencies": { - "msgpackr-extract": "^3.0.2" - } + "license": "ISC" }, - "node_modules/msgpackr-extract": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", - "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "dev": true, - "hasInstallScript": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], "license": "MIT", - "optional": true, - "dependencies": { - "node-gyp-build-optional-packages": "5.2.2" - }, - "bin": { - "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + "engines": { + "node": ">=4.0" }, - "optionalDependencies": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, "license": "MIT", - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" + "engines": { + "node": ">= 0.6" } }, - "node_modules/mute-stream": { + "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", - "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">= 0.8" } }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=6 <7 || >=8" } }, - "node_modules/needle": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", - "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, - "license": "MIT", - "optional": true, + "license": "ISC", "dependencies": { - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 4.4.x" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/negotiator": { + "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.6" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "license": "MIT", - "optional": true + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, "engines": { - "node": ">= 6.13.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/node-gyp": { - "version": "11.4.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.4.2.tgz", - "integrity": "sha512-3gD+6zsrLQH7DyYOUIutaauuXrcyxeTPyQuZQCQoNPZMHMMS5m4y0xclNpvYzoK3VNzuyxT6eF4mkIL4WSZ1eQ==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^14.0.3", - "nopt": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "tar": "^7.4.3", - "tinyglobby": "^0.2.12", - "which": "^5.0.0" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, - "bin": { - "node-gyp": "bin/node-gyp.js" + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/node-gyp-build-optional-packages": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", - "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.1" + "engines": { + "node": ">= 0.4" }, - "bin": { - "node-gyp-build-optional-packages": "bin.js", - "node-gyp-build-optional-packages-optional": "optional.js", - "node-gyp-build-optional-packages-test": "build-test.js" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/node-gyp-build-optional-packages/node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, - "license": "Apache-2.0", - "optional": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/node-gyp/node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "engines": { - "node": ">=18" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { - "node": ">=16" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/node-gyp/node_modules/tar": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", - "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=18" + "node": ">= 0.4" } }, - "node_modules/node-gyp/node_modules/which": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "node_modules/hosted-git-info": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", + "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", "dev": true, "license": "ISC", "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "lru-cache": "^11.1.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/node-gyp/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "ISC", "engines": { - "node": ">=18" + "node": "20 || >=22" } }, - "node_modules/node-releases": { - "version": "2.0.23", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", - "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, "license": "MIT" }, - "node_modules/nopt": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", - "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "node_modules/htmlparser2": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", + "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", "dev": true, - "license": "ISC", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", "dependencies": { - "abbrev": "^3.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.1", + "entities": "^6.0.0" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "license": "BSD-2-Clause" }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/npm-bundled": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-4.0.0.tgz", - "integrity": "sha512-IxaQZDMsqfQ2Lz37VvyyEtKLe8FsRZuysmedy/N06TU1RyVppYKXrO4xIhR0F+7ubIBox6Q7nir6fQI3ej39iA==", + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "npm-normalize-package-bin": "^4.0.0" + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=8.0.0" } }, - "node_modules/npm-install-checks": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-7.1.2.tgz", - "integrity": "sha512-z9HJBCYw9Zr8BqXcllKIs5nI+QggAImbBdHphOzVYrz2CB4iQ6FzWyKmlqDZua+51nAu7FcemlbTc9VgQN5XDQ==", + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "semver": "^7.1.1" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">= 14" } }, - "node_modules/npm-normalize-package-bin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", - "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">= 14" } }, - "node_modules/npm-package-arg": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.0.tgz", - "integrity": "sha512-+t2etZAGcB7TbbLHfDwooV9ppB2LhhcT6A+L9cahsf9mEUAoQ6CktLEVvEnpD0N5CkX7zJqnPGaFtoQDy9EkHQ==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "hosted-git-info": "^9.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">=0.10.0" } }, - "node_modules/npm-packlist": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.2.tgz", - "integrity": "sha512-DrIWNiWT0FTdDRjGOYfEEZUNe1IzaSZ+up7qBTKnrQDySpdmuOQvytrqQlpK5QrCA4IThMvL4wTumqaa1ZvVIQ==", + "node_modules/ignore-walk": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz", + "integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==", "dev": true, "license": "ISC", "dependencies": { - "ignore-walk": "^8.0.0", - "proc-log": "^5.0.0" + "minimatch": "^10.0.3" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm-pick-manifest": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-10.0.0.tgz", - "integrity": "sha512-r4fFa4FqYY8xaM7fHecQ9Z2nE9hgNfJR+EmoKv0+chvzWkBcORX3r0FpTByP+CbOVJDladMXnPQGVN8PBLGuTQ==", + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "npm-install-checks": "^7.1.0", - "npm-normalize-package-bin": "^4.0.0", - "npm-package-arg": "^12.0.0", - "semver": "^7.3.5" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm-pick-manifest/node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^10.0.1" + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "image-size": "bin/image-size.js" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=0.10.0" } }, - "node_modules/npm-pick-manifest/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/npm-pick-manifest/node_modules/npm-package-arg": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", - "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", + "node_modules/immutable": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", + "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", "dev": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } + "license": "MIT" }, - "node_modules/npm-registry-fetch": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-18.0.2.tgz", - "integrity": "sha512-LeVMZBBVy+oQb5R6FDV9OlJCcWDU+al10oKpe+nsvcHnG24Z3uM3SvJYKfGJlfGjVU8v9liejCrUR/M5HO5NEQ==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/redact": "^3.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^14.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minizlib": "^3.0.1", - "npm-package-arg": "^12.0.0", - "proc-log": "^5.0.0" - }, + "license": "MIT", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=0.8.19" } }, - "node_modules/npm-registry-fetch/node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "license": "ISC", "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/npm-registry-fetch/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, "license": "ISC" }, - "node_modules/npm-registry-fetch/node_modules/npm-package-arg": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", - "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", - "dev": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "node_modules/ini": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-5.0.0.tgz", + "integrity": "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 12" } }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.10" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "license": "MIT", "dependencies": { - "ee-first": "1.1.1" + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, "engines": { - "node": ">= 0.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", "dev": true, "license": "MIT", "dependencies": { - "mimic-function": "^5.0.0" + "get-east-asian-width": "^1.3.1" }, "engines": { "node": ">=18" @@ -11476,93 +6898,72 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/open": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", - "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", "dependencies": { - "default-browser": "^5.2.1", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "wsl-utils": "^0.1.0" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/ora": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", - "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", "dev": true, "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^5.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.2", - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0" - }, "engines": { - "node": ">=18" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ordered-binary": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.0.tgz", - "integrity": "sha512-IQh2aMfMIDbPjI/8a3Edr+PiOpcsB7yo8NdW7aHWVaoR/pcDldunMvnnwbk/auPGqmKeAdxtZl7MHX/QmPwhvQ==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.12.0" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/p-map": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", - "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, "license": "MIT", "engines": { @@ -11572,562 +6973,563 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-retry": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", - "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, "license": "MIT", - "dependencies": { - "@types/retry": "0.12.2", - "is-network-error": "^1.0.0", - "retry": "^0.13.1" - }, "engines": { - "node": ">=16.17" + "node": ">= 8.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/gjtorikian/" } }, - "node_modules/p-retry/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } + "license": "ISC" }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "license": "BlueOak-1.0.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } }, - "node_modules/pacote": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.0.0.tgz", - "integrity": "sha512-lcqexq73AMv6QNLo7SOpz0JJoaGdS3rBFgF122NZVl1bApo2mfu+XzUBU/X/XsiJu+iUmKpekRayqQYAs+PhkA==", + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, - "license": "ISC", + "license": "BSD-3-Clause", "dependencies": { - "@npmcli/git": "^6.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/package-json": "^6.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "@npmcli/run-script": "^9.0.0", - "cacache": "^19.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^12.0.0", - "npm-packlist": "^10.0.0", - "npm-pick-manifest": "^10.0.0", - "npm-registry-fetch": "^18.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^3.0.0", - "ssri": "^12.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "bin/index.js" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">=10" } }, - "node_modules/pacote/node_modules/hosted-git-info": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", - "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, - "license": "ISC", + "license": "BSD-3-Clause", "dependencies": { - "lru-cache": "^10.0.1" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=10" } }, - "node_modules/pacote/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/pacote/node_modules/npm-package-arg": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", - "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, - "license": "ISC", + "license": "BSD-3-Clause", "dependencies": { - "hosted-git-info": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=10" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-json/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "node_modules/jasmine-core": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.8.0.tgz", + "integrity": "sha512-Q9dqmpUAfptwyueW3+HqBOkSuYd9I/clZSSfN97wXE/Nr2ROFNCwIBEC1F6kb3QXS9Fcz0LjFYSDQT+BiwjuhA==", "dev": true, "license": "MIT" }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.10" + "optional": true, + "peer": true, + "bin": { + "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "license": "MIT", - "dependencies": { - "entities": "^6.0.0" + "bin": { + "jsesc": "bin/jsesc" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": ">=6" } }, - "node_modules/parse5-html-rewriting-stream": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.0.tgz", - "integrity": "sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==", + "node_modules/json-parse-even-better-errors": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz", + "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==", "dev": true, "license": "MIT", - "dependencies": { - "entities": "^6.0.0", - "parse5": "^8.0.0", - "parse5-sax-parser": "^8.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/parse5-sax-parser": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-8.0.0.tgz", - "integrity": "sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==", + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "license": "MIT", - "dependencies": { - "parse5": "^8.0.0" + "bin": { + "json5": "lib/cli.js" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": ">=6" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "license": "MIT" }, - "node_modules/path-exists": { + "node_modules/jsonfile": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/karma": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", + "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.7.2", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 10" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/karma-chrome-launcher": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", + "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "which": "^1.2.1" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "node_modules/karma-chrome-launcher/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "node_modules/karma-coverage": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", + "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" }, "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10.0.0" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "node_modules/karma-coverage/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, - "license": "ISC" + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "node_modules/karma-coverage/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/karma-jasmine": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.0.1.tgz", + "integrity": "sha512-FkL1Kk+JAKmim8VWU8RXKZBpl0lLI7J8LijM0/q7oP7emfB6QMZV1Az+JgqGKSLpF0tYaav+KUVFQroZUxQTHA==", + "dev": true, "license": "MIT", + "dependencies": { + "jasmine-core": "^4.1.0" + }, "engines": { "node": ">=12" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "peerDependencies": { + "karma": "^6.0.0" } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", + "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", "dev": true, "license": "MIT", - "optional": true, - "engines": { - "node": ">=6" + "peerDependencies": { + "jasmine-core": "^4.0.0 || ^5.0.0", + "karma": "^6.0.0", + "karma-jasmine": "^5.0.0" } }, - "node_modules/piscina": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.3.tgz", - "integrity": "sha512-0u3N7H4+hbr40KjuVn2uNhOcthu/9usKhnw5vT3J7ply79v3D3M8naI00el9Klcy16x557VsEkkUQaHCWFXC/g==", + "node_modules/karma-jasmine/node_modules/jasmine-core": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.1.tgz", + "integrity": "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/karma/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=20.x" - }, - "optionalDependencies": { - "@napi-rs/nice": "^1.0.4" + "node": ">=8" } }, - "node_modules/pkce-challenge": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", - "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "node_modules/karma/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=16.20.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "node_modules/karma/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/postcss-loader": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", - "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", + "node_modules/karma/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", "dependencies": { - "cosmiconfig": "^9.0.0", - "jiti": "^1.20.0", - "semver": "^7.5.4" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">= 18.12.0" + "node": ">= 8.10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" + "url": "https://paulmillr.com/funding/" }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/postcss-media-query-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", - "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "node_modules/karma/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "license": "ISC", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", - "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "node_modules/karma/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^7.0.0", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "ms": "2.0.0" } }, - "node_modules/postcss-modules-scope": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", - "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "node_modules/karma/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", "dependencies": { - "postcss-selector-parser": "^7.0.0" + "is-glob": "^4.0.1" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">= 6" } }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "node_modules/karma/node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "icss-utils": "^5.0.0" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">= 0.8" } }, - "node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/karma/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/proc-log": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", - "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", + "node_modules/karma/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=8" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "node_modules/karma/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "node_modules/karma/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, "engines": { - "node": ">=10" + "node": ">= 0.6" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "node_modules/karma/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" + "mime-db": "1.52.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 0.6" } }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "node_modules/karma/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, - "node_modules/qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "node_modules/karma/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.9" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "node_modules/karma/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -12136,406 +7538,326 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "node_modules/karma/node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", - "iconv-lite": "0.7.0", + "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 0.8" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "node_modules/karma/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "picomatch": "^2.2.1" }, "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">=8.10.0" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/karma/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "node_modules/karma/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "node": ">= 0.8" } }, - "node_modules/reflect-metadata": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "license": "Apache-2.0" - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "node_modules/karma/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "regenerate": "^1.4.2" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/regex-parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.1.tgz", - "integrity": "sha512-yXLRqatcCuKtVHsWrNg0JL3l1zGfdXeEvDa0bdu4tCDQw0RpMDZsqbkyRTUnKMR0tXF627V2oEWjBEaEdqTwtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "node_modules/karma/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/regjsparser": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "node_modules/karma/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "jsesc": "~3.1.0" + "media-typer": "0.3.0", + "mime-types": "~2.1.24" }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "node_modules/karma/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "node_modules/karma/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/karma/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/resolve-url-loader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", - "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "node_modules/less": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/less/-/less-4.4.2.tgz", + "integrity": "sha512-j1n1IuTX1VQjIy3tT7cyGbX7nvQOsFLoIqobZv4ttI5axP923gA44zUj6miiA6R5Aoms4sEGVIIcucXUbRI14g==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.14", - "source-map": "0.6.1" + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" }, "engines": { - "node": ">=12" + "node": ">=14" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" } }, - "node_modules/resolve-url-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "pify": "^4.0.1", + "semver": "^5.6.0" }, "engines": { - "node": ">=8.9.0" + "node": ">=6" } }, - "node_modules/resolve-url-loader/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "mime": "cli.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "semver": "bin/semver" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", + "optional": true, + "peer": true, "engines": { - "node": ">= 4" + "node": ">=0.10.0" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", "dev": true, "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=20.0.0" } }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "node_modules/listr2/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "dev": true, "license": "MIT" }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "node_modules/lmdb": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.4.3.tgz", + "integrity": "sha512-GWV1kVi6uhrXWqe+3NXWO73OYe8fto6q8JMo0HOpk1vf8nEyFWgo4CSNJpIFzsOxOrysVUlcO48qRbQfmKd1gA==", "dev": true, - "license": "ISC", + "hasInstallScript": true, + "license": "MIT", + "optional": true, "dependencies": { - "glob": "^7.1.3" + "msgpackr": "^1.11.2", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.2.2", + "ordered-binary": "^1.5.3", + "weak-lru-cache": "^1.2.2" }, "bin": { - "rimraf": "bin.js" + "download-lmdb-prebuilds": "bin/download-prebuilds.js" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "3.4.3", + "@lmdb/lmdb-darwin-x64": "3.4.3", + "@lmdb/lmdb-linux-arm": "3.4.3", + "@lmdb/lmdb-linux-arm64": "3.4.3", + "@lmdb/lmdb-linux-x64": "3.4.3", + "@lmdb/lmdb-win32-arm64": "3.4.3", + "@lmdb/lmdb-win32-x64": "3.4.3" } }, - "node_modules/rollup": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.3.tgz", - "integrity": "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==", + "node_modules/lmdb/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", "dev": true, "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.3", - "@rollup/rollup-android-arm64": "4.52.3", - "@rollup/rollup-darwin-arm64": "4.52.3", - "@rollup/rollup-darwin-x64": "4.52.3", - "@rollup/rollup-freebsd-arm64": "4.52.3", - "@rollup/rollup-freebsd-x64": "4.52.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.3", - "@rollup/rollup-linux-arm-musleabihf": "4.52.3", - "@rollup/rollup-linux-arm64-gnu": "4.52.3", - "@rollup/rollup-linux-arm64-musl": "4.52.3", - "@rollup/rollup-linux-loong64-gnu": "4.52.3", - "@rollup/rollup-linux-ppc64-gnu": "4.52.3", - "@rollup/rollup-linux-riscv64-gnu": "4.52.3", - "@rollup/rollup-linux-riscv64-musl": "4.52.3", - "@rollup/rollup-linux-s390x-gnu": "4.52.3", - "@rollup/rollup-linux-x64-gnu": "4.52.3", - "@rollup/rollup-linux-x64-musl": "4.52.3", - "@rollup/rollup-openharmony-arm64": "4.52.3", - "@rollup/rollup-win32-arm64-msvc": "4.52.3", - "@rollup/rollup-win32-ia32-msvc": "4.52.3", - "@rollup/rollup-win32-x64-gnu": "4.52.3", - "@rollup/rollup-win32-x64-msvc": "4.52.3", - "fsevents": "~2.3.2" - } + "optional": true }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", + "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" + "is-unicode-supported": "^2.0.0", + "yoctocolors": "^2.1.1" }, "engines": { - "node": ">= 18" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-applescript": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", - "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, "engines": { "node": ">=18" }, @@ -12543,943 +7865,896 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "queue-microtask": "^1.2.2" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" + }, + "engines": { + "node": ">=8.0" } }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", "dependencies": { - "tslib": "^2.1.0" + "yallist": "^3.0.2" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "node_modules/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" + "semver": "^7.5.3" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/sass": { - "version": "1.90.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", - "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", + "node_modules/make-fetch-happen": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.3.tgz", + "integrity": "sha512-iyyEpDty1mwW3dGlYXAJqC/azFn5PPvgKVwXayOGBSmKLxhKZ9fg4qIan2ePpp1vJIwfFiO34LAPZgq9SZW9Aw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" + "@npmcli/agent": "^4.0.0", + "cacache": "^20.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^6.0.0", + "promise-retry": "^2.0.1", + "ssri": "^13.0.0" }, "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "@parcel/watcher": "^2.4.1" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/sass-loader": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.5.tgz", - "integrity": "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==", + "node_modules/make-fetch-happen/node_modules/proc-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", + "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", "dev": true, - "license": "MIT", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/make-fetch-happen/node_modules/ssri": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.0.tgz", + "integrity": "sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==", + "dev": true, + "license": "ISC", "dependencies": { - "neo-async": "^2.6.2" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", - "sass": "^1.3.0", - "sass-embedded": "*", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "webpack": { - "optional": true - } + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "dev": true, - "license": "ISC", - "optional": true + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "dev": true, "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, "engines": { - "node": ">= 10.13.0" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/schema-utils/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "engines": { + "node": ">=8.6" } }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true, - "license": "MIT" - }, - "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", - "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" - }, + "optional": true, "engines": { - "node": ">=10" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", "bin": { - "semver": "bin/semver.js" + "mime": "cli.js" }, "engines": { - "node": ">=10" + "node": ">=4.0.0" } }, - "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" - }, "engines": { - "node": ">= 18" + "node": ">= 0.6" } }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "randombytes": "^2.1.0" + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true, "license": "MIT", - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, "engines": { - "node": ">= 0.8.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/serve-index/node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.6" + "node": "*" } }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">= 0.6" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 0.6" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" - }, - "node_modules/serve-index/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/minipass-fetch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.0.tgz", + "integrity": "sha512-fiCdUALipqgPWrOVTz9fw0XhcazULXOSU6ie40DDbX1F49p1dBrSRBuswndTx1x3vEb/g0FT7vC4c4C2u/mh3A==", "dev": true, "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^3.0.1" + }, "engines": { - "node": ">= 0.6" + "node": "^20.17.0 || >=22.9.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" } }, - "node_modules/serve-index/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "mime-db": "1.52.0" + "minipass": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 8" } }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/serve-index/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, "license": "ISC" }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" + "yallist": "^4.0.0" }, "engines": { - "node": ">= 18" + "node": ">=8" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, "license": "ISC" }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "kind-of": "^6.0.2" + "minipass": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "shebang-regex": "^3.0.0" + "yallist": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "ISC" }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "minipass": "^7.1.2" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 18" } }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" + "minimist": "^1.2.6" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "mkdirp": "bin/cmd.js" } }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/msgpackr": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.5.tgz", + "integrity": "sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optional": true, + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" } }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "optional": true, "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" + "node-gyp-build-optional-packages": "5.2.2" }, - "engines": { - "node": ">= 0.4" + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", "dev": true, "license": "ISC", "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/sigstore": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-3.1.0.tgz", - "integrity": "sha512-ZpzWAFHIFqyFE56dXqgX/DkDRZdz+rRcjoIk/RQU4IX0wiCv1l8S7ZrXDHcCc+uaf+6o7w3h2l3g6GYG5TKN9Q==", + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.1.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.4.0", - "@sigstore/sign": "^3.1.0", - "@sigstore/tuf": "^3.1.0", - "@sigstore/verify": "^2.1.0" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" }, - "engines": { - "node": ">=12" + "bin": { + "needle": "bin/needle" }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "engines": { + "node": ">= 4.4.x" } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" + "node": ">= 0.6" } }, - "node_modules/socket.io": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", - "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-gyp": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.1.0.tgz", + "integrity": "sha512-W+RYA8jBnhSr2vrTtlPYPc1K+CSjGpVDRZxcqJcERZ8ND3A1ThWPHRwctTx3qC3oW99jt726jhdz3Y6ky87J4g==", "dev": true, "license": "MIT", "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.6.0", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^15.0.0", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.2", + "tinyglobby": "^0.2.12", + "which": "^6.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": ">=10.2.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/socket.io-adapter": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", - "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "debug": "~4.3.4", - "ws": "~8.17.1" + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" } }, - "node_modules/socket.io-adapter/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "node_modules/node-gyp-build-optional-packages/node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, + "license": "Apache-2.0", + "optional": true, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=8" } }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - }, + "license": "ISC", "engines": { - "node": ">=10.0.0" + "node": ">=16" } }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "node_modules/node-gyp/node_modules/proc-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", + "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, + "license": "ISC", "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/socket.io/node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/node-gyp/node_modules/which": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", + "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" }, "engines": { - "node": ">= 0.6" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/socket.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "license": "MIT" + }, + "node_modules/nopt": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz", + "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ms": "^2.1.3" + "abbrev": "^4.0.0" }, - "engines": { - "node": ">=6.0" + "bin": { + "nopt": "bin/nopt.js" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/socket.io/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/socket.io/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/npm-bundled": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-4.0.0.tgz", + "integrity": "sha512-IxaQZDMsqfQ2Lz37VvyyEtKLe8FsRZuysmedy/N06TU1RyVppYKXrO4xIhR0F+7ubIBox6Q7nir6fQI3ej39iA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "mime-db": "1.52.0" + "npm-normalize-package-bin": "^4.0.0" }, "engines": { - "node": ">= 0.6" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/socket.io/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/npm-install-checks": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz", + "integrity": "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, "engines": { - "node": ">= 0.6" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", + "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", "dev": true, - "license": "MIT", - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "node_modules/npm-package-arg": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.1.tgz", + "integrity": "sha512-6zqls5xFvJbgFjB1B2U6yITtyGBjDBORB7suI4zA4T/sZ1OmkMFlaQSNB/4K0LtXNA1t4OprAFxPisadK5O2ag==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" + "hosted-git-info": "^9.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" }, "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/socks-proxy-agent": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "node_modules/npm-packlist": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.3.tgz", + "integrity": "sha512-zPukTwJMOu5X5uvm0fztwS5Zxyvmk38H/LfidkOMt3gbZVCyro2cD/ETzwzVPcWZA3JOyPznfUN/nkyFiyUbxg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" + "ignore-walk": "^8.0.0", + "proc-log": "^6.0.0" }, "engines": { - "node": ">= 14" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "node_modules/npm-packlist/node_modules/proc-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", + "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC", "engines": { - "node": ">= 12" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "node_modules/npm-pick-manifest": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz", + "integrity": "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC", + "dependencies": { + "npm-install-checks": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "npm-package-arg": "^13.0.0", + "semver": "^7.3.5" + }, "engines": { - "node": ">=0.10.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/source-map-loader": { + "node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", - "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", + "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.2" - }, + "license": "ISC", "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.72.1" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/npm-registry-fetch": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz", + "integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "@npmcli/redact": "^4.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^15.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^13.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/npm-registry-fetch/node_modules/proc-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.0.0.tgz", + "integrity": "sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, - "license": "Apache-2.0", + "license": "BSD-2-Clause", "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, - "license": "CC0-1.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">=6.0.0" + "node": ">= 0.8" } }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "wrappy": "1" } }, - "node_modules/ssri": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", - "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^7.0.3" + "mimic-function": "^5.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "node_modules/ora": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.0.0.tgz", + "integrity": "sha512-m0pg2zscbYgWbqRR6ABga5c3sZdEon7bSgjnlXC64kxtxLOyjRcbbUkLj7HFyy/FTD+P2xdBWu8snGhYI0jc4A==", "dev": true, "license": "MIT", + "dependencies": { + "chalk": "^5.6.2", + "cli-cursor": "^5.0.0", + "cli-spinners": "^3.2.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.1.0", + "log-symbols": "^7.0.1", + "stdin-discarder": "^0.2.2", + "string-width": "^8.1.0", + "strip-ansi": "^7.1.2" + }, "engines": { - "node": ">= 0.8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "node_modules/ordered-binary": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.0.tgz", + "integrity": "sha512-IQh2aMfMIDbPjI/8a3Edr+PiOpcsB7yo8NdW7aHWVaoR/pcDldunMvnnwbk/auPGqmKeAdxtZl7MHX/QmPwhvQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, "license": "MIT", "engines": { @@ -13489,851 +8764,980 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "node_modules/pacote": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.0.3.tgz", + "integrity": "sha512-itdFlanxO0nmQv4ORsvA9K1wv40IPfB9OmWqfaJWvoJ30VKyHsqNgDVeG+TVhI7Gk7XW8slUy7cA9r6dF5qohw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" + "@npmcli/git": "^7.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "@npmcli/run-script": "^10.0.0", + "cacache": "^20.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^13.0.0", + "npm-packlist": "^10.0.1", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^4.0.0", + "ssri": "^12.0.0", + "tar": "^7.4.3" + }, + "bin": { + "pacote": "bin/index.js" }, "engines": { - "node": ">=8.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" + "optional": true, + "peer": true, + "engines": { + "node": ">= 0.10" } }, - "node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "node_modules/parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", "license": "MIT", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "entities": "^6.0.0" }, - "engines": { - "node": ">=18" + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.0.tgz", + "integrity": "sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0", + "parse5": "^8.0.0", + "parse5-sax-parser": "^8.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/parse5-sax-parser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-8.0.0.tgz", + "integrity": "sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "parse5": "^8.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "ansi-regex": "^5.0.1" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=8" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=6" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/piscina": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.3.tgz", + "integrity": "sha512-0u3N7H4+hbr40KjuVn2uNhOcthu/9usKhnw5vT3J7ply79v3D3M8naI00el9Klcy16x557VsEkkUQaHCWFXC/g==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, "engines": { - "node": ">=8" + "node": ">=20.x" + }, + "optionalDependencies": { + "@napi-rs/nice": "^1.0.4" } }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "node_modules/pkce-challenge": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=16.20.0" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=8" + "node": "^10 || ^12 || >=14" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "node_modules/proc-log": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "err-code": "^2.0.2", + "retry": "^0.12.0" }, "engines": { "node": ">=10" } }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": ">= 8" + "node": ">= 0.10" } }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT", + "optional": true, + "peer": true }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/tar/node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true, "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, "engines": { - "node": ">= 8" + "node": ">=0.9" } }, - "node_modules/tar/node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "dev": true, - "license": "ISC", + "license": "BSD-3-Clause", "dependencies": { - "yallist": "^4.0.0" + "side-channel": "^1.1.0" }, "engines": { - "node": ">=8" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, "engines": { - "node": ">=10" + "node": ">= 0.6" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/terser": { - "version": "5.43.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", - "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.14.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.10" } }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.14", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", - "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", - "terser": "^5.31.1" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=0.10.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" + "url": "https://opencollective.com/express" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/thingies": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", - "integrity": "sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw==", + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, "engines": { - "node": ">=10.18" + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "^2" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "license": "MIT", "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "dev": true, "license": "MIT", "engines": { - "node": ">=14.14" + "node": ">= 4" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", "dependencies": { - "is-number": "^7.0.0" + "glob": "^7.1.3" }, - "engines": { - "node": ">=8.0" + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "node_modules/rolldown": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.47.tgz", + "integrity": "sha512-Mid74GckX1OeFAOYz9KuXeWYhq3xkXbMziYIC+ULVdUzPTG9y70OBSBQDQn9hQP8u/AfhuYw1R0BSg15nBI4Dg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tree-dump": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", - "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" + "dependencies": { + "@oxc-project/types": "=0.96.0", + "@rolldown/pluginutils": "1.0.0-beta.47" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" + "bin": { + "rolldown": "bin/cli.mjs" }, - "peerDependencies": { - "tslib": "2" + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-beta.47", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.47", + "@rolldown/binding-darwin-x64": "1.0.0-beta.47", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.47", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.47", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.47", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.47", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.47", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.47", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.47", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.47", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.47", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.47", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.47" } }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "node_modules/rollup": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", + "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "dev": true, "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, "bin": { - "tree-kill": "cli.js" + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.53.3", + "@rollup/rollup-android-arm64": "4.53.3", + "@rollup/rollup-darwin-arm64": "4.53.3", + "@rollup/rollup-darwin-x64": "4.53.3", + "@rollup/rollup-freebsd-arm64": "4.53.3", + "@rollup/rollup-freebsd-x64": "4.53.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", + "@rollup/rollup-linux-arm-musleabihf": "4.53.3", + "@rollup/rollup-linux-arm64-gnu": "4.53.3", + "@rollup/rollup-linux-arm64-musl": "4.53.3", + "@rollup/rollup-linux-loong64-gnu": "4.53.3", + "@rollup/rollup-linux-ppc64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-musl": "4.53.3", + "@rollup/rollup-linux-s390x-gnu": "4.53.3", + "@rollup/rollup-linux-x64-gnu": "4.53.3", + "@rollup/rollup-linux-x64-musl": "4.53.3", + "@rollup/rollup-openharmony-arm64": "4.53.3", + "@rollup/rollup-win32-arm64-msvc": "4.53.3", + "@rollup/rollup-win32-ia32-msvc": "4.53.3", + "@rollup/rollup-win32-x64-gnu": "4.53.3", + "@rollup/rollup-win32-x64-msvc": "4.53.3", + "fsevents": "~2.3.2" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/tuf-js": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-3.1.0.tgz", - "integrity": "sha512-3T3T04WzowbwV2FDiGXBbr81t64g1MUGGJRgT4x5o97N+8ArdhVCAF9IxFrxuSJmM3E5Asn7nKHkao0ibcZXAg==", + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "dev": true, "license": "MIT", "dependencies": { - "@tufjs/models": "3.0.1", - "debug": "^4.4.1", - "make-fetch-happen": "^14.0.3" + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">= 18" } }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, "license": "MIT", "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typed-assert": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "license": "MIT" }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/ua-parser-js": { - "version": "0.7.41", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.41.tgz", - "integrity": "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==", + "node_modules/sass": { + "version": "1.93.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz", + "integrity": "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" - } - ], "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, "bin": { - "ua-parser-js": "script/cli.js" + "sass": "sass.js" }, "engines": { - "node": "*" + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, - "node_modules/undici-types": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", - "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "node_modules/sax": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz", + "integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "optional": true, "peer": true }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "dev": true, - "license": "MIT", + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", "dev": true, "license": "MIT", "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" }, "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" + "node": ">= 18" } }, - "node_modules/unicode-property-aliases-ecmascript": { + "node_modules/serve-static": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unique-filename": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", - "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", - "dev": true, - "license": "ISC", "dependencies": { - "unique-slug": "^5.0.0" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">= 18" } }, - "node_modules/unique-slug": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", - "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "imurmurhash": "^0.1.4" + "shebang-regex": "^3.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=8" } }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "license": "MIT", "engines": { - "node": ">= 4.0.0" + "node": ">=8" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" }, - "bin": { - "update-browserslist-db": "cli.js" + "engines": { + "node": ">= 0.4" }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "punycode": "^2.1.0" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/util-deprecate": { + "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "node_modules/sigstore": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.0.0.tgz", + "integrity": "sha512-Gw/FgHtrLM9WP8P5lLcSGh9OQcrTruWCELAiS48ik1QbL0cH+dfjomiRTUE9zzz+D1N6rOLkwXUvVmXZAsNE0Q==", "dev": true, "license": "Apache-2.0", "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/validate-npm-package-name": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz", - "integrity": "sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==", - "dev": true, - "license": "ISC", + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.0.0", + "@sigstore/protobuf-specs": "^0.5.0", + "@sigstore/sign": "^4.0.0", + "@sigstore/tuf": "^4.0.0", + "@sigstore/verify": "^3.0.0" + }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, "engines": { - "node": ">= 0.8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 6.0.0", + "npm": ">= 3.0.0" } }, - "node_modules/watchpack": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", - "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", "dev": true, "license": "MIT", "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" }, "engines": { - "node": ">=10.13.0" + "node": ">=10.2.0" } }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", "dev": true, "license": "MIT", "dependencies": { - "minimalistic-assert": "^1.0.0" + "debug": "~4.3.4", + "ws": "~8.17.1" } }, - "node_modules/weak-lru-cache": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", - "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", - "optional": true + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } }, - "node_modules/webpack": { - "version": "5.101.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.101.2.tgz", - "integrity": "sha512-4JLXU0tD6OZNVqlwzm3HGEhAHufSiyv+skb7q0d2367VDMzrU1Q/ZeepvkcHH0rZie6uqEtTQQe0OEOOluH3Mg==", + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.8", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", - "acorn-import-phases": "^1.0.3", - "browserslist": "^4.24.0", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.3", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.2", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.11", - "watchpack": "^2.4.1", - "webpack-sources": "^3.3.3" - }, - "bin": { - "webpack": "bin/webpack.js" + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" }, "engines": { - "node": ">=10.13.0" + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "engines": { + "node": ">=6.0" }, "peerDependenciesMeta": { - "webpack-cli": { + "supports-color": { "optional": true } } }, - "node_modules/webpack-dev-middleware": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", - "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", + "node_modules/socket.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "license": "MIT", "dependencies": { - "colorette": "^2.0.10", - "memfs": "^4.6.0", - "mime-types": "^2.1.31", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" }, - "peerDependencies": { - "webpack": "^5.0.0" + "engines": { + "node": ">=6.0" }, "peerDependenciesMeta": { - "webpack": { + "supports-color": { "optional": true } } }, - "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "node_modules/socket.io/node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", @@ -14343,7 +9747,7 @@ "node": ">= 0.6" } }, - "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "node_modules/socket.io/node_modules/mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", @@ -14356,641 +9760,593 @@ "node": ">= 0.6" } }, - "node_modules/webpack-dev-server": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz", - "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/bonjour": "^3.5.13", - "@types/connect-history-api-fallback": "^1.5.4", - "@types/express": "^4.17.21", - "@types/express-serve-static-core": "^4.17.21", - "@types/serve-index": "^1.9.4", - "@types/serve-static": "^1.15.5", - "@types/sockjs": "^0.3.36", - "@types/ws": "^8.5.10", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.2.1", - "chokidar": "^3.6.0", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "express": "^4.21.2", - "graceful-fs": "^4.2.6", - "http-proxy-middleware": "^2.0.9", - "ipaddr.js": "^2.1.0", - "launch-editor": "^2.6.1", - "open": "^10.0.3", - "p-retry": "^6.2.0", - "schema-utils": "^4.2.0", - "selfsigned": "^2.4.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^7.4.2", - "ws": "^8.18.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, + "node_modules/socket.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { - "optional": true - } + "node": ">= 0.6" } }, - "node_modules/webpack-dev-server/node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "dev": true, "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 10.0.0", + "npm": ">= 3.0.0" } }, - "node_modules/webpack-dev-server/node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">= 14" } }, - "node_modules/webpack-dev-server/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">= 12" } }, - "node_modules/webpack-dev-server/node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/webpack-dev-server/node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/webpack-dev-server/node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } }, - "node_modules/webpack-dev-server/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/webpack-dev-server/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", "dev": true, - "license": "MIT" + "license": "CC0-1.0" }, - "node_modules/webpack-dev-server/node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "node_modules/ssri": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", + "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/webpack-dev-server/node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, "engines": { "node": ">= 0.8" } }, - "node_modules/webpack-dev-server/node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-dev-server/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" }, "engines": { - "node": ">= 6" + "node": ">=8.0" + } + }, + "node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", - "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", - "dev": true, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" + "node": ">=12" }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/webpack-dev-server/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/webpack-dev-server/node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, "license": "MIT", "engines": { - "node": ">= 10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/webpack-dev-server/node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "node_modules/tar": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", + "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=18" } }, - "node_modules/webpack-dev-server/node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, - "node_modules/webpack-dev-server/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "node_modules/terser": { + "version": "5.44.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", + "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, "bin": { - "mime": "cli.js" + "terser": "bin/terser" }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/webpack-dev-server/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=14.14" } }, - "node_modules/webpack-dev-server/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "is-number": "^7.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=8.0" } }, - "node_modules/webpack-dev-server/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=0.6" } }, - "node_modules/webpack-dev-server/node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "dev": true, - "license": "MIT" + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, - "node_modules/webpack-dev-server/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/tuf-js": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-4.0.0.tgz", + "integrity": "sha512-Lq7ieeGvXDXwpoSmOSgLWVdsGGV9J4a77oDTAPe/Ltrqnnm/ETaRlBAQTH5JatEh8KXuE6sddf9qAv1Q2282Hg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8.6" + "dependencies": { + "@tufjs/models": "4.0.0", + "debug": "^4.4.1", + "make-fetch-happen": "^15.0.0" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/webpack-dev-server/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "side-channel": "^1.0.6" + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" }, "engines": { - "node": ">=0.6" + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=14.17" } }, - "node_modules/webpack-dev-server/node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "node_modules/ua-parser-js": { + "version": "0.7.41", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.41.tgz", + "integrity": "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bin": { + "ua-parser-js": "script/cli.js" }, "engines": { - "node": ">= 0.8" + "node": "*" } }, - "node_modules/webpack-dev-server/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/undici": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz", + "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==", "dev": true, "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": ">=20.18.1" } }, - "node_modules/webpack-dev-server/node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/unique-filename": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-5.0.0.tgz", + "integrity": "sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==", + "dev": true, + "license": "ISC", "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" + "unique-slug": "^6.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/webpack-dev-server/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "node_modules/unique-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-6.0.0.tgz", + "integrity": "sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, "engines": { - "node": ">= 0.8" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/webpack-dev-server/node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, "engines": { - "node": ">= 0.8.0" + "node": ">= 4.0.0" } }, - "node_modules/webpack-dev-server/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/webpack-dev-server/node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, - "engines": { - "node": ">= 0.6" + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" } }, - "node_modules/webpack-merge": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", - "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.1" - }, "engines": { - "node": ">=18.0.0" + "node": ">=6" } }, - "node_modules/webpack-sources": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, "license": "MIT", "engines": { - "node": ">=10.13.0" + "node": ">= 0.4.0" } }, - "node_modules/webpack-subresource-integrity": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", - "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "typed-assert": "^1.0.8" - }, - "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", - "webpack": "^5.12.0" - }, - "peerDependenciesMeta": { - "html-webpack-plugin": { - "optional": true - } + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "node_modules/webpack/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "node_modules/validate-npm-package-name": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz", + "integrity": "sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==", "dev": true, - "license": "MIT" + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } }, - "node_modules/webpack/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/webpack/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "node_modules/watchpack": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" }, "engines": { - "node": ">=0.8.0" + "node": ">=10.13.0" } }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=0.8.0" - } + "license": "MIT", + "optional": true }, "node_modules/which": { "version": "2.0.2", @@ -15008,13 +10364,6 @@ "node": ">= 8" } }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true, - "license": "MIT" - }, "node_modules/wrap-ansi": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", @@ -15032,94 +10381,27 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, - "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" + "node": ">=18" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/wrappy": { @@ -15151,22 +10433,6 @@ } } }, - "node_modules/wsl-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", - "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-wsl": "^3.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -15208,14 +10474,37 @@ "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "node_modules/yargs/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -15245,13 +10534,13 @@ } }, "node_modules/zod-to-json-schema": { - "version": "3.24.6", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", - "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.0.tgz", + "integrity": "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==", "dev": true, "license": "ISC", "peerDependencies": { - "zod": "^3.24.1" + "zod": "^3.25 || ^4" } }, "node_modules/zone.js": { diff --git a/docs/src/assets/stackblitz/package.json b/docs/src/assets/stackblitz/package.json index ff88a9f61d0c..adeef681e680 100644 --- a/docs/src/assets/stackblitz/package.json +++ b/docs/src/assets/stackblitz/package.json @@ -10,26 +10,25 @@ }, "private": true, "dependencies": { - "@angular/cdk": "^20.2.0", - "@angular/common": "^20.2.0", - "@angular/compiler": "^20.2.0", - "@angular/core": "^20.2.0", - "@angular/forms": "^20.2.0", - "@angular/localize": "^20.2.0", - "@angular/material": "^20.2.0", - "@angular/material-luxon-adapter": "^20.2.0", - "@angular/platform-browser": "^20.2.0", - "@angular/platform-browser-dynamic": "^20.2.0", - "@angular/router": "^20.2.0", + "@angular/cdk": "^21.0.0", + "@angular/common": "^21.0.0", + "@angular/compiler": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/forms": "^21.0.0", + "@angular/localize": "^21.0.0", + "@angular/material": "^21.0.0", + "@angular/material-luxon-adapter": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "@angular/router": "^21.0.0", "luxon": "^3.7.2", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" }, "devDependencies": { - "@angular-devkit/build-angular": "^20.2.0", - "@angular/cli": "^20.2.0", - "@angular/compiler-cli": "^20.2.0", + "@angular/cli": "^21.0.0", + "@angular/build": "^21.0.0", + "@angular/compiler-cli": "^21.0.0", "@types/jasmine": "~5.1.0", "@types/luxon": "^3.0.0", "@types/node": "^12.11.1", diff --git a/docs/src/assets/stackblitz/src/test.ts b/docs/src/assets/stackblitz/src/test.ts deleted file mode 100644 index 0323f914c153..000000000000 --- a/docs/src/assets/stackblitz/src/test.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -// This file is required by karma.conf.js and loads recursively all the .spec and framework files - -import 'zone.js/testing'; -import {getTestBed} from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting, -} from '@angular/platform-browser-dynamic/testing'; - -// First, initialize the Angular testing environment. -getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); - -// Then we find all the tests. -const context = (import.meta as any).webpackContext('./', { - recursive: true, - regExp: /\.spec\.ts$/, -}); - -// And load the modules. -context.keys().map(context); diff --git a/docs/src/assets/stackblitz/tsconfig.spec.json b/docs/src/assets/stackblitz/tsconfig.spec.json index f140ce15bf10..47e3dd755170 100644 --- a/docs/src/assets/stackblitz/tsconfig.spec.json +++ b/docs/src/assets/stackblitz/tsconfig.spec.json @@ -5,6 +5,5 @@ "outDir": "./out-tsc/spec", "types": ["jasmine"] }, - "files": ["src/test.ts"], "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] } diff --git a/docs/src/robots.txt b/docs/src/robots.txt index 2edb8fe702ff..ac97c8224f72 100644 --- a/docs/src/robots.txt +++ b/docs/src/robots.txt @@ -1,3 +1,3 @@ Sitemap: https://material.angular.dev/sitemap.xml User-agent: * -Disallow: +Disallow: /docs-content/ diff --git a/docs/src/styles.scss b/docs/src/styles.scss index aa13d737aeee..eb3ebfd8d76c 100644 --- a/docs/src/styles.scss +++ b/docs/src/styles.scss @@ -9,16 +9,19 @@ html { background-color: var(--mat-sys-surface); color: var(--mat-sys-on-surface); - @include mat.theme(( - color: ( - theme-type: light, - primary: mat.$azure-palette, - tertiary: mat.$blue-palette, - ), - typography: Roboto, - density: 0, - )); + @include mat.theme( + ( + color: ( + theme-type: light, + primary: mat.$azure-palette, + tertiary: mat.$blue-palette, + ), + typography: Roboto, + density: 0, + ) + ); + @include mat.system-classes(); @include cdk.a11y-visually-hidden(); } diff --git a/docs/src/styles/_markdown.scss b/docs/src/styles/_markdown.scss index 99c056889a22..51c8dc31be0d 100644 --- a/docs/src/styles/_markdown.scss +++ b/docs/src/styles/_markdown.scss @@ -44,7 +44,9 @@ font-weight: 400; } - p, ul, ol { + p, + ul, + ol { font-size: 16px; line-height: 28px; } @@ -118,4 +120,30 @@ } } + summary { + cursor: pointer; + padding: 8px; + + &:hover { + background-color: color-mix( + in srgb, + var(--mat-sys-on-surface) calc(var(--mat-sys-hover-state-layer-opacity) * 100%), + transparent + ); + } + &:focus { + background-color: color-mix( + in srgb, + var(--mat-sys-on-surface) calc(var(--mat-sys-focus-state-layer-opacity) * 100%), + transparent + ); + } + &:active { + background-color: color-mix( + in srgb, + var(--mat-sys-on-surface) calc(var(--mat-sys-pressed-state-layer-opacity) * 100%), + transparent + ); + } + } } diff --git a/docs/src/styles/_tables.scss b/docs/src/styles/_tables.scss index c9084474be8b..cf41ac2373ce 100644 --- a/docs/src/styles/_tables.scss +++ b/docs/src/styles/_tables.scss @@ -10,7 +10,6 @@ width: 100%; } - // Styles specific only to the table inside markdown. .docs-markdown > table { font-size: 14px; @@ -18,10 +17,10 @@ // Code tends to wrap inside tables which doesn't look great with the background color. code { background: transparent; + padding: 0; } } - .docs-api th, .docs-markdown > table th { max-width: 100px; diff --git a/goldens/BUILD.bazel b/goldens/BUILD.bazel index d26af032d4ae..063143221953 100644 --- a/goldens/BUILD.bazel +++ b/goldens/BUILD.bazel @@ -39,3 +39,12 @@ api_golden_test_npm_package( "//:node_modules/@types/youtube": "youtube", }, ) + +api_golden_test_npm_package( + name = "aria_api", + data = glob(["aria/**"]) + [ + "//src/aria:npm_package", + ], + golden_dir = "goldens/aria", + npm_package = "src/aria/npm_package", +) diff --git a/goldens/aria/accordion/index.api.md b/goldens/aria/accordion/index.api.md new file mode 100644 index 000000000000..2d5ea966bc61 --- /dev/null +++ b/goldens/aria/accordion/index.api.md @@ -0,0 +1,76 @@ +## API Report File for "@angular/aria_accordion" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as _angular_cdk_bidi from '@angular/cdk/bidi'; +import * as _angular_core from '@angular/core'; +import { OnDestroy } from '@angular/core'; +import { WritableSignal } from '@angular/core'; + +// @public +export class AccordionContent { + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class AccordionGroup { + constructor(); + collapseAll(): void; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + expandAll(): void; + readonly multiExpandable: _angular_core.InputSignalWithTransform; + readonly _pattern: AccordionGroupPattern; + readonly softDisabled: _angular_core.InputSignalWithTransform; + readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; + readonly wrap: _angular_core.InputSignalWithTransform; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class AccordionPanel { + constructor(); + readonly _accordionTriggerPattern: WritableSignal; + collapse(): void; + expand(): void; + readonly id: _angular_core.InputSignal; + readonly panelId: _angular_core.InputSignal; + readonly _pattern: AccordionPanelPattern; + toggle(): void; + readonly visible: _angular_core.Signal; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class AccordionTrigger { + readonly _accordionPanelPattern: WritableSignal; + readonly active: _angular_core.Signal; + collapse(): void; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + expand(): void; + readonly expanded: _angular_core.ModelSignal; + readonly id: _angular_core.InputSignal; + readonly panelId: _angular_core.InputSignal; + readonly _pattern: AccordionTriggerPattern; + toggle(): void; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/aria/combobox/index.api.md b/goldens/aria/combobox/index.api.md new file mode 100644 index 000000000000..57dbe14c8fe1 --- /dev/null +++ b/goldens/aria/combobox/index.api.md @@ -0,0 +1,80 @@ +## API Report File for "@angular/aria_combobox" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as _angular_cdk_bidi from '@angular/cdk/bidi'; +import * as _angular_core from '@angular/core'; +import { OnDestroy } from '@angular/core'; + +// @public +export class Combobox { + constructor(); + readonly alwaysExpanded: _angular_core.InputSignalWithTransform; + close(): void; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly expanded: _angular_core.Signal; + filterMode: _angular_core.InputSignal<"manual" | "auto-select" | "highlight">; + readonly firstMatch: _angular_core.InputSignal; + readonly inputElement: _angular_core.Signal; + open(): void; + readonly _pattern: ComboboxPattern; + readonly popup: _angular_core.Signal | undefined>; + readonly readonly: _angular_core.InputSignalWithTransform; + protected textDirection: _angular_core.Signal<_angular_cdk_bidi.Direction>; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngCombobox]", ["ngCombobox"], { "filterMode": { "alias": "filterMode"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "firstMatch": { "alias": "firstMatch"; "required": false; "isSignal": true; }; "alwaysExpanded": { "alias": "alwaysExpanded"; "required": false; "isSignal": true; }; }, {}, ["popup"], never, true, [{ directive: typeof DeferredContentAware; inputs: { "preserveContent": "preserveContent"; }; outputs: {}; }]>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// @public +export class ComboboxDialog { + constructor(); + // (undocumented) + close(): void; + readonly combobox: Combobox; + readonly element: HTMLElement; + // (undocumented) + _pattern: ComboboxDialogPattern; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class ComboboxInput { + constructor(); + readonly combobox: Combobox; + readonly element: HTMLElement; + value: _angular_core.ModelSignal; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class ComboboxPopup { + readonly combobox: Combobox | null; + readonly _controls: _angular_core.WritableSignal | ComboboxTreeControls | ComboboxDialogPattern | undefined>; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngComboboxPopup]", ["ngComboboxPopup"], {}, {}, never, never, true, never>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// @public +export class ComboboxPopupContainer { + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/aria/grid/index.api.md b/goldens/aria/grid/index.api.md new file mode 100644 index 000000000000..237af288901c --- /dev/null +++ b/goldens/aria/grid/index.api.md @@ -0,0 +1,97 @@ +## API Report File for "@angular/aria_grid" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as _angular_aria_private_public_api from '@angular/aria/private/public-api'; +import * as _angular_cdk_bidi from '@angular/cdk/bidi'; +import * as _angular_core from '@angular/core'; +import { ElementRef } from '@angular/core'; +import { Signal } from '@angular/core'; + +// @public +export class Grid { + constructor(); + readonly colWrap: _angular_core.InputSignal<"continuous" | "loop" | "nowrap">; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly enableRangeSelection: _angular_core.InputSignalWithTransform; + readonly enableSelection: _angular_core.InputSignalWithTransform; + readonly focusMode: _angular_core.InputSignal<"roving" | "activedescendant">; + readonly multi: _angular_core.InputSignalWithTransform; + readonly _pattern: GridPattern; + readonly rowWrap: _angular_core.InputSignal<"continuous" | "loop" | "nowrap">; + readonly selectionMode: _angular_core.InputSignal<"follow" | "explicit">; + readonly softDisabled: _angular_core.InputSignalWithTransform; + readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class GridCell { + constructor(); + readonly active: Signal; + readonly colIndex: _angular_core.InputSignal; + readonly colSpan: _angular_core.InputSignal; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly id: _angular_core.InputSignal; + readonly orientation: _angular_core.InputSignal<"vertical" | "horizontal">; + readonly _pattern: GridCellPattern; + readonly role: _angular_core.InputSignal<"gridcell" | "columnheader" | "rowheader">; + readonly rowIndex: _angular_core.InputSignal; + readonly rowSpan: _angular_core.InputSignal; + readonly selectable: _angular_core.InputSignal; + readonly selected: _angular_core.ModelSignal; + protected readonly _tabIndex: Signal; + readonly tabindex: _angular_core.InputSignal; + readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; + readonly wrap: _angular_core.InputSignalWithTransform; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class GridCellWidget { + constructor(); + activate(): void; + readonly active: Signal; + deactivate(): void; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly focusTarget: _angular_core.InputSignal | HTMLElement | undefined>; + readonly id: _angular_core.InputSignal; + get isActivated(): Signal; + readonly onActivate: _angular_core.OutputEmitterRef; + readonly onDeactivate: _angular_core.OutputEmitterRef; + readonly _pattern: GridCellWidgetPattern; + protected readonly _tabIndex: Signal; + readonly tabindex: _angular_core.InputSignal; + readonly widgetType: _angular_core.InputSignal<"simple" | "complex" | "editable">; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class GridRow { + readonly element: HTMLElement; + readonly _gridPattern: Signal<_angular_aria_private_public_api.GridPattern>; + readonly _pattern: GridRowPattern; + readonly rowIndex: _angular_core.InputSignal; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/aria/index.api.md b/goldens/aria/index.api.md new file mode 100644 index 000000000000..7dfdcb1f20fc --- /dev/null +++ b/goldens/aria/index.api.md @@ -0,0 +1,14 @@ +## API Report File for "@angular/aria" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Version } from '@angular/core'; + +// @public +export const VERSION: Version; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/aria/listbox/index.api.md b/goldens/aria/listbox/index.api.md new file mode 100644 index 000000000000..81a3e399963a --- /dev/null +++ b/goldens/aria/listbox/index.api.md @@ -0,0 +1,60 @@ +## API Report File for "@angular/aria_listbox" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as _angular_aria_private_public_api from '@angular/aria/private/public-api'; +import * as _angular_cdk_bidi from '@angular/cdk/bidi'; +import * as _angular_core from '@angular/core'; + +// @public +export class Listbox { + constructor(); + disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + focusMode: _angular_core.InputSignal<"roving" | "activedescendant">; + gotoFirst(): void; + readonly id: _angular_core.InputSignal; + protected items: _angular_core.Signal<_angular_aria_private_public_api.OptionPattern[]>; + multi: _angular_core.InputSignalWithTransform; + // (undocumented) + _onFocus(): void; + orientation: _angular_core.InputSignal<"vertical" | "horizontal">; + readonly _pattern: ListboxPattern; + readonly: _angular_core.InputSignalWithTransform; + // (undocumented) + scrollActiveItemIntoView(options?: ScrollIntoViewOptions): void; + selectionMode: _angular_core.InputSignal<"follow" | "explicit">; + softDisabled: _angular_core.InputSignalWithTransform; + protected textDirection: _angular_core.Signal<_angular_cdk_bidi.Direction>; + typeaheadDelay: _angular_core.InputSignal; + values: _angular_core.ModelSignal; + wrap: _angular_core.InputSignalWithTransform; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngListbox]", ["ngListbox"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "multi": { "alias": "multi"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "softDisabled": { "alias": "softDisabled"; "required": false; "isSignal": true; }; "focusMode": { "alias": "focusMode"; "required": false; "isSignal": true; }; "selectionMode": { "alias": "selectionMode"; "required": false; "isSignal": true; }; "typeaheadDelay": { "alias": "typeaheadDelay"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "values": { "alias": "values"; "required": false; "isSignal": true; }; }, { "values": "valuesChange"; }, ["_options"], never, true, [{ directive: typeof ComboboxPopup; inputs: {}; outputs: {}; }]>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// @public +class Option_2 { + active: _angular_core.Signal; + disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly id: _angular_core.InputSignal; + label: _angular_core.InputSignal; + readonly _pattern: OptionPattern; + protected searchTerm: _angular_core.Signal; + readonly selected: _angular_core.Signal; + value: _angular_core.InputSignal; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngOption]", ["ngOption"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} +export { Option_2 as Option } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/aria/menu/index.api.md b/goldens/aria/menu/index.api.md new file mode 100644 index 000000000000..6199c6194184 --- /dev/null +++ b/goldens/aria/menu/index.api.md @@ -0,0 +1,109 @@ +## API Report File for "@angular/aria_menu" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as _angular_cdk_bidi from '@angular/cdk/bidi'; +import * as _angular_core from '@angular/core'; +import { OnDestroy } from '@angular/core'; +import { Signal } from '@angular/core'; + +// @public +export class Menu { + constructor(); + readonly _allItems: Signal[]>; + close(): void; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly expansionDelay: _angular_core.InputSignal; + readonly id: _angular_core.InputSignal; + readonly _items: Signal[]>; + onSelect: _angular_core.OutputEmitterRef; + readonly parent: _angular_core.WritableSignal | MenuItem | undefined>; + readonly _pattern: MenuPattern; + readonly tabIndex: Signal<0 | -1>; + readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; + readonly typeaheadDelay: _angular_core.InputSignal; + readonly visible: Signal; + readonly wrap: _angular_core.InputSignalWithTransform; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngMenu]", ["ngMenu"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "typeaheadDelay": { "alias": "typeaheadDelay"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "expansionDelay": { "alias": "expansionDelay"; "required": false; "isSignal": true; }; }, { "onSelect": "onSelect"; }, ["_allItems"], never, true, [{ directive: typeof DeferredContentAware; inputs: { "preserveContent": "preserveContent"; }; outputs: {}; }]>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// @public +export class MenuBar { + constructor(); + readonly _allItems: _angular_core.Signal[]>; + close(): void; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + // (undocumented) + readonly _items: SignalLike[]>; + onSelect: _angular_core.OutputEmitterRef; + readonly _pattern: MenuBarPattern; + readonly softDisabled: _angular_core.InputSignalWithTransform; + readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; + readonly typeaheadDelay: _angular_core.InputSignal; + readonly values: _angular_core.ModelSignal; + readonly wrap: _angular_core.InputSignalWithTransform; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngMenuBar]", ["ngMenuBar"], { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "softDisabled": { "alias": "softDisabled"; "required": false; "isSignal": true; }; "values": { "alias": "values"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "typeaheadDelay": { "alias": "typeaheadDelay"; "required": false; "isSignal": true; }; }, { "values": "valuesChange"; "onSelect": "onSelect"; }, ["_allItems"], never, true, never>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// @public +export class MenuContent { + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class MenuItem { + constructor(); + readonly active: _angular_core.Signal; + close(): void; + readonly disabled: _angular_core.InputSignal; + readonly element: HTMLElement; + readonly expanded: _angular_core.Signal; + readonly hasPopup: _angular_core.Signal; + readonly id: _angular_core.InputSignal; + open(): void; + readonly parent: Menu | MenuBar | null; + readonly _pattern: MenuItemPattern; + readonly searchTerm: _angular_core.ModelSignal; + readonly submenu: _angular_core.InputSignal | undefined>; + readonly value: _angular_core.InputSignal; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngMenuItem]", ["ngMenuItem"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "searchTerm": { "alias": "searchTerm"; "required": false; "isSignal": true; }; "submenu": { "alias": "submenu"; "required": false; "isSignal": true; }; }, { "searchTerm": "searchTermChange"; }, never, never, true, never>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// @public +export class MenuTrigger { + constructor(); + close(): void; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly expanded: _angular_core.Signal; + readonly hasPopup: _angular_core.Signal; + menu: _angular_core.InputSignal | undefined>; + open(): void; + _pattern: MenuTriggerPattern; + readonly softDisabled: _angular_core.InputSignalWithTransform; + readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "button[ngMenuTrigger]", ["ngMenuTrigger"], { "menu": { "alias": "menu"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "softDisabled": { "alias": "softDisabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/aria/private/index.api.md b/goldens/aria/private/index.api.md new file mode 100644 index 000000000000..c8ca83c0d9a1 --- /dev/null +++ b/goldens/aria/private/index.api.md @@ -0,0 +1,945 @@ +## API Report File for "@angular/aria_private" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as _angular_core from '@angular/core'; +import { OnDestroy } from '@angular/core'; +import { untracked } from '@angular/core/primitives/signals'; + +// @public +export interface AccordionGroupInputs extends Omit & ListFocusInputs & Omit, 'focusMode'> { + getItem: (e: Element | null | undefined) => AccordionTriggerPattern | undefined; +} + +// @public +export class AccordionGroupPattern { + constructor(inputs: AccordionGroupInputs); + readonly expansionBehavior: ListExpansion; + readonly focusBehavior: ListFocus; + // (undocumented) + readonly inputs: AccordionGroupInputs; + keydown: SignalLike>; + readonly navigationBehavior: ListNavigation; + nextKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">; + onFocus(event: FocusEvent): void; + onKeydown(event: KeyboardEvent): void; + onPointerdown(event: PointerEvent): void; + pointerdown: SignalLike>; + prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; + toggle(): void; +} + +// @public +export interface AccordionPanelInputs { + accordionTrigger: SignalLike; + id: SignalLike; + panelId: SignalLike; +} + +// @public +export class AccordionPanelPattern { + constructor(inputs: AccordionPanelInputs); + accordionTrigger: SignalLike; + hidden: SignalLike; + id: SignalLike; + // (undocumented) + readonly inputs: AccordionPanelInputs; +} + +// @public +export interface AccordionTriggerInputs extends Omit, Omit { + accordionGroup: SignalLike; + accordionPanel: SignalLike; + panelId: SignalLike; +} + +// @public +export class AccordionTriggerPattern implements ListNavigationItem, ListFocusItem, ExpansionItem { + constructor(inputs: AccordionTriggerInputs); + readonly active: SignalLike; + close(): void; + readonly controls: SignalLike; + readonly disabled: SignalLike; + readonly element: SignalLike; + readonly expandable: SignalLike; + readonly expanded: WritableSignalLike; + readonly hardDisabled: SignalLike; + readonly id: SignalLike; + readonly index: SignalLike; + // (undocumented) + readonly inputs: AccordionTriggerInputs; + open(): void; + readonly tabIndex: SignalLike<-1 | 0>; + toggle(): void; +} + +// @public (undocumented) +export class ComboboxDialogPattern { + constructor(inputs: { + combobox: ComboboxPattern; + element: SignalLike; + id: SignalLike; + }); + // (undocumented) + id: () => string; + // (undocumented) + readonly inputs: { + combobox: ComboboxPattern; + element: SignalLike; + id: SignalLike; + }; + // (undocumented) + keydown: SignalLike>; + // (undocumented) + onClick(event: MouseEvent): void; + // (undocumented) + onKeydown(event: KeyboardEvent): void; + // (undocumented) + role: () => "dialog"; +} + +// @public +export interface ComboboxInputs, V> { + alwaysExpanded: SignalLike; + containerEl: SignalLike; + disabled: SignalLike; + filterMode: SignalLike<'manual' | 'auto-select' | 'highlight'>; + firstMatch: SignalLike; + inputEl: SignalLike; + inputValue?: WritableSignalLike; + popupControls: SignalLike | ComboboxTreeControls | ComboboxDialogPattern | undefined>; + readonly: SignalLike; + textDirection: SignalLike<'rtl' | 'ltr'>; +} + +// @public +export interface ComboboxListboxControls, V> { + activeId: SignalLike; + clearSelection: () => void; + first: () => void; + focus: (item: T, opts?: { + focusElement?: boolean; + }) => void; + getActiveItem: () => T | undefined; + getItem: (e: PointerEvent) => T | undefined; + getSelectedItems: () => T[]; + id: () => string; + items: SignalLike; + last: () => void; + multi: SignalLike; + next: () => void; + prev: () => void; + role: SignalLike<'listbox' | 'tree' | 'grid'>; + select: (item?: T) => void; + setValue: (value: V | undefined) => void; + toggle: (item?: T) => void; + unfocus: () => void; +} + +// @public (undocumented) +export type ComboboxListboxInputs = ListboxInputs & { + combobox: SignalLike, V> | undefined>; +}; + +// @public (undocumented) +export class ComboboxListboxPattern extends ListboxPattern implements ComboboxListboxControls, V> { + constructor(inputs: ComboboxListboxInputs); + activeId: SignalLike; + clearSelection: () => void; + first: () => void; + focus: (item: OptionPattern, opts?: { + focusElement?: boolean; + }) => void; + getActiveItem: () => OptionPattern | undefined; + getItem: (e: PointerEvent) => OptionPattern | undefined; + getSelectedItems: () => OptionPattern[]; + id: SignalLike; + // (undocumented) + readonly inputs: ComboboxListboxInputs; + items: SignalLike[]>; + last: () => void; + multi: SignalLike; + next: () => void; + onKeydown(_: KeyboardEvent): void; + onPointerdown(_: PointerEvent): void; + prev: () => void; + role: SignalLike<"listbox">; + select: (item?: OptionPattern) => void; + setDefaultState(): void; + setValue: (value: V | undefined) => void; + tabIndex: SignalLike<-1 | 0>; + toggle: (item?: OptionPattern) => void; + unfocus: () => void; +} + +// @public +export class ComboboxPattern, V> { + constructor(inputs: ComboboxInputs); + activeDescendant: SignalLike; + autocomplete: SignalLike<"both" | "list">; + click: SignalLike>; + close(opts?: { + reset: boolean; + }): void; + collapseItem(): void; + collapseKey: SignalLike<"ArrowLeft" | "ArrowRight">; + commit(): void; + disabled: () => boolean; + expanded: WritableSignalLike; + expandItem(): void; + expandKey: SignalLike<"ArrowLeft" | "ArrowRight">; + first(): void; + firstMatch: SignalLike; + hasBeenFocused: WritableSignalLike; + hasPopup: SignalLike<"listbox" | "tree" | "grid" | "dialog" | null>; + highlight(): void; + highlightedItem: WritableSignalLike; + // (undocumented) + readonly inputs: ComboboxInputs; + isDeleting: boolean; + isFocused: WritableSignalLike; + keydown: SignalLike>; + last(): void; + listControls: () => ComboboxListboxControls | null | undefined; + next(): void; + onClick(event: MouseEvent): void; + onFilter(): void; + onFocusIn(): void; + onFocusOut(event: FocusEvent): void; + onInput(event: Event): void; + onKeydown(event: KeyboardEvent): void; + open(nav?: { + first?: boolean; + last?: boolean; + selected?: boolean; + }): void; + popupId: SignalLike; + prev(): void; + readonly: SignalLike; + select(opts?: { + item?: T; + commit?: boolean; + close?: boolean; + }): void; + treeControls: () => ComboboxTreeControls | null; +} + +// @public (undocumented) +export interface ComboboxTreeControls, V> extends ComboboxListboxControls { + collapseAll: () => void; + collapseItem: () => void; + expandAll: () => void; + expandItem: () => void; + isItemCollapsible: () => boolean; + isItemExpandable: (item?: T) => boolean; + isItemSelectable: (item?: T) => boolean; + toggleExpansion: (item?: T) => void; +} + +// @public (undocumented) +export type ComboboxTreeInputs = TreeInputs & { + combobox: SignalLike, V> | undefined>; +}; + +// @public (undocumented) +export class ComboboxTreePattern extends TreePattern implements ComboboxTreeControls, V> { + constructor(inputs: ComboboxTreeInputs); + // (undocumented) + activeId: SignalLike; + clearSelection: () => void; + collapseAll: () => void; + collapseItem: () => void; + expandAll: () => void; + expandItem: () => void; + first: () => void; + focus: (item: TreeItemPattern) => void; + getActiveItem: () => TreeItemPattern | undefined; + getItem: (e: PointerEvent) => TreeItemPattern | undefined; + getSelectedItems: () => TreeItemPattern[]; + // (undocumented) + readonly inputs: ComboboxTreeInputs; + isItemCollapsible: () => boolean; + isItemExpandable(item?: TreeItemPattern | undefined): boolean; + isItemSelectable: (item?: TreeItemPattern | undefined) => boolean; + items: SignalLike[]>; + last: () => void; + next: () => void; + onKeydown(_: KeyboardEvent): void; + onPointerdown(_: PointerEvent): void; + prev: () => void; + role: () => "tree"; + select: (item?: TreeItemPattern) => void; + setDefaultState(): void; + setValue: (value: V | undefined) => void; + tabIndex: SignalLike<-1 | 0>; + toggle: (item?: TreeItemPattern) => void; + unfocus: () => void; +} + +// @public (undocumented) +export function computed(computation: () => T): SignalLike; + +// @public +export function convertGetterSetterToWritableSignalLike(getter: () => T, setter: (v: T) => void): WritableSignalLike; + +// @public +export class DeferredContent implements OnDestroy { + constructor(); + // (undocumented) + readonly deferredContentAware: _angular_core.WritableSignal; + // (undocumented) + ngOnDestroy(): void; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class DeferredContentAware { + // (undocumented) + readonly contentVisible: _angular_core.WritableSignal; + // (undocumented) + readonly preserveContent: _angular_core.ModelSignal; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export interface GridCellInputs extends GridCell, Omit, 'focusMode' | 'items' | 'activeItem' | 'softDisabled' | 'element'> { + colIndex: SignalLike; + getWidget: (e: Element | null) => GridCellWidgetPattern | undefined; + grid: SignalLike; + row: SignalLike; + rowIndex: SignalLike; + widgets: SignalLike; +} + +// @public +export class GridCellPattern implements GridCell { + constructor(inputs: GridCellInputs); + readonly active: SignalLike; + readonly activeWidget: WritableSignalLike; + readonly anchor: SignalLike; + readonly ariaColIndex: SignalLike; + readonly ariaRowIndex: SignalLike; + readonly ariaSelected: SignalLike; + readonly colSpan: SignalLike; + readonly disabled: SignalLike; + readonly element: SignalLike; + focus(): void; + readonly focusBehavior: ListFocus; + readonly id: SignalLike; + // (undocumented) + readonly inputs: GridCellInputs; + readonly isActivated: SignalLike; + readonly isFocused: WritableSignalLike; + readonly keydown: SignalLike>; + readonly multiWidgetMode: SignalLike; + readonly navigationActivated: WritableSignalLike; + readonly navigationBehavior: ListNavigation; + readonly navigationDisabled: SignalLike; + readonly nextKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">; + onFocusIn(event: FocusEvent): void; + onFocusOut(event: FocusEvent): void; + onKeydown(event: KeyboardEvent): void; + readonly prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; + readonly rowSpan: SignalLike; + readonly selectable: SignalLike; + readonly selected: WritableSignalLike; + readonly singleWidgetMode: SignalLike; + startNavigation(): void; + stopNavigation(): void; + readonly tabIndex: SignalLike<-1 | 0>; + readonly widgetActivated: SignalLike; + widgetTabIndex(): -1 | 0; +} + +// @public +export interface GridCellWidgetInputs extends Omit { + cell: SignalLike; + element: SignalLike; + focusTarget: SignalLike; + widgetType: SignalLike<'simple' | 'complex' | 'editable'>; +} + +// @public +export class GridCellWidgetPattern implements ListNavigationItem { + constructor(inputs: GridCellWidgetInputs); + activate(event?: KeyboardEvent | FocusEvent): void; + readonly active: SignalLike; + deactivate(event?: KeyboardEvent | FocusEvent): void; + readonly disabled: SignalLike; + readonly element: SignalLike; + focus(): void; + readonly id: SignalLike; + readonly index: SignalLike; + // (undocumented) + readonly inputs: GridCellWidgetInputs; + readonly isActivated: WritableSignalLike; + readonly keydown: SignalLike>; + readonly lastActivateEvent: WritableSignalLike; + readonly lastDeactivateEvent: WritableSignalLike; + onFocusIn(event: FocusEvent): void; + onFocusOut(event: FocusEvent): void; + onKeydown(event: KeyboardEvent): void; + readonly tabIndex: SignalLike<-1 | 0>; + readonly widgetHost: SignalLike; +} + +// @public +export interface GridInputs extends Omit, 'cells'> { + element: SignalLike; + enableRangeSelection: SignalLike; + enableSelection: SignalLike; + getCell: (e: Element | null) => GridCellPattern | undefined; + multi: SignalLike; + rows: SignalLike; + selectionMode: SignalLike<'follow' | 'explicit'>; + textDirection: SignalLike<'rtl' | 'ltr'>; +} + +// @public +export class GridPattern { + constructor(inputs: GridInputs); + readonly activeCell: SignalLike; + readonly activeDescendant: SignalLike; + readonly anchorCell: SignalLike; + readonly cells: SignalLike; + readonly disabled: SignalLike; + readonly dragging: WritableSignalLike; + focusEffect(): void; + readonly gridBehavior: Grid; + readonly hasBeenFocused: WritableSignalLike; + // (undocumented) + readonly inputs: GridInputs; + readonly isFocused: WritableSignalLike; + readonly keydown: SignalLike>; + readonly nextColKey: SignalLike<"ArrowRight" | "ArrowLeft">; + onFocusIn(event: FocusEvent): void; + onFocusOut(event: FocusEvent): void; + onKeydown(event: KeyboardEvent): void; + onPointerdown(event: PointerEvent): void; + onPointermove(event: PointerEvent): void; + onPointerup(event: PointerEvent): void; + readonly pauseNavigation: SignalLike; + readonly pointerdown: SignalLike>; + readonly pointerup: SignalLike>; + readonly prevColKey: SignalLike<"ArrowRight" | "ArrowLeft">; + resetFocusEffect(): void; + resetStateEffect(): void; + restoreFocusEffect(): void; + setDefaultStateEffect(): void; + readonly tabIndex: SignalLike<0 | -1>; +} + +// @public +export interface GridRowInputs { + cells: SignalLike; + grid: SignalLike; + rowIndex: SignalLike; +} + +// @public +export class GridRowPattern { + constructor(inputs: GridRowInputs); + // (undocumented) + readonly inputs: GridRowInputs; + rowIndex: SignalLike; +} + +// @public (undocumented) +export function linkedSignal(sourceFn: () => T): WritableSignalLike; + +// @public +export type ListboxInputs = ListInputs, V> & { + id: SignalLike; + readonly: SignalLike; +}; + +// @public +export class ListboxPattern { + constructor(inputs: ListboxInputs); + activeDescendant: SignalLike; + disabled: SignalLike; + dynamicSpaceKey: SignalLike<"" | " ">; + followFocus: SignalLike; + // (undocumented) + protected _getItem(e: PointerEvent): OptionPattern | undefined; + // (undocumented) + readonly inputs: ListboxInputs; + keydown: SignalLike>; + // (undocumented) + listBehavior: List, V>; + multi: SignalLike; + nextKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">; + onKeydown(event: KeyboardEvent): void; + // (undocumented) + onPointerdown(event: PointerEvent): void; + orientation: SignalLike<'vertical' | 'horizontal'>; + pointerdown: SignalLike>; + prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; + readonly: SignalLike; + setDefaultState(): void; + setsize: SignalLike; + tabIndex: SignalLike<-1 | 0>; + typeaheadRegexp: RegExp; + validate(): string[]; + wrap: WritableSignalLike; +} + +// @public +export interface MenuBarInputs extends ListInputs, V> { + items: SignalLike[]>; + onSelect?: (value: V) => void; + textDirection: SignalLike<'ltr' | 'rtl'>; +} + +// @public +export class MenuBarPattern { + constructor(inputs: MenuBarInputs); + close(): void; + disabled: () => boolean; + dynamicSpaceKey: SignalLike<"" | " ">; + goto(item: MenuItemPattern, opts?: { + focusElement?: boolean; + }): void; + hasBeenFocused: WritableSignalLike; + // (undocumented) + readonly inputs: MenuBarInputs; + isFocused: WritableSignalLike; + keydownManager: SignalLike>; + listBehavior: List, V>; + next(): void; + onClick(event: MouseEvent): void; + onFocusIn(): void; + onFocusOut(event: FocusEvent): void; + onKeydown(event: KeyboardEvent): void; + onMouseOver(event: MouseEvent): void; + prev(): void; + setDefaultState(): void; + tabIndex: () => 0 | -1; + typeaheadRegexp: RegExp; +} + +// @public +export interface MenuInputs extends Omit, V>, 'values'> { + expansionDelay: SignalLike; + id: SignalLike; + items: SignalLike[]>; + onSelect?: (value: V) => void; + parent: SignalLike | MenuItemPattern | undefined>; + textDirection: SignalLike<'ltr' | 'rtl'>; +} + +// @public +export interface MenuItemInputs extends Omit, 'index' | 'selectable'> { + parent: SignalLike | MenuBarPattern | undefined>; + submenu: SignalLike | undefined>; +} + +// @public +export class MenuItemPattern implements ListItem { + constructor(inputs: MenuItemInputs); + active: SignalLike; + close(opts?: { + refocus?: boolean; + }): void; + controls: WritableSignalLike; + disabled: () => boolean; + element: SignalLike; + expanded: SignalLike; + _expanded: WritableSignalLike; + hasBeenFocused: WritableSignalLike; + hasPopup: SignalLike; + id: SignalLike; + index: SignalLike; + // (undocumented) + readonly inputs: MenuItemInputs; + onFocusIn(): void; + open(opts?: { + first?: boolean; + last?: boolean; + }): void; + role: () => string; + searchTerm: SignalLike; + selectable: SignalLike; + submenu: SignalLike | undefined>; + tabIndex: SignalLike<0 | -1>; + value: SignalLike; +} + +// @public +export class MenuPattern { + constructor(inputs: MenuInputs); + _clearCloseTimeout(): void; + _clearOpenTimeout(): void; + _clearTimeouts(): void; + close(): void; + closeAll(): void; + _closeTimeout: any; + collapse(): void; + disabled: () => boolean; + dynamicSpaceKey: SignalLike<"" | " ">; + expand(): void; + first(): void; + hasBeenFocused: WritableSignalLike; + hasBeenHovered: WritableSignalLike; + id: SignalLike; + // (undocumented) + readonly inputs: MenuInputs; + isFocused: WritableSignalLike; + keydownManager: SignalLike>; + last(): void; + listBehavior: List, V>; + next(): void; + onClick(event: MouseEvent): void; + onFocusIn(): void; + onFocusOut(event: FocusEvent): void; + onKeydown(event: KeyboardEvent): void; + onMouseOut(event: MouseEvent): void; + onMouseOver(event: MouseEvent): void; + _openTimeout: any; + prev(): void; + role: () => string; + root: SignalLike | MenuBarPattern | MenuPattern | undefined>; + setDefaultState(): void; + shouldFocus: SignalLike; + submit(item?: MenuItemPattern | undefined): void; + tabIndex: () => 0 | -1; + trigger(): void; + typeaheadRegexp: RegExp; + visible: SignalLike; +} + +// @public +export interface MenuTriggerInputs { + disabled: SignalLike; + element: SignalLike; + menu: SignalLike | undefined>; + textDirection: SignalLike<'ltr' | 'rtl'>; +} + +// @public +export class MenuTriggerPattern { + constructor(inputs: MenuTriggerInputs); + close(opts?: { + refocus?: boolean; + }): void; + disabled: () => boolean; + expanded: WritableSignalLike; + hasBeenFocused: WritableSignalLike; + hasPopup: () => boolean; + // (undocumented) + readonly inputs: MenuTriggerInputs; + keydownManager: SignalLike>; + menu: SignalLike | undefined>; + onClick(): void; + onFocusIn(): void; + onFocusOut(event: FocusEvent): void; + onKeydown(event: KeyboardEvent): void; + open(opts?: { + first?: boolean; + last?: boolean; + }): void; + role: () => string; + tabIndex: SignalLike<-1 | 0>; +} + +// @public +export interface OptionInputs extends Omit, 'index' | 'selectable'> { + // (undocumented) + listbox: SignalLike | undefined>; +} + +// @public +export class OptionPattern { + constructor(args: OptionInputs); + active: SignalLike; + disabled: SignalLike; + element: SignalLike; + id: SignalLike; + index: SignalLike; + listbox: SignalLike | undefined>; + searchTerm: SignalLike; + selectable: () => boolean; + selected: SignalLike; + tabIndex: SignalLike<0 | -1 | undefined>; + value: SignalLike; +} + +// @public (undocumented) +export function signal(initialValue: T): WritableSignalLike; + +// @public (undocumented) +export type SignalLike = () => T; + +// @public +export interface TabInputs extends Omit, Omit { + tablist: SignalLike; + tabpanel: SignalLike; + value: SignalLike; +} + +// @public +export interface TabListInputs extends Omit, 'multi'>, Omit { + selectionMode: SignalLike<'follow' | 'explicit'>; +} + +// @public +export class TabListPattern { + constructor(inputs: TabListInputs); + readonly activeDescendant: SignalLike; + readonly activeTab: SignalLike; + readonly disabled: SignalLike; + readonly expansionBehavior: ListExpansion; + readonly focusBehavior: ListFocus; + readonly followFocus: SignalLike; + // (undocumented) + readonly inputs: TabListInputs; + readonly keydown: SignalLike>; + readonly navigationBehavior: ListNavigation; + readonly nextKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">; + onKeydown(event: KeyboardEvent): void; + onPointerdown(event: PointerEvent): void; + open(value: string): boolean; + open(tab?: TabPattern): boolean; + readonly orientation: SignalLike<'vertical' | 'horizontal'>; + readonly pointerdown: SignalLike>; + readonly prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; + readonly selectedTab: WritableSignalLike; + setDefaultState(): void; + readonly tabIndex: SignalLike<0 | -1>; +} + +// @public +export interface TabPanelInputs extends LabelControlOptionalInputs { + id: SignalLike; + tab: SignalLike; + value: SignalLike; +} + +// @public +export class TabPanelPattern { + constructor(inputs: TabPanelInputs); + readonly hidden: SignalLike; + readonly id: SignalLike; + // (undocumented) + readonly inputs: TabPanelInputs; + readonly labelledBy: SignalLike; + readonly labelManager: LabelControl; + readonly tabIndex: SignalLike<-1 | 0>; + readonly value: SignalLike; +} + +// @public +export class TabPattern { + constructor(inputs: TabInputs); + readonly active: SignalLike; + readonly controls: SignalLike; + readonly disabled: SignalLike; + readonly element: SignalLike; + readonly expandable: SignalLike; + readonly expanded: WritableSignalLike; + readonly id: SignalLike; + readonly index: SignalLike; + // (undocumented) + readonly inputs: TabInputs; + open(): boolean; + readonly selected: SignalLike; + readonly tabIndex: SignalLike<0 | -1>; + readonly value: SignalLike; +} + +// @public +export type ToolbarInputs = Omit, V>, 'multi' | 'typeaheadDelay' | 'selectionMode' | 'focusMode'> & { + getItem: (e: Element) => ToolbarWidgetPattern | undefined; +}; + +// @public +export class ToolbarPattern { + constructor(inputs: ToolbarInputs); + readonly activeDescendant: SignalLike; + readonly activeItem: () => ToolbarWidgetPattern | undefined; + readonly disabled: SignalLike; + // (undocumented) + readonly inputs: ToolbarInputs; + readonly listBehavior: List, V>; + onClick(event: MouseEvent): void; + onKeydown(event: KeyboardEvent): void; + // (undocumented) + onPointerdown(event: PointerEvent): void; + readonly orientation: SignalLike<'vertical' | 'horizontal'>; + // (undocumented) + select(): void; + setDefaultState(): void; + readonly softDisabled: SignalLike; + readonly tabIndex: SignalLike<0 | -1>; + validate(): string[]; +} + +// @public +export interface ToolbarWidgetGroupInputs, V> { + disabled: SignalLike; + items: SignalLike; + multi: SignalLike; + toolbar: SignalLike | undefined>; +} + +// @public +export class ToolbarWidgetGroupPattern, V> { + constructor(inputs: ToolbarWidgetGroupInputs); + readonly disabled: () => boolean; + // (undocumented) + readonly element: () => undefined; + // (undocumented) + readonly inputs: ToolbarWidgetGroupInputs; + readonly multi: () => boolean; + // (undocumented) + readonly searchTerm: () => string; + // (undocumented) + readonly selectable: () => boolean; + readonly toolbar: () => ToolbarPattern | undefined; + // (undocumented) + readonly value: () => V; +} + +// @public +export interface ToolbarWidgetInputs extends Omit, 'searchTerm' | 'index' | 'selectable'> { + group: SignalLike, V> | undefined>; + toolbar: SignalLike>; +} + +// @public (undocumented) +export class ToolbarWidgetPattern implements ListItem { + constructor(inputs: ToolbarWidgetInputs); + readonly active: SignalLike; + readonly disabled: () => boolean; + readonly element: () => HTMLElement | undefined; + readonly group: () => ToolbarWidgetGroupPattern, V> | undefined; + readonly id: () => string; + readonly index: SignalLike; + // (undocumented) + readonly inputs: ToolbarWidgetInputs; + readonly searchTerm: () => string; + readonly selectable: () => boolean; + readonly selected: SignalLike; + readonly tabIndex: SignalLike<0 | -1>; + readonly toolbar: () => ToolbarPattern; + readonly value: () => V; +} + +// @public +export interface TreeInputs extends Omit, V>, 'items'> { + allItems: SignalLike[]>; + currentType: SignalLike<'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'>; + id: SignalLike; + nav: SignalLike; +} + +// @public +export interface TreeItemInputs extends Omit, 'index'>, Omit { + children: SignalLike[]>; + hasChildren: SignalLike; + parent: SignalLike | TreePattern>; + tree: SignalLike>; +} + +// @public +export class TreeItemPattern implements ListItem, ExpansionItem { + constructor(inputs: TreeItemInputs); + readonly active: SignalLike; + readonly children: SignalLike[]>; + readonly current: SignalLike; + readonly disabled: SignalLike; + readonly element: SignalLike; + readonly expandable: SignalLike; + readonly expanded: WritableSignalLike; + readonly expansionBehavior: ListExpansion; + readonly id: SignalLike; + readonly index: SignalLike; + // (undocumented) + readonly inputs: TreeItemInputs; + readonly level: SignalLike; + readonly parent: SignalLike | TreePattern>; + readonly posinset: SignalLike; + readonly searchTerm: SignalLike; + readonly selectable: SignalLike; + readonly selected: SignalLike; + readonly setsize: SignalLike; + readonly tabIndex: SignalLike<0 | -1>; + readonly tree: SignalLike>; + readonly value: SignalLike; + readonly visible: SignalLike; +} + +// @public +export class TreePattern implements TreeInputs { + constructor(inputs: TreeInputs); + readonly activeDescendant: SignalLike; + readonly activeItem: WritableSignalLike | undefined>; + readonly allItems: SignalLike[]>; + readonly children: SignalLike[]>; + collapse(opts?: SelectOptions): void; + readonly collapseKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; + readonly currentType: SignalLike<'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'>; + readonly disabled: SignalLike; + readonly dynamicSpaceKey: SignalLike<"" | " ">; + readonly element: SignalLike; + expand(opts?: SelectOptions): void; + readonly expanded: () => boolean; + readonly expandKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">; + expandSiblings(item?: TreeItemPattern): void; + readonly expansionBehavior: ListExpansion; + readonly focusMode: SignalLike<'roving' | 'activedescendant'>; + readonly followFocus: SignalLike; + protected _getItem(event: Event): TreeItemPattern | undefined; + goto(e: PointerEvent, opts?: SelectOptions): void; + readonly id: SignalLike; + // (undocumented) + readonly inputs: TreeInputs; + readonly isRtl: SignalLike; + readonly keydown: SignalLike>; + readonly level: () => number; + readonly listBehavior: List, V>; + readonly multi: SignalLike; + readonly nav: SignalLike; + readonly nextKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">; + onKeydown(event: KeyboardEvent): void; + onPointerdown(event: PointerEvent): void; + readonly orientation: SignalLike<'vertical' | 'horizontal'>; + pointerdown: SignalLike>; + readonly prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; + readonly selectionMode: SignalLike<'follow' | 'explicit'>; + setDefaultState(): void; + readonly softDisabled: SignalLike; + readonly tabIndex: SignalLike<-1 | 0>; + readonly textDirection: SignalLike<'ltr' | 'rtl'>; + toggleExpansion(item?: TreeItemPattern): void; + readonly typeaheadDelay: SignalLike; + readonly typeaheadRegexp: RegExp; + readonly values: WritableSignalLike; + readonly visible: () => boolean; + readonly visibleItems: SignalLike[]>; + readonly wrap: SignalLike; +} + +export { untracked } + +// @public (undocumented) +export interface WritableSignalLike extends SignalLike { + // (undocumented) + asReadonly(): SignalLike; + // (undocumented) + set(value: T): void; + // (undocumented) + update(updateFn: (value: T) => T): void; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/aria/tabs/index.api.md b/goldens/aria/tabs/index.api.md new file mode 100644 index 000000000000..835892dd6851 --- /dev/null +++ b/goldens/aria/tabs/index.api.md @@ -0,0 +1,108 @@ +## API Report File for "@angular/aria_tabs" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as _angular_aria_private from '@angular/aria/private'; +import * as _angular_aria_private_public_api from '@angular/aria/private/public-api'; +import * as _angular_cdk_bidi from '@angular/cdk/bidi'; +import * as _angular_core from '@angular/core'; +import { OnDestroy } from '@angular/core'; +import { OnInit } from '@angular/core'; + +// @public +export class Tab implements HasElement, OnInit, OnDestroy { + readonly active: _angular_core.Signal; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly id: _angular_core.InputSignal; + // (undocumented) + ngOnDestroy(): void; + // (undocumented) + ngOnInit(): void; + open(): void; + readonly _pattern: TabPattern; + readonly selected: _angular_core.Signal; + readonly value: _angular_core.InputSignal; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class TabContent { + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class TabList implements OnInit, OnDestroy { + constructor(); + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly focusMode: _angular_core.InputSignal<"roving" | "activedescendant">; + // (undocumented) + ngOnDestroy(): void; + // (undocumented) + ngOnInit(): void; + // (undocumented) + _onFocus(): void; + open(value: string): boolean; + readonly orientation: _angular_core.InputSignal<"vertical" | "horizontal">; + readonly _pattern: TabListPattern; + // (undocumented) + _register(child: Tab): void; + readonly selectedTab: _angular_core.ModelSignal; + readonly selectionMode: _angular_core.InputSignal<"follow" | "explicit">; + readonly softDisabled: _angular_core.InputSignalWithTransform; + readonly _tabPatterns: _angular_core.Signal<_angular_aria_private_public_api.TabPattern[]>; + readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; + // (undocumented) + _unregister(child: Tab): void; + readonly wrap: _angular_core.InputSignalWithTransform; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class TabPanel implements OnInit, OnDestroy { + constructor(); + readonly element: HTMLElement; + readonly id: _angular_core.InputSignal; + // (undocumented) + ngOnDestroy(): void; + // (undocumented) + ngOnInit(): void; + readonly _pattern: TabPanelPattern; + readonly value: _angular_core.InputSignal; + readonly visible: _angular_core.Signal; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// @public +export class Tabs { + readonly element: HTMLElement; + // (undocumented) + _register(child: TabList | TabPanel): void; + readonly _tabPatterns: _angular_core.Signal<_angular_aria_private.TabPattern[] | undefined>; + readonly _unorderedTabpanelPatterns: _angular_core.Signal<_angular_aria_private.TabPanelPattern[]>; + // (undocumented) + _unregister(child: TabList | TabPanel): void; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/aria/toolbar/index.api.md b/goldens/aria/toolbar/index.api.md new file mode 100644 index 000000000000..2b5f29031e43 --- /dev/null +++ b/goldens/aria/toolbar/index.api.md @@ -0,0 +1,73 @@ +## API Report File for "@angular/aria_toolbar" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as _angular_aria_private_public_api from '@angular/aria/private/public-api'; +import * as _angular_cdk_bidi from '@angular/cdk/bidi'; +import * as _angular_core from '@angular/core'; +import { OnDestroy } from '@angular/core'; +import { OnInit } from '@angular/core'; + +// @public +export class Toolbar { + constructor(); + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly _itemPatterns: _angular_core.Signal<_angular_aria_private_public_api.ToolbarWidgetPattern[]>; + // (undocumented) + _onFocus(): void; + readonly orientation: _angular_core.InputSignal<"vertical" | "horizontal">; + readonly _pattern: ToolbarPattern; + // (undocumented) + _register(widget: ToolbarWidget): void; + softDisabled: _angular_core.InputSignalWithTransform; + readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; + // (undocumented) + _unregister(widget: ToolbarWidget): void; + readonly values: _angular_core.ModelSignal; + readonly wrap: _angular_core.InputSignalWithTransform; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngToolbar]", ["ngToolbar"], { "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "softDisabled": { "alias": "softDisabled"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "values": { "alias": "values"; "required": false; "isSignal": true; }; }, { "values": "valuesChange"; }, never, never, true, never>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// @public +export class ToolbarWidget implements OnInit, OnDestroy { + readonly active: _angular_core.Signal; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly _group: ToolbarWidgetGroup | null; + readonly hardDisabled: _angular_core.Signal; + readonly id: _angular_core.InputSignal; + // (undocumented) + ngOnDestroy(): void; + // (undocumented) + ngOnInit(): void; + readonly _pattern: ToolbarWidgetPattern; + readonly selected: () => boolean; + readonly _toolbarPattern: _angular_core.Signal<_angular_aria_private_public_api.ToolbarPattern>; + readonly value: _angular_core.InputSignal; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngToolbarWidget]", ["ngToolbarWidget"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// @public +export class ToolbarWidgetGroup { + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly multi: _angular_core.InputSignalWithTransform; + readonly _pattern: ToolbarWidgetGroupPattern, V>; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngToolbarWidgetGroup]", ["ngToolbarWidgetGroup"], { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "multi": { "alias": "multi"; "required": false; "isSignal": true; }; }, {}, ["_widgets"], never, true, never>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/aria/tree/index.api.md b/goldens/aria/tree/index.api.md new file mode 100644 index 000000000000..e796fe0102d4 --- /dev/null +++ b/goldens/aria/tree/index.api.md @@ -0,0 +1,99 @@ +## API Report File for "@angular/aria_tree" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import * as _angular_cdk_bidi from '@angular/cdk/bidi'; +import * as _angular_core from '@angular/core'; +import { OnDestroy } from '@angular/core'; +import { OnInit } from '@angular/core'; +import { Signal } from '@angular/core'; + +// @public +export class Tree { + constructor(); + readonly currentType: _angular_core.InputSignal<"page" | "step" | "location" | "date" | "time" | "true" | "false">; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly focusMode: _angular_core.InputSignal<"roving" | "activedescendant">; + readonly id: _angular_core.InputSignal; + readonly multi: _angular_core.InputSignalWithTransform; + readonly nav: _angular_core.InputSignalWithTransform; + // (undocumented) + _onFocus(): void; + readonly orientation: _angular_core.InputSignal<"vertical" | "horizontal">; + readonly _pattern: TreePattern; + // (undocumented) + _register(child: TreeItem): void; + // (undocumented) + scrollActiveItemIntoView(options?: ScrollIntoViewOptions): void; + readonly selectionMode: _angular_core.InputSignal<"follow" | "explicit">; + readonly softDisabled: _angular_core.InputSignalWithTransform; + readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; + readonly typeaheadDelay: _angular_core.InputSignal; + // (undocumented) + _unregister(child: TreeItem): void; + readonly values: _angular_core.ModelSignal; + readonly wrap: _angular_core.InputSignalWithTransform; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngTree]", ["ngTree"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "multi": { "alias": "multi"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "selectionMode": { "alias": "selectionMode"; "required": false; "isSignal": true; }; "focusMode": { "alias": "focusMode"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "softDisabled": { "alias": "softDisabled"; "required": false; "isSignal": true; }; "typeaheadDelay": { "alias": "typeaheadDelay"; "required": false; "isSignal": true; }; "values": { "alias": "values"; "required": false; "isSignal": true; }; "nav": { "alias": "nav"; "required": false; "isSignal": true; }; "currentType": { "alias": "currentType"; "required": false; "isSignal": true; }; }, { "values": "valuesChange"; }, never, never, true, [{ directive: typeof ComboboxPopup; inputs: {}; outputs: {}; }]>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// @public +export class TreeItem extends DeferredContentAware implements OnInit, OnDestroy, HasElement { + constructor(); + readonly active: Signal; + readonly disabled: _angular_core.InputSignalWithTransform; + readonly element: HTMLElement; + readonly expanded: _angular_core.ModelSignal; + protected readonly _expanded: Signal; + readonly id: _angular_core.InputSignal; + readonly label: _angular_core.InputSignal; + readonly level: Signal; + // (undocumented) + ngOnDestroy(): void; + // (undocumented) + ngOnInit(): void; + readonly parent: _angular_core.InputSignal | Tree>; + _pattern: TreeItemPattern; + // (undocumented) + _register(group: TreeItemGroup): void; + readonly searchTerm: Signal; + readonly selectable: _angular_core.InputSignal; + readonly selected: Signal; + readonly tree: Signal>; + // (undocumented) + _unregister(): void; + readonly value: _angular_core.InputSignal; + readonly visible: Signal; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngTreeItem]", ["ngTreeItem"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "parent": { "alias": "parent"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "selectable": { "alias": "selectable"; "required": false; "isSignal": true; }; "expanded": { "alias": "expanded"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, { "expanded": "expandedChange"; }, never, never, true, never>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// @public +export class TreeItemGroup implements OnInit, OnDestroy { + readonly _childPatterns: _angular_core.Signal[]>; + readonly element: HTMLElement; + // (undocumented) + ngOnDestroy(): void; + // (undocumented) + ngOnInit(): void; + readonly ownedBy: _angular_core.InputSignal>; + // (undocumented) + _register(child: TreeItem): void; + // (undocumented) + _unregister(child: TreeItem): void; + // (undocumented) + static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "ng-template[ngTreeItemGroup]", ["ngTreeItemGroup"], { "ownedBy": { "alias": "ownedBy"; "required": true; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof DeferredContent; inputs: {}; outputs: {}; }]>; + // (undocumented) + static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/goldens/cdk/a11y/index.api.md b/goldens/cdk/a11y/index.api.md index ea7039d26cd3..0a68560adbda 100644 --- a/goldens/cdk/a11y/index.api.md +++ b/goldens/cdk/a11y/index.api.md @@ -295,7 +295,7 @@ export interface Highlightable extends ListKeyManagerOption { // @public export class _IdGenerator { - getId(prefix: string): string; + getId(prefix: string, randomize?: boolean): string; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration<_IdGenerator, never>; // (undocumented) diff --git a/goldens/cdk/accordion/index.api.md b/goldens/cdk/accordion/index.api.md index bcb6931f8f80..1b1ed1b9af99 100644 --- a/goldens/cdk/accordion/index.api.md +++ b/goldens/cdk/accordion/index.api.md @@ -29,7 +29,9 @@ export class CdkAccordion implements OnDestroy, OnChanges { ngOnDestroy(): void; openAll(): void; readonly _openCloseAllActions: Subject; - readonly _stateChanges: Subject; + readonly _stateChanges: Subject<{ + [propName: string]: i0.SimpleChange; + }>; // (undocumented) static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) diff --git a/goldens/cdk/menu/index.api.md b/goldens/cdk/menu/index.api.md index 27be93023ab9..318e551c75c2 100644 --- a/goldens/cdk/menu/index.api.md +++ b/goldens/cdk/menu/index.api.md @@ -46,7 +46,7 @@ export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestr open(coordinates: ContextMenuCoordinates): void; _openOnContextMenu(event: MouseEvent): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -224,7 +224,7 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD toggle(): void; _toggleOnKeydown(event: KeyboardEvent): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -250,6 +250,7 @@ export abstract class CdkMenuTriggerBase implements OnDestroy { protected overlayRef: OverlayRef | null; registerChildMenu(child: Menu): void; protected readonly stopOutsideClicksListener: rxjs.Observable; + transformOriginSelector: string | null; protected readonly viewContainerRef: ViewContainerRef; // (undocumented) static ɵdir: i0.ɵɵDirectiveDeclaration; diff --git a/goldens/cdk/overlay/index.api.md b/goldens/cdk/overlay/index.api.md index d2537257ed04..5f83c88501c8 100644 --- a/goldens/cdk/overlay/index.api.md +++ b/goldens/cdk/overlay/index.api.md @@ -12,6 +12,7 @@ import { EmbeddedViewRef } from '@angular/core'; import { EnvironmentInjector } from '@angular/core'; import { EventEmitter } from '@angular/core'; import * as i0 from '@angular/core'; +import { InjectionToken } from '@angular/core'; import { Injector } from '@angular/core'; import { Location as Location_2 } from '@angular/common'; import { NgIterable } from '@angular/core'; @@ -37,6 +38,9 @@ export class BlockScrollStrategy implements ScrollStrategy { enable(): void; } +// @public +export const CDK_CONNECTED_OVERLAY_DEFAULT_CONFIG: InjectionToken; + // @public export class CdkConnectedOverlay implements OnDestroy, OnChanges { constructor(...args: unknown[]); @@ -44,17 +48,18 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { attachOverlay(): void; backdropClass: string | string[]; readonly backdropClick: EventEmitter; + set _config(value: string | CdkConnectedOverlayConfig); readonly detach: EventEmitter; detachOverlay(): void; get dir(): Direction; disableClose: boolean; - get disposeOnNavigation(): boolean; - set disposeOnNavigation(value: boolean); + disposeOnNavigation: boolean; flexibleDimensions: boolean; growAfterOpen: boolean; hasBackdrop: boolean; height: number | string; lockPosition: boolean; + matchWidth: boolean; minHeight: number | string; minWidth: number | string; // (undocumented) @@ -68,6 +73,8 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { // (undocumented) static ngAcceptInputType_lockPosition: unknown; // (undocumented) + static ngAcceptInputType_matchWidth: unknown; + // (undocumented) static ngAcceptInputType_push: unknown; // (undocumented) ngOnChanges(changes: SimpleChanges): void; @@ -89,14 +96,65 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { push: boolean; scrollStrategy: ScrollStrategy; transformOriginSelector: string; + usePopover: FlexibleOverlayPopoverLocation | null; viewportMargin: ViewportMargin; width: number | string; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } +// @public +export interface CdkConnectedOverlayConfig { + // (undocumented) + backdropClass?: string | string[]; + // (undocumented) + disableClose?: boolean; + // (undocumented) + disposeOnNavigation?: boolean; + // (undocumented) + flexibleDimensions?: boolean; + // (undocumented) + growAfterOpen?: boolean; + // (undocumented) + hasBackdrop?: boolean; + // (undocumented) + height?: number | string; + // (undocumented) + lockPosition?: boolean; + // (undocumented) + matchWidth?: boolean; + // (undocumented) + minHeight?: number | string; + // (undocumented) + minWidth?: number | string; + // (undocumented) + offsetX?: number; + // (undocumented) + offsetY?: number; + // (undocumented) + origin?: CdkOverlayOrigin | FlexibleConnectedPositionStrategyOrigin; + // (undocumented) + panelClass?: string | string[]; + // (undocumented) + positions?: ConnectedPosition[]; + // (undocumented) + positionStrategy?: FlexibleConnectedPositionStrategy; + // (undocumented) + push?: boolean; + // (undocumented) + scrollStrategy?: ScrollStrategy; + // (undocumented) + transformOriginSelector?: string; + // (undocumented) + usePopover?: FlexibleOverlayPopoverLocation | null; + // (undocumented) + viewportMargin?: ViewportMargin; + // (undocumented) + width?: number | string; +} + // @public export class CdkOverlayOrigin { constructor(...args: unknown[]); @@ -226,6 +284,10 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { // (undocumented) detach(): void; dispose(): void; + getPopoverInsertionPoint(): Element | null | { + type: 'parent'; + element: Element; + }; _origin: FlexibleConnectedPositionStrategyOrigin; positionChanges: Observable; get positions(): ConnectionPositionPair[]; @@ -237,6 +299,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { withFlexibleDimensions(flexibleDimensions?: boolean): this; withGrowAfterOpen(growAfterOpen?: boolean): this; withLockedPosition(isLocked?: boolean): this; + withPopoverLocation(location: FlexibleOverlayPopoverLocation): this; withPositions(positions: ConnectedPosition[]): this; withPush(canPush?: boolean): this; withScrollableContainers(scrollables: CdkScrollable[]): this; @@ -250,6 +313,12 @@ export type FlexibleConnectedPositionStrategyOrigin = ElementRef | Element | (Po height?: number; }); +// @public +export type FlexibleOverlayPopoverLocation = 'global' | 'inline' | { + type: 'parent'; + element: Element; +}; + // @public export class FullscreenOverlayContainer extends OverlayContainer implements OnDestroy { constructor(...args: unknown[]); @@ -315,6 +384,9 @@ export class Overlay { static ɵprov: i0.ɵɵInjectableDeclaration; } +// @public +export const OVERLAY_DEFAULT_CONFIG: InjectionToken; + // @public export class OverlayConfig { constructor(config?: OverlayConfig); @@ -331,6 +403,7 @@ export class OverlayConfig { panelClass?: string | string[]; positionStrategy?: PositionStrategy; scrollStrategy?: ScrollStrategy; + usePopover?: boolean; width?: number | string; } @@ -364,6 +437,12 @@ export class OverlayContainer implements OnDestroy { static ɵprov: i0.ɵɵInjectableDeclaration; } +// @public +export interface OverlayDefaultConfig { + // (undocumented) + usePopover?: boolean; +} + // @public export class OverlayKeyboardDispatcher extends BaseOverlayDispatcher { add(overlayRef: OverlayRef): void; @@ -461,6 +540,10 @@ export interface PositionStrategy { attach(overlayRef: OverlayRef): void; detach?(): void; dispose(): void; + getPopoverInsertionPoint?(): Element | null | { + type: 'parent'; + element: Element; + }; } // @public diff --git a/goldens/cdk/private/index.api.md b/goldens/cdk/private/index.api.md index 5ef9ad638b5c..dbe48ac4374c 100644 --- a/goldens/cdk/private/index.api.md +++ b/goldens/cdk/private/index.api.md @@ -16,6 +16,15 @@ export class _CdkPrivateStyleLoader { static ɵprov: i0.ɵɵInjectableDeclaration<_CdkPrivateStyleLoader>; } +// @public (undocumented) +export interface TrustedHTML { + // (undocumented) + __brand__: 'TrustedHTML'; +} + +// @public +export function trustedHTMLFromString(html: string): TrustedHTML; + // @public export class _VisuallyHiddenLoader { // (undocumented) diff --git a/goldens/material/expansion/index.api.md b/goldens/material/expansion/index.api.md index 65c13c024054..2f7066c0442c 100644 --- a/goldens/material/expansion/index.api.md +++ b/goldens/material/expansion/index.api.md @@ -95,7 +95,9 @@ export class MatExpansionPanel extends CdkAccordionItem implements AfterContentI _headerId: string; get hideToggle(): boolean; set hideToggle(value: boolean); - readonly _inputChanges: Subject; + readonly _inputChanges: Subject<{ + [propName: string]: i0.SimpleChange; + }>; _lazyContent: MatExpansionPanelContent; // (undocumented) static ngAcceptInputType_hideToggle: unknown; diff --git a/goldens/material/menu/testing/index.api.md b/goldens/material/menu/testing/index.api.md index 8cc4d315be89..43e5a2601eea 100644 --- a/goldens/material/menu/testing/index.api.md +++ b/goldens/material/menu/testing/index.api.md @@ -62,6 +62,7 @@ export class MatMenuItemHarness extends ContentContainerComponentHarness // @public export interface MenuHarnessFilters extends BaseHarnessFilters { + triggerIconName?: string | RegExp; triggerText?: string | RegExp; } diff --git a/goldens/material/select/index.api.md b/goldens/material/select/index.api.md index 2f02eff60d41..d0975c05859a 100644 --- a/goldens/material/select/index.api.md +++ b/goldens/material/select/index.api.md @@ -316,7 +316,7 @@ export class MatSelect implements AfterContentInit, OnChanges, OnDestroy, OnInit ngOnInit(): void; _onBlur(): void; _onChange: (value: any) => void; - onContainerClick(): void; + onContainerClick(event: MouseEvent): void; // (undocumented) _onFocus(): void; _onTouched: () => void; diff --git a/goldens/material/stepper/index.api.md b/goldens/material/stepper/index.api.md index ee565c8a8339..76b74b8c8813 100644 --- a/goldens/material/stepper/index.api.md +++ b/goldens/material/stepper/index.api.md @@ -50,14 +50,14 @@ export class MatStep extends CdkStep implements ErrorStateMatcher, AfterContentI } // @public -export class MatStepContent { +export class MatStepContent { constructor(...args: unknown[]); // (undocumented) - _template: TemplateRef; + _template: TemplateRef; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration, "ng-template[matStepContent]", never, {}, {}, never, never, true, never>; // (undocumented) - static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵfac: i0.ɵɵFactoryDeclaration, never>; } // @public (undocumented) diff --git a/goldens/material/table/index.api.md b/goldens/material/table/index.api.md index a019f4778ae0..c391f1b5a0ad 100644 --- a/goldens/material/table/index.api.md +++ b/goldens/material/table/index.api.md @@ -174,7 +174,7 @@ export class MatTable extends CdkTable { } // @public -export class MatTableDataSource extends DataSource { +export class MatTableDataSource extends DataSource { constructor(initialData?: T[]); connect(): BehaviorSubject; get data(): T[]; diff --git a/goldens/material/timepicker/index.api.md b/goldens/material/timepicker/index.api.md index d97326892cd0..4176fd9e10a2 100644 --- a/goldens/material/timepicker/index.api.md +++ b/goldens/material/timepicker/index.api.md @@ -46,6 +46,8 @@ export class MatTimepicker implements OnDestroy, MatOptionParentComponent { readonly disabled: Signal; readonly disableRipple: InputSignalWithTransform; protected _getAriaLabelledby(): string | null; + // (undocumented) + _getOverlayHost(): HTMLElement | undefined; protected _handleAnimationEnd(event: AnimationEvent): void; readonly interval: InputSignalWithTransform; readonly isOpen: Signal; @@ -107,7 +109,7 @@ export class MatTimepickerInput implements MatTimepickerConnectedInput, Co // (undocumented) ngOnDestroy(): void; readonly openOnClick: InputSignalWithTransform; - registerOnChange(fn: (value: any) => void): void; + registerOnChange(fn: (value: unknown) => void): void; registerOnTouched(fn: () => void): void; registerOnValidatorChange(fn: () => void): void; setDisabledState(isDisabled: boolean): void; @@ -115,7 +117,7 @@ export class MatTimepickerInput implements MatTimepickerConnectedInput, Co timepickerValueAssigned(value: D | null): void; validate(control: AbstractControl): ValidationErrors | null; readonly value: ModelSignal; - writeValue(value: any): void; + writeValue(value: unknown): void; // (undocumented) static ɵdir: i0.ɵɵDirectiveDeclaration, "input[matTimepicker]", ["matTimepickerInput"], { "value": { "alias": "value"; "required": false; "isSignal": true; }; "timepicker": { "alias": "matTimepicker"; "required": true; "isSignal": true; }; "min": { "alias": "matTimepickerMin"; "required": false; "isSignal": true; }; "max": { "alias": "matTimepickerMax"; "required": false; "isSignal": true; }; "openOnClick": { "alias": "matTimepickerOpenOnClick"; "required": false; "isSignal": true; }; "disabledInput": { "alias": "disabled"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, never, never, true, never>; // (undocumented) diff --git a/goldens/material/tooltip/index.api.md b/goldens/material/tooltip/index.api.md index 5b3a661ac3c2..79aa94a2a9a2 100644 --- a/goldens/material/tooltip/index.api.md +++ b/goldens/material/tooltip/index.api.md @@ -53,7 +53,7 @@ export class MatTooltip implements OnDestroy, AfterViewInit { set hideDelay(value: NumberInput); _isTooltipVisible(): boolean; get message(): string; - set message(value: string | null | undefined); + set message(value: string | number | null | undefined); // (undocumented) ngAfterViewInit(): void; ngOnDestroy(): void; @@ -76,10 +76,10 @@ export class MatTooltip implements OnDestroy, AfterViewInit { y: number; }): void; get tooltipClass(): string | string[] | Set | { - [key: string]: any; + [key: string]: unknown; }; set tooltipClass(value: string | string[] | Set | { - [key: string]: any; + [key: string]: unknown; }); // (undocumented) _tooltipInstance: TooltipComponent | null; @@ -143,7 +143,7 @@ export class TooltipComponent implements OnDestroy { show(delay: number): void; _tooltip: ElementRef; tooltipClass: string | string[] | Set | { - [key: string]: any; + [key: string]: unknown; }; _triggerElement: HTMLElement; // (undocumented) diff --git a/guides/theming-your-components.md b/guides/theming-your-components.md new file mode 100644 index 000000000000..d7532b4db11b --- /dev/null +++ b/guides/theming-your-components.md @@ -0,0 +1,1009 @@ + + +# Theming your components + +Angular Material provides two approaches to styling custom components to match the application's +theme: + +- **CSS variables** included by `mat.theme()`. These are prefixed with `--mat-sys` and can be used + in your component stylesheets to match the theme and design for your application. +- **Utility classes** included by `mat.system-classes()`. These utility classes wrap the CSS variables + and allow you to apply theme styles directly from your component templates. + +Both approaches are valid ways to ensure your application is consistently designed alongside Angular +Material's components. Also, by using the system tokens for applying color to your application, +you will automatically support both light and dark mode versions that can be set using the +`color-scheme` CSS property. + +This guide will focus on showing the implementation for the utility classes as a means to show +both the available classes and the underlying system token CSS variables used. + +If your application is based on the older Material Design 2 APIs with theme configs, you can still +use these CSS variables and classes. See +the [Material Design 2 Support](#material-design-2-support) section below to learn how to enable +them. + +## Colors + +Material Design uses color to create accessible, personal color schemes that communicate your +product's hierarchy, state, and brand. See Material +Design's [Color Roles](https://m3.material.io/styles/color/roles) page to learn more +about its use and purpose. + +Using the system tokens makes it easy to match the same color scheme of your application's theme. It +also makes it easy to ensure your application can correctly handle both light and dark mode +automatically. + +
+ Expand to view all available color system tokens + +```css +/* Primary */ +--mat-sys-primary +--mat-sys-on-primary +--mat-sys-primary-container +--mat-sys-on-primary-container +--mat-sys-primary-fixed +--mat-sys-on-primary-fixed +--mat-sys-on-primary-fixed-variant +--mat-sys-primary-fixed-dim +--mat-sys-inverse-primary + +/* Secondary */ +--mat-sys-secondary +--mat-sys-on-secondary +--mat-sys-secondary-container +--mat-sys-on-secondary-container +--mat-sys-secondary-fixed +--mat-sys-on-secondary-fixed +--mat-sys-on-secondary-fixed-variant +--mat-sys-secondary-fixed-dim + +/* Tertiary */ +--mat-sys-tertiary +--mat-sys-on-tertiary +--mat-sys-tertiary-container +--mat-sys-on-tertiary-container +--mat-sys-tertiary-fixed +--mat-sys-on-tertiary-fixed +--mat-sys-on-tertiary-fixed-variant +--mat-sys-tertiary-fixed-dim + +/* Error */ +--mat-sys-error +--mat-sys-on-error +--mat-sys-error-container +--mat-sys-on-error-container + +/* Surface */ +--mat-sys-surface +--mat-sys-on-surface +--mat-sys-on-surface-variant +--mat-sys-surface-bright +--mat-sys-surface-container +--mat-sys-surface-container-high +--mat-sys-surface-container-highest +--mat-sys-surface-container-low +--mat-sys-surface-container-lowest +--mat-sys-surface-dim +--mat-sys-surface-tint +--mat-sys-surface-variant +--mat-sys-inverse-surface +--mat-sys-inverse-on-surface + +/* Miscellaneous */ +--mat-sys-background +--mat-sys-on-background +--mat-sys-neutral-variant20 +--mat-sys-neutral10 +--mat-sys-outline +--mat-sys-outline-variant +--mat-sys-scrim +--mat-sys-shadow +``` +
+ +### Background + +

Primary

+ +A primary background is useful for key components across the UI, such as buttons that have greater +importance on the page. In Angular Material, this is used for the selected date in a datepicker, the +handle of a slider, and the background of a checkbox. + +Text and icons should use the `on-primary` system color token ensure good contrast and +accessibility (see [Text](#text) below). + +
+.mat-bg-primary {
+  background-color: var(--mat-sys-primary);
+}
+
+ +A primary container color background is useful for filling components that should stand out on a +surface. In Angular Material, this is used for the container of a floating action button. + +
+.mat-bg-primary-container {
+  background-color: var(--mat-sys-primary-container);
+}
+
+ +

Secondary

+ +A secondary background is useful for less prominent components in the UI that have a different color +scheme than the primary. + +Text and icons should use the `on-secondary` system color token ensure good contrast and +accessibility (see [Text](#text) below). + +
+.mat-bg-secondary {
+  background-color: var(--mat-sys-secondary);
+}
+
+ +A secondary container color background is useful for components that need less emphasis than +secondary, such as filter chips. In Angular Material, this is used for selected items in a list and +the container of a tonal button. + +
+.mat-bg-secondary-container {
+  background-color: var(--mat-sys-secondary-container);
+}
+
+ +

Error

+ +An error background is useful for indicating an error state, such as an invalid text field, or for +the background of an important notification. In Angular Material, this is used for the background of +a badge. + +Text and icons should use the `on-error` system color token ensure good contrast and accessibility ( +see [Text](#text) below). + +
+.mat-bg-error {
+  background-color: var(--mat-sys-error);
+}
+
+ +An error container color background is useful for components that need less emphasis than error, +such as a container for error text. + +
+.mat-bg-error-container {
+  background-color: var(--mat-sys-error-container);
+}
+
+ +

Surfaces

+ +When using surface backgrounds, text and icons should use the `on-surface` or `on-surface-variant` +system color tokens ensure good contrast and accessibility (see [Text](#text) below). + +A surface background is useful for general surfaces of components. In Angular Material, this is used +for the background of many components, like tables, dialogs, menus, and toolbars. + +
+.mat-bg-surface {
+  background-color: var(--mat-sys-surface);
+}
+
+ +A surface variant background is useful for surfaces that need to stand out from the main surface +color. In Angular Material, this is used for the background of a filled form field and the track of +a progress bar. + +
+.mat-bg-surface-variant {
+  background-color: var(--mat-sys-surface-variant);
+}
+
+ +The "highest" surface container background is useful for surfaces that need the most emphasis +against the main surface color. In Angular Material, this is used for the background of a filled +card. + +
+.mat-bg-surface-container-highest {
+  background-color: var(--mat-sys-surface-container-highest);
+}
+
+ +A "high" surface container background is useful for surfaces that need more emphasis against the +main surface color. In Angular Material, this is used for the background of a datepicker. + +
+.mat-bg-surface-container-high {
+  background-color: var(--mat-sys-surface-container-high);
+}
+
+ +A surface container background is useful for surfaces that need to stand out from the main surface +color. In Angular Material, this is used for the background of a menu. + +
+.mat-bg-surface-container {
+  background-color: var(--mat-sys-surface-container);
+}
+
+ +A "low" surface container background is useful for surfaces that need less emphasis against the main +surface color. In Angular Material, this is used for the background of a bottom sheet. + +
+.mat-bg-surface-container-low {
+  background-color: var(--mat-sys-surface-container-low);
+}
+
+ +The "lowest" surface container background is useful for surfaces that need the least emphasis +against the main surface color. + +
+.mat-bg-surface-container-lowest {
+  background-color: var(--mat-sys-surface-container-lowest);
+}
+
+ +An inverse surface color background is useful for making elements stand out against the default +color scheme. It is good for temporary notifications that appear above your content. In Angular +Material, this is used for the background of a snackbar and a tooltip. + +When using the inverse surface background, text and icons should use the `inverse-on-surface` system +color token ensure good contrast and accessibility (see [Text](#text) below). + +
+.mat-bg-inverse-surface {
+  background-color: var(--mat-sys-inverse-surface);
+}
+
+ +

Disabled

+ +A disabled color background is useful for disabled components. In Angular Material, this is used for +components generally filled with the primary color but are currently disabled. + +In Angular Material, text and icons often use a 38% color mix of the surface color to strongly +convey +the disabled state. This is described with the `mat-text-disabled` class in [Text](#text)). + +
+.mat-bg-disabled {
+  background-color: color-mix(in srgb, var(--mat-sys-on-surface) 12%, transparent);
+}
+
+ +### Text + +

Primary

+ +Use the primary color for text that needs to stand out. In Angular Material, this is used for the +text of a text button and the selected tab label. + +
+.mat-text-primary {
+  color: var(--mat-sys-primary);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

Secondary

+ +Use the secondary color for text that needs to stand out apart from the main theme color. + +
+.mat-text-secondary {
+  color: var(--mat-sys-secondary);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

Error

+ +Use the error color for text that indicates an issue or warning, such as validation messages. In +Angular Material, this is used for the error text in a form field. + +
+.mat-text-error {
+  color: var(--mat-sys-error);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

Disabled

+ +Use the disabled text color for elements that are disabled on either the disabled or surface +background. + +
+.mat-text-disabled {
+  color: color-mix(in srgb, var(--mat-sys-on-surface) 38%, transparent);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

On Surface Variant

+ +Use the on-surface-variant color for text that should have a lower emphasis than the surrounding +text. This can include subheading, captions, and hint text. + +
+.mat-text-on-surface-variant {
+  color: var(--mat-sys-on-surface-variant);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

On Primary

+ +Use the on-primary color for text and icons appearing on primary backgrounds to ensure good contrast +and accessibility. + +
+.mat-text-on-primary {
+  color: var(--mat-sys-on-primary);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

On Primary Container

+ +Use the on-primary-container color for text and icons appearing on primary-container backgrounds to +ensure good contrast and accessibility. + +
+.mat-text-on-primary-container {
+  color: var(--mat-sys-on-primary-container);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

On Secondary

+ +Use the on-secondary color for text and icons appearing on secondary backgrounds to ensure good +contrast and accessibility. + +
+.mat-text-on-secondary {
+  color: var(--mat-sys-on-secondary);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

On Secondary Container

+ +Use the on-secondary-container color for text that contrasts well against a secondary-container +background. + +
+.mat-text-on-secondary-container {
+  color: var(--mat-sys-on-secondary-container);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

On Error

+ +Use the on-error color for text that contrasts well against an error background. + +
+.mat-text-on-error {
+  color: var(--mat-sys-on-error);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

On Error Container

+ +Use the on-error-container color for text that contrasts well against an error-container background. + +
+.mat-text-on-error-container {
+  color: var(--mat-sys-on-error-container);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

On Surface

+ +Use the on-surface color for text that contrasts well against a surface background. + +
+.mat-text-on-surface {
+  color: var(--mat-sys-on-surface);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

Inverse On Surface

+ +Use the inverse-on-surface color for text that contrasts well against an inverse-surface background. + +
+.mat-text-inverse-on-surface {
+  color: var(--mat-sys-inverse-on-surface);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +## Typography + +Material Design provides five categories of font types: body, display, headline, label, and title. +Each category has three sizes: small, medium, and large. Learn more about how these categories and +their sizes should be used in your application by visiting Material +Design's [Applying Type](https://m3.material.io/styles/typography/applying-type) documentation. + +
+ Expand to view all available typography system tokens + +```css +--mat-sys-body-large +--mat-sys-body-large-font +--mat-sys-body-large-line-height +--mat-sys-body-large-size +--mat-sys-body-large-tracking +--mat-sys-body-large-weight + +--mat-sys-body-medium +--mat-sys-body-medium-font +--mat-sys-body-medium-line-height +--mat-sys-body-medium-size +--mat-sys-body-medium-tracking +--mat-sys-body-medium-weight + +--mat-sys-body-small +--mat-sys-body-small-font +--mat-sys-body-small-line-height +--mat-sys-body-small-size +--mat-sys-body-small-tracking +--mat-sys-body-small-weight + +--mat-sys-display-large +--mat-sys-display-large-font +--mat-sys-display-large-line-height +--mat-sys-display-large-size +--mat-sys-display-large-tracking +--mat-sys-display-large-weight + +--mat-sys-display-medium +--mat-sys-display-medium-font +--mat-sys-display-medium-line-height +--mat-sys-display-medium-size +--mat-sys-display-medium-tracking +--mat-sys-display-medium-weight + +--mat-sys-display-small +--mat-sys-display-small-font +--mat-sys-display-small-line-height +--mat-sys-display-small-size +--mat-sys-display-small-tracking +--mat-sys-display-small-weight + +--mat-sys-headline-large +--mat-sys-headline-large-font +--mat-sys-headline-large-line-height +--mat-sys-headline-large-size +--mat-sys-headline-large-tracking +--mat-sys-headline-large-weight + +--mat-sys-headline-medium +--mat-sys-headline-medium-font +--mat-sys-headline-medium-line-height +--mat-sys-headline-medium-size +--mat-sys-headline-medium-tracking +--mat-sys-headline-medium-weight + +--mat-sys-headline-small +--mat-sys-headline-small-font +--mat-sys-headline-small-line-height +--mat-sys-headline-small-size +--mat-sys-headline-small-tracking +--mat-sys-headline-small-weight + +--mat-sys-label-large +--mat-sys-label-large-font +--mat-sys-label-large-line-height +--mat-sys-label-large-size +--mat-sys-label-large-tracking +--mat-sys-label-large-weight +--mat-sys-label-large-weight-prominent + +--mat-sys-label-medium +--mat-sys-label-medium-font +--mat-sys-label-medium-line-height +--mat-sys-label-medium-size +--mat-sys-label-medium-tracking +--mat-sys-label-medium-weight +--mat-sys-label-medium-weight-prominent + +--mat-sys-label-small +--mat-sys-label-small-font +--mat-sys-label-small-line-height +--mat-sys-label-small-size +--mat-sys-label-small-tracking +--mat-sys-label-small-weight + +--mat-sys-title-large +--mat-sys-title-large-font +--mat-sys-title-large-line-height +--mat-sys-title-large-size +--mat-sys-title-large-tracking +--mat-sys-title-large-weight + +--mat-sys-title-medium +--mat-sys-title-medium-font +--mat-sys-title-medium-line-height +--mat-sys-title-medium-size +--mat-sys-title-medium-tracking +--mat-sys-title-medium-weight + +--mat-sys-title-small +--mat-sys-title-small-font +--mat-sys-title-small-line-height +--mat-sys-title-small-size +--mat-sys-title-small-tracking +--mat-sys-title-small-weight +``` +
+ +

Body

+ + +The small body typeface is useful for captions. In Angular Material, this is used for the subscript +text in a form field and the text in a paginator. + +
+.mat-font-body-sm {
+  font: var(--mat-sys-body-small);
+  letter-spacing: var(--mat-sys-body-small-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +The medium body typeface is the default body font. In Angular Material, this is used for the text in +a table row and the supporting text in a dialog. + +
+.mat-font-body-md {
+  font: var(--mat-sys-body-medium);
+  letter-spacing: var(--mat-sys-body-medium-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +The large body typeface is useful for an introductory paragraph. In Angular Material, this is used +for the text in a list item and the text in a select trigger. + +
+.mat-font-body-lg {
+  font: var(--mat-sys-body-large);
+  letter-spacing: var(--mat-sys-body-large-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

Display

+ + +The small display typeface is useful for short, important text or numerals, such as in hero sections +or for marking key information. + +
+.mat-font-display-sm {
+  font: var(--mat-sys-display-small);
+  letter-spacing: var(--mat-sys-display-small-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +The medium display typeface is useful for short, impactful text in hero sections or titles on larger +screens. + +
+.mat-font-display-md {
+  font: var(--mat-sys-display-medium);
+  letter-spacing: var(--mat-sys-display-medium-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +The large display typeface is useful for short, high-emphasis text in hero sections or titles on +larger screens, providing the most visual weight. + +
+.mat-font-display-lg {
+  font: var(--mat-sys-display-large);
+  letter-spacing: var(--mat-sys-display-large-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

Headline

+ + +The small headline typeface is useful for a page title. In Angular Material, this is used for the +headline in a dialog. + +
+.mat-font-headline-sm {
+  font: var(--mat-sys-headline-small);
+  letter-spacing: var(--mat-sys-headline-small-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +The medium headline typeface is useful for a section title. + +
+.mat-font-headline-md {
+  font: var(--mat-sys-headline-medium);
+  letter-spacing: var(--mat-sys-headline-medium-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +The large headline typeface is useful for a page title on a large screen. + +
+.mat-font-headline-lg {
+  font: var(--mat-sys-headline-large);
+  letter-spacing: var(--mat-sys-headline-large-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

Label

+ + +The small label typeface is useful for text in a badge. + +
+.mat-font-label-sm {
+  font: var(--mat-sys-label-small);
+  letter-spacing: var(--mat-sys-label-small-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +The medium label typeface is useful for the slider label. + +
+.mat-font-label-md {
+  font: var(--mat-sys-label-medium);
+  letter-spacing: var(--mat-sys-label-medium-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +The large label typeface is useful for buttons, chips, and menu labels. + +
+.mat-font-label-lg {
+  font: var(--mat-sys-label-large);
+  letter-spacing: var(--mat-sys-label-large-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +

Title

+ + +The small title typeface is useful for a card title. In Angular Material, this is used for the +header of a table and the label of an option group. + +
+.mat-font-title-sm {
+  font: var(--mat-sys-title-small);
+  letter-spacing: var(--mat-sys-title-small-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +The medium title typeface is useful for a dialog title or the primary text in a list item. In +Angular Material, this is used for the subtitle of a card and the header of an expansion panel. + +
+.mat-font-title-md {
+  font: var(--mat-sys-title-medium);
+  letter-spacing: var(--mat-sys-title-medium-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +The large title typeface is useful for a page title on a small screen. In Angular Material, this is +used for the title of a card and the title of a toolbar. + +
+.mat-font-title-lg {
+  font: var(--mat-sys-title-large);
+  letter-spacing: var(--mat-sys-title-large-tracking);
+}
+
+ +
Example text: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ +## Shape + +Material Design uses border radius to help direct attention, identify components, communicate state, +and express brand. See Material +Design's [Corner Radius Scale](https://m3.material.io/styles/shape/corner-radius-scale) +documentation to learn more. + +In Angular Material, shape is scoped to varying levels of border-radius. The following code blocks +demonstrate the levels of roundness. Their border sizes are increased to `2px` to clearly show the +border radii. + +
+ Expand to view all available corner shape system tokens + +```css +--mat-sys-corner-extra-large: 28px; +--mat-sys-corner-extra-large-top: 28px 28px 0 0; +--mat-sys-corner-extra-small: 4px; +--mat-sys-corner-extra-small-top: 4px 4px 0 0; +--mat-sys-corner-full: 9999px; +--mat-sys-corner-large: 16px; +--mat-sys-corner-large-end: 0 16px 16px 0; +--mat-sys-corner-large-start: 16px 0 0 16px; +--mat-sys-corner-large-top: 16px 16px 0 0; +--mat-sys-corner-medium: 12px; +--mat-sys-corner-none: 0; +--mat-sys-corner-small: 8px; +``` +
+ +The extra small border radius is useful for components that need a small amount of rounding, such as +a chip. In Angular Material, this is used for the shape of a snackbar and a tooltip. + +
+.mat-corner-xs {
+  border-radius: var(--mat-sys-corner-extra-small);
+}
+
+The small border radius is useful for components that need a small amount of rounding, such as a +text field. + +
+.mat-corner-sm {
+  border-radius: var(--mat-sys-corner-small);
+}
+
+The medium border radius is useful for components that need a medium amount of rounding, such as a +button. In Angular Material, this is used for the shape of a card. + +
+.mat-corner-md {
+  border-radius: var(--mat-sys-corner-medium);
+}
+
+The large border radius is useful for components that need a large amount of rounding, such as a +card. In Angular Material, this is used for the shape of a floating action button and a datepicker. + +
+.mat-corner-lg {
+  border-radius: var(--mat-sys-corner-large);
+}
+
+The extra large border radius is useful for components that need a large amount of rounding. In +Angular Material, this is used for the shape of a button toggle and the shape of a dialog. + +
+.mat-corner-xl {
+  border-radius: var(--mat-sys-corner-extra-large);
+}
+
+The full border radius is useful for components that are circular, such as a user avatar. In Angular +Material, this is used for the shape of a badge and the shape of a button. + +
+.mat-corner-full {
+  border-radius: var(--mat-sys-corner-full);
+}
+
+ +## Elevation + +Material Design uses borders and shadows to create a sense of depth and hierarchy in the UI. See +Material Design's [Applying Elevation](https://m3.material.io/styles/elevation/applying-elevation) +documentation to learn more. + +

Border

+ +
+ Expand to view the outline system tokens + +```css +--mat-sys-outline +--mat-sys-outline-variant +``` +
+ +The Material Design border is useful for components that need a visible boundary. In Angular +Material, this is used for the outline of an outlined button. + +
+.mat-border {
+  border: 1px solid var(--mat-sys-outline);
+}
+
+ +The subtle outline variant is useful for components that need a less obvious boundary. In Angular +Material, this is used for the outline of an outlined card and the color of the divider. + +
+.mat-border-subtle {
+  border: 1px solid var(--mat-sys-outline-variant);
+}
+
+ +

Shadow

+ +
+ Expand to view all available elevation system tokens + +```css +--mat-sys-level0: 0px 0px 0px 0px rgba(0, 0, 0, .2), 0px 0px 0px 0px rgba(0, 0, 0, .14), 0px 0px 0px 0px rgba(0, 0, 0, .12); +--mat-sys-level1: 0px 2px 1px -1px rgba(0, 0, 0, .2), 0px 1px 1px 0px rgba(0, 0, 0, .14), 0px 1px 3px 0px rgba(0, 0, 0, .12); +--mat-sys-level2: 0px 3px 3px -2px rgba(0, 0, 0, .2), 0px 3px 4px 0px rgba(0, 0, 0, .14), 0px 1px 8px 0px rgba(0, 0, 0, .12); +--mat-sys-level3: 0px 3px 5px -1px rgba(0, 0, 0, .2), 0px 6px 10px 0px rgba(0, 0, 0, .14), 0px 1px 18px 0px rgba(0, 0, 0, .12); +--mat-sys-level4: 0px 5px 5px -3px rgba(0, 0, 0, .2), 0px 8px 10px 1px rgba(0, 0, 0, .14), 0px 3px 14px 2px rgba(0, 0, 0, .12); +--mat-sys-level5: 0px 7px 8px -4px rgba(0, 0, 0, .2), 0px 12px 17px 2px rgba(0, 0, 0, .14), 0px 5px 22px 4px rgba(0, 0, 0, .12); +``` +
+ +Level 1 elevation can be used to slightly raise the appearance of a surface. In Angular Material, +this is used for the elevation of an elevated card and the handle of a slider. + +
+.mat-shadow-1 {
+  box-shadow: var(--mat-sys-level1);
+}
+
+ +Level 2 elevation can be used to raise the appearance of a surface. In Angular Material, this is +used for the elevation of a menu and a select panel. + +
+.mat-shadow-2 {
+  box-shadow: var(--mat-sys-level2);
+}
+
+ +Level 3 elevation is used to raise the appearance of a surface. In Angular Material, this is used +for the elevation of a floating action button. + +
+.mat-shadow-3 {
+  box-shadow: var(--mat-sys-level3);
+}
+
+ +Level 4 elevation is generally reserved for elevation changes due to interaction like focus and +hover. In Angular Material, this is used for the elevation of a hovered floating action button. + +
+.mat-shadow-4 {
+  box-shadow: var(--mat-sys-level4);
+}
+
+ +Level 5 elevation is used to greatly raise the appearance of a surface and is generally reserved for +elevation changes due to interaction like focus and hover. + +
+.mat-shadow-5 {
+  box-shadow: var(--mat-sys-level5);
+}
+
+ +## Material Design 2 Support + +This guide is compatible for applications defining their theme with the "m2" Sass APIs using +the legacy theme-config approach. To take advantage of CSS variables and the utility classes, +you can call `@include mat.m2-theme($theme)` in your theme file, which will define +system tokens according to the Material Design 2 system that matches your current theme +configuration. + +```scss +@use '@angular/material' as mat; + +$theme: mat.m2-define-light-theme(( + color: ( + primary: mat.define-palette(mat.$indigo-palette, 500), + ), + ... +)); + +html { + @include mat.core-theme($theme); + @include mat.button-theme($theme); + ... + @include mat.m2-theme($theme); + @include mat.system-classes(); +} +``` + +By using CSS variables and utility classes, you can avoid creating component-specific theme files +and mixins that extract values from the `$theme` Sass map. For example, consider the following +example of how styles used to be applied in custom components: + +```scss +@use '@angular/material' as mat; +@use 'sass:map'; + +@mixin my-component-theme($theme) { + $foreground: map.get(mat.m2-get-color-config($theme), foreground); + $background: map.get(mat.m2-get-color-config($theme), background); + $primary: map.get(mat.m2-get-color-config($theme), primary); + $typography: mat.m2-get-typography-config($config-or-theme); + + .widget-a { + background-color: mat.m2-get-color-from-palette($background, card); + color: mat.m2-get-color-from-palette($foreground, text); + @include mat.m2-typography-level($config, body-1); + } + + .widget-b { + background-color: mat.m2-get-color-from-palette($primary, default); + color: mat.m2-get-color-from-palette($primary, default-contrast); + } +} +``` + +By using the CSS variables, you can define these theme styles in your component's +stylesheet and avoid creating a separate theme file or mixin: + +```scss +.widget-a { + background-color: var(--mat-sys-surface); + color: var(--mat-sys-on-surface); + font: var(--mat-sys-body-medium); +} + +.widget-b { + background-color: var(--mat-sys-primary); + color: var(--mat-sys-on-primary); +} +``` + +Taking it one step further, you can alternatively use the utility classes to achieve the same styles +in the component template: + +```html + + + +``` diff --git a/guides/theming.md b/guides/theming.md index 78a285cc62a3..d0bb0567a59d 100644 --- a/guides/theming.md +++ b/guides/theming.md @@ -58,6 +58,20 @@ body { } ``` +You can also define a convenient set of CSS utility classes that let you apply +theme styles from your component templates. + +```scss +html { + ... + @include mat.system-classes(); +} +``` + +```html + +``` + The `mat.theme` mixin will only declare CSS variables for the categories included in the input. For example, if `typography` is not defined, then typography CSS variables will not be included in the output. @@ -89,10 +103,10 @@ distinct accent color to some components. You can also set the `theme-type` to determine the color values are defined: -* `color-scheme` \- include both light and dark colors using the `light-dark` - CSS color function -* `light` \- only define the light color values -* `dark` \- only define the dark color values +- `color-scheme` \- include both light and dark colors using the `light-dark` + CSS color function +- `light` \- only define the light color values +- `dark` \- only define the dark color values The `light-dark` CSS color function is [widely available](https://caniuse.com/?search=light-dark) for all major @@ -213,18 +227,18 @@ scheme to communicate an application’s hierarchy, state, and brand. Angular Material provides twelve prebuilt color palettes that can be used for your application’s theme: -* `$red-palette` -* `$green-palette` -* `$blue-palette` -* `$yellow-palette` -* `$cyan-palette` -* `$magenta-palette` -* `$orange-palette` -* `$chartreuse-palette` -* `$spring-green-palette` -* `$azure-palette` -* `$violet-palette` -* `$rose-palette` +- `$red-palette` +- `$green-palette` +- `$blue-palette` +- `$yellow-palette` +- `$cyan-palette` +- `$magenta-palette` +- `$orange-palette` +- `$chartreuse-palette` +- `$spring-green-palette` +- `$azure-palette` +- `$violet-palette` +- `$rose-palette` ### Custom Color Palettes @@ -357,7 +371,7 @@ typography variables to create an application-wide banner presenting important information to the user: ```scss -:host { +.my-component { background: var(--mat-sys-primary-container); color: var(--mat-sys-on-primary-container); border: 1px solid var(--mat-sys-outline-variant); @@ -365,8 +379,14 @@ information to the user: } ``` -See the [Theme Variables](https://material.angular.dev/guide/system-variables) guide for a -comprehensive list of these variables, examples of where they are used, and how +Alternatively, you can use utility classes to achieve the same styles: + +```html +
+``` + +See the [Theming your components](https://material.angular.dev/guide/theming-your-components) guide for a +comprehensive list of these variables and classes, including examples of where they are used, and how components can depend on them. ## Customizing Tokens @@ -458,6 +478,56 @@ structure and CSS classes are considered private implementation details that may change at any time. CSS variables used by the Angular Material components should be defined through the `overrides` API instead of defined explicitly. +## Strong focus indicators + +By default, most components indicate browser focus by changing their background color as described +by the Material Design specification. This behavior, however, can fall short of accessibility +requirements, such as [WCAG 4.5:1][], which require a stronger indication of browser focus. + +Angular Material supports rendering highly visible outlines on focused elements. Applications can +enable these strong focus indicators by calling `mat.strong-focus-indicators()`. + +```scss +@use '@angular/material' as mat; + +html { + color-scheme: light dark; + @include mat.theme(( + color: mat.$violet-palette, + typography: Roboto, + density: 0 + )); + @include mat.strong-focus-indicators(); +} +``` + +By default, the focus indicator uses the theme's secondary color, but you can customize this color +by calling the `strong-focus-indicators-theme($color)` mixin. Additionally, you can use +this mixin to change the color of the focus indicators in situations in which the default color +would not contrast sufficiently with the background color. + +### Customizing strong focus indicators + +You can pass a configuration map to `strong-focus-indicators` to customize the appearance of the +indicators. This configuration includes `border-color`, `border-style`, `border-width`, and +`border-radius`. + +The following example includes strong focus indicator styles with custom settings alongside the rest +of the custom theme API. + +```scss +@use '@angular/material' as mat; + +@include mat.strong-focus-indicators(( + border-color: red, + border-style: dotted, + border-width: 4px, + border-radius: 2px, +)); +``` + +[WCAG]: https://www.w3.org/WAI/standards-guidelines/wcag/glance/ + ## Shadow DOM Angular Material assumes that, by default, all theme styles are loaded as global diff --git a/integration/harness-e2e-cli/angular.json b/integration/harness-e2e-cli/angular.json index 008a5748db50..b47b4e0da88b 100644 --- a/integration/harness-e2e-cli/angular.json +++ b/integration/harness-e2e-cli/angular.json @@ -2,6 +2,11 @@ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", + "cli": { + "cache": { + "enabled": false + } + }, "projects": { "harness-e2e-cli": { "projectType": "application", @@ -18,16 +23,16 @@ "prefix": "app", "architect": { "build": { - "builder": "@angular-devkit/build-angular:browser", + "builder": "@angular/build:application", "options": { "outputPath": "dist/harness-e2e-cli", + "polyfills": ["zone.js"], "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", + "browser": "src/main.ts", "tsConfig": "tsconfig.app.json", - "inlineStyleLanguage": "scss", + "inlineStyleLanguage": "css", "assets": ["src/favicon.ico", "src/assets"], - "styles": ["src/styles.scss"], + "styles": ["src/styles.css"], "scripts": [] }, "configurations": { @@ -53,9 +58,7 @@ "outputHashing": "all" }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -64,7 +67,7 @@ "defaultConfiguration": "production" }, "serve": { - "builder": "@angular-devkit/build-angular:dev-server", + "builder": "@angular/build:dev-server", "configurations": { "production": { "buildTarget": "harness-e2e-cli:build:production" @@ -74,25 +77,6 @@ } }, "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "harness-e2e-cli:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "inlineStyleLanguage": "scss", - "assets": ["src/favicon.ico", "src/assets"], - "styles": ["src/styles.scss"], - "scripts": [] - } } } } diff --git a/integration/harness-e2e-cli/karma.conf.js b/integration/harness-e2e-cli/karma.conf.js deleted file mode 100644 index 1f700a8e6126..000000000000 --- a/integration/harness-e2e-cli/karma.conf.js +++ /dev/null @@ -1,41 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - require('@angular-devkit/build-angular/plugins/karma'), - ], - client: { - jasmine: { - // you can add configuration options for Jasmine here - // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html - // for example, you can disable the random execution with `random: false` - // or set a specific seed with `seed: 4321` - }, - clearContext: false, // leave Jasmine Spec Runner output visible in browser - }, - jasmineHtmlReporter: { - suppressAll: true, // removes the duplicated traces - }, - coverageReporter: { - dir: require('path').join(__dirname, './coverage/harness-e2e-cli'), - subdir: '.', - reporters: [{type: 'html'}, {type: 'text-summary'}], - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false, - restartOnFileChange: true, - }); -}; diff --git a/integration/harness-e2e-cli/package.json b/integration/harness-e2e-cli/package.json index 39958a4b55c8..e968d3ad0e77 100644 --- a/integration/harness-e2e-cli/package.json +++ b/integration/harness-e2e-cli/package.json @@ -8,8 +8,8 @@ "watch": "ng build --watch --configuration development", "test": "ng test", "run-e2e-specs": "node --loader ts-node/esm node_modules/jasmine/bin/jasmine --config=e2e/jasmine.json", - "wait-and-run-e2e": "wait-on http://localhost:4200 && pnpm run-e2e-specs", - "e2e": "concurrently -s first -k 'pnpm ng serve' 'pnpm wait-and-run-e2e'" + "wait-and-run-e2e": "for i in {1..25}; do curl -s --fail http://localhost:4200 > /dev/null && break || (echo 'Waiting for server... attempt '$i' of 25'; sleep 2); done; pnpm run run-e2e-specs", + "e2e": "concurrently -s first -k 'pnpm run ng serve' 'pnpm run wait-and-run-e2e'" }, "private": true, "dependencies": { @@ -26,7 +26,7 @@ "zone.js": "~0.15.0" }, "devDependencies": { - "@angular-devkit/build-angular": "20.2.0", + "@angular/build": "20.2.0", "@angular/cli": "20.2.0", "@angular/compiler-cli": "20.2.0", "@types/jasmine": "5.1.8", @@ -35,14 +35,8 @@ "concurrently": "^9.0.0", "jasmine": "5.8.0", "jasmine-core": "5.8.0", - "karma": "6.4.4", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.0", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "~2.1.0", "selenium-webdriver": "3.6.0", "ts-node": "~10.9.1", - "typescript": "5.8.3", - "wait-on": "^8.0.0" + "typescript": "5.8.3" } } diff --git a/integration/harness-e2e-cli/pnpm-lock.yaml b/integration/harness-e2e-cli/pnpm-lock.yaml index c2a49fe03367..f99d483dee2d 100644 --- a/integration/harness-e2e-cli/pnpm-lock.yaml +++ b/integration/harness-e2e-cli/pnpm-lock.yaml @@ -42,9 +42,9 @@ importers: specifier: ~0.15.0 version: 0.15.0 devDependencies: - '@angular-devkit/build-angular': + '@angular/build': specifier: 20.2.0 - version: 20.2.0(@angular/compiler-cli@20.2.0(@angular/compiler@20.2.0)(typescript@5.8.3))(@angular/compiler@20.2.0)(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@types/node@22.15.33)(chokidar@4.0.3)(jiti@1.21.7)(karma@6.4.4)(typescript@5.8.3) + version: 20.2.0(@angular/compiler-cli@20.2.0(@angular/compiler@20.2.0)(typescript@5.8.3))(@angular/compiler@20.2.0)(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@types/node@22.15.33)(chokidar@4.0.3)(jiti@1.21.7)(karma@6.4.4)(less@4.4.0)(postcss@8.5.6)(terser@5.43.1)(tslib@2.8.1)(typescript@5.8.3) '@angular/cli': specifier: 20.2.0 version: 20.2.0(@types/node@22.15.33)(chokidar@4.0.3) @@ -69,21 +69,6 @@ importers: jasmine-core: specifier: 5.8.0 version: 5.8.0 - karma: - specifier: 6.4.4 - version: 6.4.4 - karma-chrome-launcher: - specifier: ~3.2.0 - version: 3.2.0 - karma-coverage: - specifier: ~2.2.0 - version: 2.2.1 - karma-jasmine: - specifier: ~4.0.0 - version: 4.0.2(karma@6.4.4) - karma-jasmine-html-reporter: - specifier: ~2.1.0 - version: 2.1.0(jasmine-core@5.8.0)(karma-jasmine@4.0.2(karma@6.4.4))(karma@6.4.4) selenium-webdriver: specifier: 3.6.0 version: 3.6.0 @@ -93,9 +78,6 @@ importers: typescript: specifier: 5.8.3 version: 5.8.3 - wait-on: - specifier: ^8.0.0 - version: 8.0.3 packages: @@ -163,63 +145,6 @@ packages: resolution: {integrity: sha512-PaBXFP1kdUuNtMie0lWnitlYbq8o1gz/s0YIa8oY1X3swOJ7bP6kBfxTb9opV5uXAOkXg2zCdnZ4Eu1aVkgPGw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-devkit/build-angular@20.2.0': - resolution: {integrity: sha512-B3dlR9AnANyT8yfESODFYEDEGV6pMwozsfjsH0NFxrdrfB1BYTBKpgYkQWg2I1j48hf7YmetZgA1sa3gYOt1QQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - peerDependencies: - '@angular/compiler-cli': ^20.0.0 - '@angular/core': ^20.0.0 - '@angular/localize': ^20.0.0 - '@angular/platform-browser': ^20.0.0 - '@angular/platform-server': ^20.0.0 - '@angular/service-worker': ^20.0.0 - '@angular/ssr': ^20.2.0 - '@web/test-runner': ^0.20.0 - browser-sync: ^3.0.2 - jest: ^29.5.0 - jest-environment-jsdom: ^29.5.0 - karma: ^6.3.0 - ng-packagr: ^20.0.0 - protractor: ^7.0.0 - tailwindcss: ^2.0.0 || ^3.0.0 || ^4.0.0 - typescript: '>=5.8 <6.0' - peerDependenciesMeta: - '@angular/core': - optional: true - '@angular/localize': - optional: true - '@angular/platform-browser': - optional: true - '@angular/platform-server': - optional: true - '@angular/service-worker': - optional: true - '@angular/ssr': - optional: true - '@web/test-runner': - optional: true - browser-sync: - optional: true - jest: - optional: true - jest-environment-jsdom: - optional: true - karma: - optional: true - ng-packagr: - optional: true - protractor: - optional: true - tailwindcss: - optional: true - - '@angular-devkit/build-webpack@0.2002.0': - resolution: {integrity: sha512-sON0IFOaZW5/bLXlMuKXOV5viaa7SAGHhdM4PXM6Fa0PPqPI6zZp2iqYpwETKpN8DfnLNxefdysvCn9DbHuNhQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - peerDependencies: - webpack: ^5.30.0 - webpack-dev-server: ^5.0.2 - '@angular-devkit/core@20.2.0': resolution: {integrity: sha512-3CM6Zsr09Kf92ItFkxijlnC4+ZOgkxdCk0vFYvuw9UuvTDNwyIqJi6693PRPRbcXgpdY2vs6u99elSvQVmoEEw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} @@ -380,14 +305,6 @@ packages: resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.0': - resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.27.1': - resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==} - engines: {node: '>=6.9.0'} - '@babel/core@7.28.3': resolution: {integrity: sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==} engines: {node: '>=6.9.0'} @@ -408,77 +325,20 @@ packages: resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.27.1': - resolution: {integrity: sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-create-class-features-plugin@7.28.3': - resolution: {integrity: sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-create-regexp-features-plugin@7.27.1': - resolution: {integrity: sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-define-polyfill-provider@0.6.5': - resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.27.1': - resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} - engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.27.1': - resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/helper-module-transforms@7.28.3': resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-remap-async-to-generator@7.27.1': - resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} - engines: {node: '>=6.9.0'} - '@babel/helper-split-export-declaration@7.24.7': resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} engines: {node: '>=6.9.0'} @@ -495,14 +355,6 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.27.1': - resolution: {integrity: sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.27.1': - resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} - engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.3': resolution: {integrity: sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==} engines: {node: '>=6.9.0'} @@ -517,535 +369,150 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1': - resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': - resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': - resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} + '@babel/traverse@7.27.1': + resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': - resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} + '@babel/traverse@7.28.3': + resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.13.0 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3': - resolution: {integrity: sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==} + '@babel/types@7.27.1': + resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': - resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.27.1': - resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} - '@babel/plugin-syntax-unicode-sets-regex@7.18.6': - resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@emnapi/core@1.5.0': + resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} - '@babel/plugin-transform-arrow-functions@7.27.1': - resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@emnapi/runtime@1.5.0': + resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} - '@babel/plugin-transform-async-generator-functions@7.28.0': - resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@babel/plugin-transform-async-to-generator@7.27.1': - resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/aix-ppc64@0.25.9': + resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] - '@babel/plugin-transform-block-scoped-functions@7.27.1': - resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/android-arm64@0.25.9': + resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] - '@babel/plugin-transform-block-scoping@7.28.0': - resolution: {integrity: sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/android-arm@0.25.9': + resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] - '@babel/plugin-transform-class-properties@7.27.1': - resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/android-x64@0.25.9': + resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] - '@babel/plugin-transform-class-static-block@7.28.3': - resolution: {integrity: sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.12.0 + '@esbuild/darwin-arm64@0.25.9': + resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] - '@babel/plugin-transform-classes@7.28.3': - resolution: {integrity: sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/darwin-x64@0.25.9': + resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] - '@babel/plugin-transform-computed-properties@7.27.1': - resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/freebsd-arm64@0.25.9': + resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] - '@babel/plugin-transform-destructuring@7.28.0': - resolution: {integrity: sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/freebsd-x64@0.25.9': + resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] - '@babel/plugin-transform-dotall-regex@7.27.1': - resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-arm64@0.25.9': + resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] - '@babel/plugin-transform-duplicate-keys@7.27.1': - resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-arm@0.25.9': + resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@esbuild/linux-ia32@0.25.9': + resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] - '@babel/plugin-transform-dynamic-import@7.27.1': - resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-loong64@0.25.9': + resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] - '@babel/plugin-transform-explicit-resource-management@7.28.0': - resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-mips64el@0.25.9': + resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] - '@babel/plugin-transform-exponentiation-operator@7.27.1': - resolution: {integrity: sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-ppc64@0.25.9': + resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] - '@babel/plugin-transform-export-namespace-from@7.27.1': - resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-riscv64@0.25.9': + resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] - '@babel/plugin-transform-for-of@7.27.1': - resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-s390x@0.25.9': + resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] - '@babel/plugin-transform-function-name@7.27.1': - resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-x64@0.25.9': + resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] - '@babel/plugin-transform-json-strings@7.27.1': - resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-literals@7.27.1': - resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-logical-assignment-operators@7.27.1': - resolution: {integrity: sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-member-expression-literals@7.27.1': - resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-amd@7.27.1': - resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-commonjs@7.27.1': - resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-systemjs@7.27.1': - resolution: {integrity: sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-umd@7.27.1': - resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-new-target@7.27.1': - resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1': - resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-numeric-separator@7.27.1': - resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-object-rest-spread@7.28.0': - resolution: {integrity: sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-object-super@7.27.1': - resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-optional-catch-binding@7.27.1': - resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-optional-chaining@7.27.1': - resolution: {integrity: sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-parameters@7.27.7': - resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-private-methods@7.27.1': - resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-private-property-in-object@7.27.1': - resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-property-literals@7.27.1': - resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-regenerator@7.28.3': - resolution: {integrity: sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-regexp-modifiers@7.27.1': - resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-reserved-words@7.27.1': - resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-runtime@7.28.3': - resolution: {integrity: sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-shorthand-properties@7.27.1': - resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-spread@7.27.1': - resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-sticky-regex@7.27.1': - resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-template-literals@7.27.1': - resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typeof-symbol@7.27.1': - resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-escapes@7.27.1': - resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-property-regex@7.27.1': - resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-regex@7.27.1': - resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-sets-regex@7.27.1': - resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/preset-env@7.28.3': - resolution: {integrity: sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/preset-modules@0.1.6-no-external-plugins': - resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} - peerDependencies: - '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - - '@babel/runtime@7.28.3': - resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.27.1': - resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.3': - resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.27.1': - resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.2': - resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} - engines: {node: '>=6.9.0'} - - '@colors/colors@1.5.0': - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - - '@discoveryjs/json-ext@0.6.3': - resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==} - engines: {node: '>=14.17.0'} - - '@emnapi/core@1.5.0': - resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} - - '@emnapi/runtime@1.5.0': - resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} - - '@emnapi/wasi-threads@1.1.0': - resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - - '@esbuild/aix-ppc64@0.25.9': - resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.9': - resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.9': - resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.9': - resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.9': - resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.9': - resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.9': - resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.9': - resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.9': - resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.9': - resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.9': - resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.9': - resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.9': - resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.9': - resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.9': - resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.9': - resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.9': - resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.9': - resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] + '@esbuild/netbsd-arm64@0.25.9': + resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] '@esbuild/netbsd-x64@0.25.9': resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} @@ -1095,12 +562,6 @@ packages: cpu: [x64] os: [win32] - '@hapi/hoek@9.3.0': - resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} - - '@hapi/topo@5.1.0': - resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} - '@inquirer/checkbox@4.2.2': resolution: {integrity: sha512-E+KExNurKcUJJdxmjglTl141EwxWyAHplvsYJQgSwXf8qiNWkTxTuCCqmhFEmbIXd4zLaGMfQFJ6WrZ7fSeV3g==} engines: {node: '>=18'} @@ -1282,30 +743,9 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@jsonjoy.com/base64@1.1.2': - resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==} - engines: {node: '>=10.0'} - peerDependencies: - tslib: '2' - - '@jsonjoy.com/json-pack@1.2.0': - resolution: {integrity: sha512-io1zEbbYcElht3tdlqEOFxZ0dMTYrHz9iMf0gqn1pPjZFTCgM5R4R5IMA20Chb2UPYYsxjzs8CgZ7Nb5n2K2rA==} - engines: {node: '>=10.0'} - peerDependencies: - tslib: '2' - - '@jsonjoy.com/util@1.5.0': - resolution: {integrity: sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==} - engines: {node: '>=10.0'} - peerDependencies: - tslib: '2' - - '@leichtgewicht/ip-codec@2.0.5': - resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} - - '@listr2/prompt-adapter-inquirer@3.0.1': - resolution: {integrity: sha512-3XFmGwm3u6ioREG+ynAQB7FoxfajgQnMhIu8wC5eo/Lsih4aKDg0VuIMGaOsYn7hJSJagSeaD4K8yfpkEoDEmA==} - engines: {node: '>=20.0.0'} + '@listr2/prompt-adapter-inquirer@3.0.1': + resolution: {integrity: sha512-3XFmGwm3u6ioREG+ynAQB7FoxfajgQnMhIu8wC5eo/Lsih4aKDg0VuIMGaOsYn7hJSJagSeaD4K8yfpkEoDEmA==} + engines: {node: '>=20.0.0'} peerDependencies: '@inquirer/prompts': '>= 3 < 8' listr2: 9.0.1 @@ -1420,42 +860,49 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-arm64-musl@1.1.1': resolution: {integrity: sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@napi-rs/nice-linux-ppc64-gnu@1.1.1': resolution: {integrity: sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-riscv64-gnu@1.1.1': resolution: {integrity: sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-s390x-gnu@1.1.1': resolution: {integrity: sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-x64-gnu@1.1.1': resolution: {integrity: sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-x64-musl@1.1.1': resolution: {integrity: sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@napi-rs/nice-openharmony-arm64@1.1.1': resolution: {integrity: sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==} @@ -1488,26 +935,6 @@ packages: '@napi-rs/wasm-runtime@1.0.3': resolution: {integrity: sha512-rZxtMsLwjdXkMUGC3WwsPwLNVqVqnTJT6MNIB6e+5fhMcSCPP0AOsNWuMQ5mdCq6HNjs/ZeWAEchpqeprqBD2Q==} - '@ngtools/webpack@20.2.0': - resolution: {integrity: sha512-+oRNsB8RfmDd4Mnr8AyJwU3GUyXalQcI9r3Hoi4OSyFncWJeOnpTAWErx2JomqAYkm8WkE0PoRxKnD0RxKQ30Q==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - peerDependencies: - '@angular/compiler-cli': ^20.0.0 - typescript: '>=5.8 <6.0' - webpack: ^5.54.0 - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - '@npmcli/agent@3.0.0': resolution: {integrity: sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==} engines: {node: ^18.17.0 || >=20.5.0} @@ -1581,36 +1008,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.5.1': resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} @@ -1667,21 +1100,25 @@ packages: resolution: {integrity: sha512-hRZygRlaGCjcNTNY9GV7dDI18sG1dK3cc7ujHq72LoDad23zFDUGMQjiSxHWK+/r92iMV+j2MiHbvzayxqynsg==} cpu: [arm64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.0.0-beta.32': resolution: {integrity: sha512-HzgT6h+CXLs+GKAU0Wvkt3rvcv0CmDBsDjlPhh4GHysOKbG9NjpKYX2zvjx671E9pGbTvcPpwy7gGsy7xpu+8g==} cpu: [arm64] os: [linux] + libc: [musl] '@rolldown/binding-linux-x64-gnu@1.0.0-beta.32': resolution: {integrity: sha512-Ab/wbf6gdzphDbsg51UaxsC93foQ7wxhtg0SVCXd25BrV4MAJ1HoDtKN/f4h0maFmJobkqYub2DlmoasUzkvBg==} cpu: [x64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-x64-musl@1.0.0-beta.32': resolution: {integrity: sha512-VoxqGEfh5A1Yx+zBp/FR5QwAbtzbuvky2SVc+ii4g1gLD4zww6mt/hPi5zG+b88zYPFBKHpxMtsz9cWqXU5V5Q==} cpu: [x64] os: [linux] + libc: [musl] '@rolldown/binding-openharmony-arm64@1.0.0-beta.32': resolution: {integrity: sha512-qZ1ViyOUDGbiZrSAJ/FIAhYUElDfVxxFW6DLT/w4KeoZN3HsF4jmRP95mXtl51/oGrqzU9l9Q2f7/P4O/o2ZZA==} @@ -1745,56 +1182,67 @@ packages: resolution: {integrity: sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.50.0': resolution: {integrity: sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.50.0': resolution: {integrity: sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.50.0': resolution: {integrity: sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.50.0': resolution: {integrity: sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.50.0': resolution: {integrity: sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.50.0': resolution: {integrity: sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.50.0': resolution: {integrity: sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.50.0': resolution: {integrity: sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.50.0': resolution: {integrity: sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.50.0': resolution: {integrity: sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openharmony-arm64@4.50.0': resolution: {integrity: sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==} @@ -1820,15 +1268,6 @@ packages: resolution: {integrity: sha512-7sZVj7hOcytQrPE17ixjzul9ih81IfXGcEZvr7fT77qy7Hm5rbMjxqSYxCTf3kAyBFRSLq/E8GTapPAjk2coOg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@sideway/address@4.1.5': - resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} - - '@sideway/formula@3.0.1': - resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} - - '@sideway/pinpoint@2.0.0': - resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} - '@sigstore/bundle@3.1.0': resolution: {integrity: sha512-Mm1E3/CmDDCz3nDhFKTuYdB47EdRFRQMOE/EAbiG1MJW77/w1b3P7Qx7JSrVJs8PfwOLOVcKQCHErIwCTyPbag==} engines: {node: ^18.17.0 || >=20.5.0} @@ -1879,141 +1318,27 @@ packages: '@tybys/wasm-util@0.10.0': resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} - '@types/body-parser@1.19.5': - resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} - - '@types/bonjour@3.5.13': - resolution: {integrity: sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==} - - '@types/connect-history-api-fallback@1.5.4': - resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==} - - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - '@types/cors@2.8.17': resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} - '@types/eslint-scope@3.7.7': - resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} - - '@types/eslint@9.6.1': - resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} - '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/express-serve-static-core@4.19.6': - resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} - - '@types/express@4.17.21': - resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} - - '@types/http-errors@2.0.4': - resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} - - '@types/http-proxy@1.17.16': - resolution: {integrity: sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==} - '@types/jasmine@5.1.8': resolution: {integrity: sha512-u7/CnvRdh6AaaIzYjCgUuVbREFgulhX05Qtf6ZtW+aOcjCKKVvKgpkPYJBFTZSHtFBYimzU4zP0V2vrEsq9Wcg==} - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/mime@1.3.5': - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - - '@types/node-forge@1.3.11': - resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} - '@types/node@22.15.33': resolution: {integrity: sha512-wzoocdnnpSxZ+6CjW4ADCK1jVmd1S/J3ArNWfn8FDDQtRm8dkDg7TA+mvek2wNrfCgwuZxqEOiB9B1XCJ6+dbw==} - '@types/qs@6.9.18': - resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} - - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - - '@types/retry@0.12.2': - resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} - '@types/selenium-webdriver@3.0.26': resolution: {integrity: sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==} - '@types/send@0.17.4': - resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} - - '@types/serve-index@1.9.4': - resolution: {integrity: sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==} - - '@types/serve-static@1.15.7': - resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} - - '@types/sockjs@0.3.36': - resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} - - '@types/ws@8.18.1': - resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@vitejs/plugin-basic-ssl@2.1.0': resolution: {integrity: sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} peerDependencies: vite: ^6.0.0 || ^7.0.0 - '@webassemblyjs/ast@1.14.1': - resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} - - '@webassemblyjs/floating-point-hex-parser@1.13.2': - resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} - - '@webassemblyjs/helper-api-error@1.13.2': - resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} - - '@webassemblyjs/helper-buffer@1.14.1': - resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} - - '@webassemblyjs/helper-numbers@1.13.2': - resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} - - '@webassemblyjs/helper-wasm-bytecode@1.13.2': - resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} - - '@webassemblyjs/helper-wasm-section@1.14.1': - resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} - - '@webassemblyjs/ieee754@1.13.2': - resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} - - '@webassemblyjs/leb128@1.13.2': - resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} - - '@webassemblyjs/utf8@1.13.2': - resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} - - '@webassemblyjs/wasm-edit@1.14.1': - resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} - - '@webassemblyjs/wasm-gen@1.14.1': - resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} - - '@webassemblyjs/wasm-opt@1.14.1': - resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} - - '@webassemblyjs/wasm-parser@1.14.1': - resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} - - '@webassemblyjs/wast-printer@1.14.1': - resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} - - '@xtuc/ieee754@1.2.0': - resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} - - '@xtuc/long@4.2.2': - resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} @@ -2029,12 +1354,6 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} - acorn-import-phases@1.0.4: - resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} - engines: {node: '>=10.13.0'} - peerDependencies: - acorn: ^8.14.0 - acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -2049,22 +1368,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - adjust-sourcemap-loader@4.0.0: - resolution: {integrity: sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==} - engines: {node: '>=8.9'} - agent-base@7.1.3: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} - ajv-formats@2.1.1: - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -2073,11 +1380,6 @@ packages: ajv: optional: true - ajv-keywords@5.1.0: - resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} - peerDependencies: - ajv: ^8.8.2 - ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -2088,10 +1390,6 @@ packages: resolution: {integrity: sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg==} engines: {node: '>= 14.0.0'} - ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -2100,11 +1398,6 @@ packages: resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} engines: {node: '>=18'} - ansi-html-community@0.0.8: - resolution: {integrity: sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==} - engines: {'0': node >= 0.8.0} - hasBin: true - ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2132,47 +1425,6 @@ packages: arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - autoprefixer@10.4.21: - resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - - axios@1.9.0: - resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} - - babel-loader@10.0.0: - resolution: {integrity: sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA==} - engines: {node: ^18.20.0 || ^20.10.0 || >=22.0.0} - peerDependencies: - '@babel/core': ^7.12.0 - webpack: '>=5.61.0' - - babel-plugin-polyfill-corejs2@0.4.14: - resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - babel-plugin-polyfill-corejs3@0.13.0: - resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - babel-plugin-polyfill-regenerator@0.6.5: - resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2180,16 +1432,10 @@ packages: resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} engines: {node: ^4.5.0 || >= 5.9} - batch@0.6.1: - resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} - beasties@0.3.5: resolution: {integrity: sha512-NaWu+f4YrJxEttJSm16AzMIFtVldCvaJ68b1L098KpqXmxt9xOLtKoLkKxb8ekhOrLqEJAbvT6n6SEvB/sac7A==} engines: {node: '>=14.0.0'} - big.js@5.2.2: - resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -2202,9 +1448,6 @@ packages: resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} engines: {node: '>=18'} - bonjour-service@1.3.0: - resolution: {integrity: sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==} - boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -2231,10 +1474,6 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - bundle-name@4.1.0: - resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} - engines: {node: '>=18'} - bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -2251,10 +1490,6 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - caniuse-lite@1.0.30001713: resolution: {integrity: sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q==} @@ -2288,10 +1523,6 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} - chrome-trace-event@1.0.4: - resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} - engines: {node: '>=6.0'} - cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -2319,10 +1550,6 @@ packages: resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} engines: {node: '>=20'} - clone-deep@4.0.1: - resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} - engines: {node: '>=6'} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -2333,21 +1560,9 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - compressible@2.0.18: - resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} - engines: {node: '>= 0.6'} - - compression@1.8.0: - resolution: {integrity: sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==} - engines: {node: '>= 0.8.0'} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -2356,18 +1571,10 @@ packages: engines: {node: '>=18'} hasBin: true - connect-history-api-fallback@2.0.0: - resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} - engines: {node: '>=0.8'} - connect@3.7.0: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} engines: {node: '>= 0.10.0'} - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - content-disposition@1.0.0: resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} engines: {node: '>= 0.6'} @@ -2382,17 +1589,10 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} - engines: {node: '>= 0.6'} - cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} @@ -2400,15 +1600,6 @@ packages: copy-anything@2.0.6: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} - copy-webpack-plugin@13.0.1: - resolution: {integrity: sha512-J+YV3WfhY6W/Xf9h+J1znYuqTye2xkBUIGyTPWuBAT27qajBa5mR4f8WBmfDY3YjRftT2kqZZiLi1qf0H+UOFw==} - engines: {node: '>= 18.12.0'} - peerDependencies: - webpack: ^5.1.0 - - core-js-compat@3.45.1: - resolution: {integrity: sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==} - core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -2416,15 +1607,6 @@ packages: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} - cosmiconfig@9.0.0: - resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true - create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -2432,18 +1614,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - css-loader@7.1.2: - resolution: {integrity: sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==} - engines: {node: '>= 18.12.0'} - peerDependencies: - '@rspack/core': 0.x || 1.x - webpack: ^5.27.0 - peerDependenciesMeta: - '@rspack/core': - optional: true - webpack: - optional: true - css-select@6.0.0: resolution: {integrity: sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==} @@ -2451,11 +1621,6 @@ packages: resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} engines: {node: '>= 6'} - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - custom-event@1.0.1: resolution: {integrity: sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==} @@ -2498,26 +1663,6 @@ packages: supports-color: optional: true - default-browser-id@5.0.0: - resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} - engines: {node: '>=18'} - - default-browser@5.2.1: - resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} - engines: {node: '>=18'} - - define-lazy-prop@3.0.0: - resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} - engines: {node: '>=12'} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - depd@1.1.2: - resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} - engines: {node: '>= 0.6'} - depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -2535,9 +1680,6 @@ packages: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} - detect-node@2.1.0: - resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} - di@0.0.1: resolution: {integrity: sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==} @@ -2545,10 +1687,6 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} - dns-packet@5.6.1: - resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} - engines: {node: '>=6'} - dom-serialize@2.2.1: resolution: {integrity: sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==} @@ -2590,10 +1728,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - emojis-list@3.0.0: - resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} - engines: {node: '>= 4'} - encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -2613,10 +1747,6 @@ packages: resolution: {integrity: sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==} engines: {node: '>=10.2.0'} - enhanced-resolve@5.18.1: - resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} - engines: {node: '>=10.13.0'} - ent@2.2.2: resolution: {integrity: sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==} engines: {node: '>= 0.4'} @@ -2644,9 +1774,6 @@ packages: resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} hasBin: true - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -2655,22 +1782,10 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.6.0: - resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} - es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - esbuild-wasm@0.25.9: - resolution: {integrity: sha512-Jpv5tCSwQg18aCqCRD3oHIX/prBhXMDapIoG//A+6+dV0e7KQMGFg85ihJ5T1EeMjbZjON3TqFy0VrGAnIHLDA==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.25.9: resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} engines: {node: '>=18'} @@ -2683,26 +1798,6 @@ packages: escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} @@ -2713,10 +1808,6 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - eventsource-parser@3.0.6: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} @@ -2734,10 +1825,6 @@ packages: peerDependencies: express: '>= 4.11' - express@4.21.2: - resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} - engines: {node: '>= 0.10.0'} - express@5.1.0: resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} engines: {node: '>= 18'} @@ -2748,23 +1835,12 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} - - faye-websocket@0.11.4: - resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} - engines: {node: '>=0.8.0'} - fdir@6.4.4: resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} peerDependencies: @@ -2790,22 +1866,10 @@ packages: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} engines: {node: '>= 0.8'} - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} - engines: {node: '>= 0.8'} - finalhandler@2.1.0: resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} engines: {node: '>= 0.8'} - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} @@ -2822,21 +1886,10 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data@4.0.2: - resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} - engines: {node: '>= 6'} - forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - fresh@2.0.0: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} @@ -2888,10 +1941,6 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} @@ -2914,9 +1963,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - handle-thing@2.0.1: - resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -2941,49 +1987,20 @@ packages: resolution: {integrity: sha512-gEf705MZLrDPkbbhi8PnoO4ZwYgKoNL+ISZ3AjZMht2r3N5tuTwncyDi6Fv2/qDnMmZxgs0yI8WDOyR8q3G+SQ==} engines: {node: ^20.17.0 || >=22.9.0} - hpack.js@2.1.6: - resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} - - html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - htmlparser2@10.0.0: resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} - http-deceiver@1.2.7: - resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} - - http-errors@1.6.3: - resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} - engines: {node: '>= 0.6'} - http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} - http-parser-js@0.5.10: - resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} - http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} - http-proxy-middleware@2.0.9: - resolution: {integrity: sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@types/express': ^4.17.13 - peerDependenciesMeta: - '@types/express': - optional: true - - http-proxy-middleware@3.0.5: - resolution: {integrity: sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - http-proxy@1.18.1: resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} engines: {node: '>=8.0.0'} @@ -2992,10 +2009,6 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - hyperdyperid@1.2.0: - resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==} - engines: {node: '>=10.18'} - iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -3008,12 +2021,6 @@ packages: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} - icss-utils@5.1.0: - resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - ignore-walk@7.0.0: resolution: {integrity: sha512-T4gbf83A4NH95zvhVYZc+qWocBBGlpzUXLPGurJggw/WIOwicfXJChLDP/iBZnN5WqROSu5Bm3hhle4z8a8YGQ==} engines: {node: ^18.17.0 || >=20.5.0} @@ -3029,10 +2036,6 @@ packages: immutable@5.1.1: resolution: {integrity: sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==} - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -3041,9 +2044,6 @@ packages: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.3: - resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -3059,13 +2059,6 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - ipaddr.js@2.2.0: - resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} - engines: {node: '>= 10'} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -3074,11 +2067,6 @@ packages: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} - is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -3099,35 +2087,14 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true - is-interactive@2.0.0: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} - is-network-error@1.1.0: - resolution: {integrity: sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==} - engines: {node: '>=16'} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-plain-obj@3.0.0: - resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==} - engines: {node: '>=10'} - - is-plain-object@2.0.4: - resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} - engines: {node: '>=0.10.0'} - - is-plain-object@5.0.0: - resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} - engines: {node: '>=0.10.0'} - is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -3146,10 +2113,6 @@ packages: is-what@3.14.1: resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} - is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} - engines: {node: '>=16'} - isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -3164,40 +2127,17 @@ packages: resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} engines: {node: '>=16'} - isobject@3.0.1: - resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} - engines: {node: '>=0.10.0'} - istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} - istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - istanbul-lib-instrument@6.0.3: resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} engines: {node: '>=10'} - istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} - - istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - - istanbul-reports@3.1.7: - resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} - engines: {node: '>=8'} - jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jasmine-core@3.99.1: - resolution: {integrity: sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==} - jasmine-core@5.8.0: resolution: {integrity: sha512-Q9dqmpUAfptwyueW3+HqBOkSuYd9I/clZSSfN97wXE/Nr2ROFNCwIBEC1F6kb3QXS9Fcz0LjFYSDQT+BiwjuhA==} @@ -3205,40 +2145,21 @@ packages: resolution: {integrity: sha512-1V6HGa0+TMoMY20+/vp++RqLlL1noupV8awzV6CiPuICC0g7iKZ9z87zV2KyelRyoig0G1lHn7ueElXVMGVagg==} hasBin: true - jest-worker@27.5.1: - resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} - engines: {node: '>= 10.13.0'} - jiti@1.21.7: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true - joi@17.13.3: - resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - jsbn@1.1.0: resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - jsesc@3.0.2: - resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} - engines: {node: '>=6'} - hasBin: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} hasBin: true - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-parse-even-better-errors@4.0.0: resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -3267,73 +2188,19 @@ packages: jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} - karma-chrome-launcher@3.2.0: - resolution: {integrity: sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==} - - karma-coverage@2.2.1: - resolution: {integrity: sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==} - engines: {node: '>=10.0.0'} - - karma-jasmine-html-reporter@2.1.0: - resolution: {integrity: sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==} - peerDependencies: - jasmine-core: ^4.0.0 || ^5.0.0 - karma: ^6.0.0 - karma-jasmine: ^5.0.0 - - karma-jasmine@4.0.2: - resolution: {integrity: sha512-ggi84RMNQffSDmWSyyt4zxzh2CQGwsxvYYsprgyR1j8ikzIduEdOlcLvXjZGwXG/0j41KUXOWsUCBfbEHPWP9g==} - engines: {node: '>= 10'} - peerDependencies: - karma: '*' - - karma-source-map-support@1.4.0: - resolution: {integrity: sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==} - karma@6.4.4: resolution: {integrity: sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==} engines: {node: '>= 10'} hasBin: true - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - - launch-editor@2.10.0: - resolution: {integrity: sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==} - - less-loader@12.3.0: - resolution: {integrity: sha512-0M6+uYulvYIWs52y0LqN4+QM9TqWAohYSNTo4htE8Z7Cn3G/qQMEmktfHmyJT23k+20kU9zHH2wrfFXkxNLtVw==} - engines: {node: '>= 18.12.0'} - peerDependencies: - '@rspack/core': 0.x || 1.x - less: ^3.5.0 || ^4.0.0 - webpack: ^5.0.0 - peerDependenciesMeta: - '@rspack/core': - optional: true - webpack: - optional: true - - less@4.4.0: - resolution: {integrity: sha512-kdTwsyRuncDfjEs0DlRILWNvxhDG/Zij4YLO4TMJgDLW+8OzpfkdPnRgrsRuY1o+oaxJGWsps5f/RVBgGmmN0w==} - engines: {node: '>=14'} - hasBin: true - - license-webpack-plugin@4.0.2: - resolution: {integrity: sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==} - peerDependencies: - webpack: '*' - peerDependenciesMeta: - webpack: - optional: true + less@4.4.0: + resolution: {integrity: sha512-kdTwsyRuncDfjEs0DlRILWNvxhDG/Zij4YLO4TMJgDLW+8OzpfkdPnRgrsRuY1o+oaxJGWsps5f/RVBgGmmN0w==} + engines: {node: '>=14'} + hasBin: true lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - listr2@9.0.1: resolution: {integrity: sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==} engines: {node: '>=20.0.0'} @@ -3342,25 +2209,6 @@ packages: resolution: {integrity: sha512-nwVGUfTBUwJKXd6lRV8pFNfnrCC1+l49ESJRM19t/tFb/97QfJEixe5DYRvug5JO7DSFKoKaVy7oGMt5rVqZvg==} hasBin: true - loader-runner@4.3.0: - resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} - engines: {node: '>=6.11.5'} - - loader-utils@2.0.4: - resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} - engines: {node: '>=8.9.0'} - - loader-utils@3.3.1: - resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} - engines: {node: '>= 12.13.0'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.debounce@4.0.8: - resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -3393,10 +2241,6 @@ packages: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} - make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} - make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} @@ -3416,28 +2260,10 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} - memfs@4.17.0: - resolution: {integrity: sha512-4eirfZ7thblFmqFjywlTmuWVSvccHAJbn1r8qQLzmTO11qcqpohOjmY2mFce6x7x7WtskzRqApPD0hv+Oa74jg==} - engines: {node: '>= 4.0.0'} - - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -3472,15 +2298,6 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - mini-css-extract-plugin@2.9.4: - resolution: {integrity: sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ==} - engines: {node: '>= 12.13.0'} - peerDependencies: - webpack: ^5.0.0 - - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -3562,10 +2379,6 @@ packages: msgpackr@1.11.2: resolution: {integrity: sha512-F9UngXRlPyWCDEASDpTf6c9uNhGPTqnTeLVt7bN+bU1eajoR/8V9ys2BRaV5C/e5ihE6sJ9uPIKaYt6bFuO32g==} - multicast-dns@7.2.5: - resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} - hasBin: true - mute-stream@2.0.0: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -3584,27 +2397,16 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} - neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - node-addon-api@6.1.0: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-forge@1.3.1: - resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} - engines: {node: '>= 6.13.0'} - node-gyp-build-optional-packages@5.2.2: resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} hasBin: true @@ -3626,10 +2428,6 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - npm-bundled@4.0.0: resolution: {integrity: sha512-IxaQZDMsqfQ2Lz37VvyyEtKLe8FsRZuysmedy/N06TU1RyVppYKXrO4xIhR0F+7ubIBox6Q7nir6fQI3ej39iA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -3673,9 +2471,6 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} - obuf@1.1.2: - resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - on-finished@2.3.0: resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} engines: {node: '>= 0.8'} @@ -3684,10 +2479,6 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} - on-headers@1.0.2: - resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -3695,10 +2486,6 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} - open@10.2.0: - resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} - engines: {node: '>=18'} - ora@8.2.0: resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} engines: {node: '>=18'} @@ -3710,22 +2497,10 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - p-map@7.0.3: resolution: {integrity: sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==} engines: {node: '>=18'} - p-retry@6.2.1: - resolution: {integrity: sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==} - engines: {node: '>=16.17'} - package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -3737,14 +2512,6 @@ packages: pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - parse-node-version@1.0.1: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} @@ -3765,10 +2532,6 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -3784,9 +2547,6 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -3813,53 +2573,9 @@ packages: resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} engines: {node: '>=16.20.0'} - postcss-loader@8.1.1: - resolution: {integrity: sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==} - engines: {node: '>= 18.12.0'} - peerDependencies: - '@rspack/core': 0.x || 1.x - postcss: ^7.0.0 || ^8.0.1 - webpack: ^5.0.0 - peerDependenciesMeta: - '@rspack/core': - optional: true - webpack: - optional: true - postcss-media-query-parser@0.2.3: resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==} - postcss-modules-extract-imports@3.1.0: - resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - - postcss-modules-local-by-default@4.2.0: - resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - - postcss-modules-scope@3.2.1: - resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - - postcss-modules-values@4.0.0: - resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - - postcss-selector-parser@7.1.0: - resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} - engines: {node: '>=4'} - - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -3879,9 +2595,6 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} @@ -3904,12 +2617,6 @@ packages: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -3925,10 +2632,6 @@ packages: readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -3940,27 +2643,6 @@ packages: reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} - regenerate-unicode-properties@10.2.0: - resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} - engines: {node: '>=4'} - - regenerate@1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} - - regex-parser@2.3.1: - resolution: {integrity: sha512-yXLRqatcCuKtVHsWrNg0JL3l1zGfdXeEvDa0bdu4tCDQw0RpMDZsqbkyRTUnKMR0tXF627V2oEWjBEaEdqTwtQ==} - - regexpu-core@6.2.0: - resolution: {integrity: sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==} - engines: {node: '>=4'} - - regjsgen@0.8.0: - resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - - regjsparser@0.12.0: - resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} - hasBin: true - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -3972,14 +2654,6 @@ packages: requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve-url-loader@5.0.0: - resolution: {integrity: sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==} - engines: {node: '>=12'} - resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} @@ -3993,14 +2667,6 @@ packages: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} - retry@0.13.1: - resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} - engines: {node: '>= 4'} - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} @@ -4027,13 +2693,6 @@ packages: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} - run-applescript@7.0.0: - resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} - engines: {node: '>=18'} - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -4050,27 +2709,6 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass-loader@16.0.5: - resolution: {integrity: sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==} - engines: {node: '>= 18.12.0'} - peerDependencies: - '@rspack/core': 0.x || 1.x - node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - sass: ^1.3.0 - sass-embedded: '*' - webpack: ^5.0.0 - peerDependenciesMeta: - '@rspack/core': - optional: true - node-sass: - optional: true - sass: - optional: true - sass-embedded: - optional: true - webpack: - optional: true - sass@1.90.0: resolution: {integrity: sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==} engines: {node: '>=14.0.0'} @@ -4079,21 +2717,10 @@ packages: sax@1.4.1: resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} - schema-utils@4.3.2: - resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} - engines: {node: '>= 10.13.0'} - - select-hose@2.0.0: - resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} - selenium-webdriver@3.6.0: resolution: {integrity: sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==} engines: {node: '>= 6.9.0'} - selfsigned@2.4.1: - resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} - engines: {node: '>=10'} - semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -4107,25 +2734,10 @@ packages: engines: {node: '>=10'} hasBin: true - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - send@1.2.0: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - - serve-index@1.9.1: - resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} - engines: {node: '>= 0.8.0'} - - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} - serve-static@2.2.0: resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} engines: {node: '>= 18'} @@ -4133,16 +2745,9 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - setprototypeof@1.1.0: - resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} - setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shallow-clone@3.0.1: - resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} - engines: {node: '>=8'} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -4202,9 +2807,6 @@ packages: resolution: {integrity: sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==} engines: {node: '>=10.2.0'} - sockjs@0.3.24: - resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} - socks-proxy-agent@8.0.5: resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} engines: {node: '>= 14'} @@ -4217,12 +2819,6 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map-loader@5.0.0: - resolution: {integrity: sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==} - engines: {node: '>= 18.12.0'} - peerDependencies: - webpack: ^5.72.1 - source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -4246,13 +2842,6 @@ packages: spdx-license-ids@3.0.21: resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} - spdy-transport@3.0.0: - resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} - - spdy@4.0.2: - resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} - engines: {node: '>=6.0.0'} - sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} @@ -4291,9 +2880,6 @@ packages: string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -4314,10 +2900,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} - engines: {node: '>=6'} - tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} @@ -4326,36 +2908,11 @@ packages: resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} engines: {node: '>=18'} - terser-webpack-plugin@5.3.14: - resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@swc/core': '*' - esbuild: '*' - uglify-js: '*' - webpack: ^5.1.0 - peerDependenciesMeta: - '@swc/core': - optional: true - esbuild: - optional: true - uglify-js: - optional: true - terser@5.43.1: resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==} engines: {node: '>=10'} hasBin: true - thingies@1.21.0: - resolution: {integrity: sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==} - engines: {node: '>=10.18'} - peerDependencies: - tslib: ^2 - - thunky@1.1.0: - resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} - tinyglobby@0.2.13: resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} engines: {node: '>=12.0.0'} @@ -4380,12 +2937,6 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - tree-dump@1.0.2: - resolution: {integrity: sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==} - engines: {node: '>=10.0'} - peerDependencies: - tslib: '2' - tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -4423,9 +2974,6 @@ packages: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} - typed-assert@1.0.9: - resolution: {integrity: sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==} - typescript@5.8.3: resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} @@ -4438,22 +2986,6 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - unicode-canonical-property-names-ecmascript@2.0.1: - resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} - engines: {node: '>=4'} - - unicode-match-property-ecmascript@2.0.0: - resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} - engines: {node: '>=4'} - - unicode-match-property-value-ecmascript@2.2.0: - resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} - engines: {node: '>=4'} - - unicode-property-aliases-ecmascript@2.1.0: - resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} - engines: {node: '>=4'} - unique-filename@4.0.0: resolution: {integrity: sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==} engines: {node: ^18.17.0 || >=20.5.0} @@ -4486,10 +3018,6 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -4548,91 +3076,13 @@ packages: resolution: {integrity: sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==} engines: {node: '>=0.10.0'} - wait-on@8.0.3: - resolution: {integrity: sha512-nQFqAFzZDeRxsu7S3C7LbuxslHhk+gnJZHyethuGKAn2IVleIbTB9I3vJSQiSR+DifUqmdzfPMoMPJfLqMF2vw==} - engines: {node: '>=12.0.0'} - hasBin: true - - watchpack@2.4.2: - resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} - engines: {node: '>=10.13.0'} - watchpack@2.4.4: resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} engines: {node: '>=10.13.0'} - wbuf@1.7.3: - resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} - weak-lru-cache@1.2.2: resolution: {integrity: sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==} - webpack-dev-middleware@7.4.2: - resolution: {integrity: sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==} - engines: {node: '>= 18.12.0'} - peerDependencies: - webpack: ^5.0.0 - peerDependenciesMeta: - webpack: - optional: true - - webpack-dev-server@5.2.2: - resolution: {integrity: sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==} - engines: {node: '>= 18.12.0'} - hasBin: true - peerDependencies: - webpack: ^5.0.0 - webpack-cli: '*' - peerDependenciesMeta: - webpack: - optional: true - webpack-cli: - optional: true - - webpack-merge@6.0.1: - resolution: {integrity: sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==} - engines: {node: '>=18.0.0'} - - webpack-sources@3.2.3: - resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} - engines: {node: '>=10.13.0'} - - webpack-sources@3.3.3: - resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} - engines: {node: '>=10.13.0'} - - webpack-subresource-integrity@5.1.0: - resolution: {integrity: sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==} - engines: {node: '>= 12'} - peerDependencies: - html-webpack-plugin: '>= 5.0.0-beta.1 < 6' - webpack: ^5.12.0 - peerDependenciesMeta: - html-webpack-plugin: - optional: true - - webpack@5.101.2: - resolution: {integrity: sha512-4JLXU0tD6OZNVqlwzm3HGEhAHufSiyv+skb7q0d2367VDMzrU1Q/ZeepvkcHH0rZie6uqEtTQQe0OEOOluH3Mg==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - - websocket-driver@0.7.4: - resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} - engines: {node: '>=0.8.0'} - - websocket-extensions@0.1.4: - resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} - engines: {node: '>=0.8.0'} - - which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -4643,9 +3093,6 @@ packages: engines: {node: ^18.17.0 || >=20.5.0} hasBin: true - wildcard@2.0.1: - resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} - wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -4677,22 +3124,6 @@ packages: utf-8-validate: optional: true - ws@8.18.1: - resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - wsl-utils@0.1.0: - resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} - engines: {node: '>=18'} - xml2js@0.4.23: resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} engines: {node: '>=4.0.0'} @@ -4743,10 +3174,6 @@ packages: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - yoctocolors-cjs@2.1.2: resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} engines: {node: '>=18'} @@ -4860,101 +3287,6 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@20.2.0(@angular/compiler-cli@20.2.0(@angular/compiler@20.2.0)(typescript@5.8.3))(@angular/compiler@20.2.0)(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@types/node@22.15.33)(chokidar@4.0.3)(jiti@1.21.7)(karma@6.4.4)(typescript@5.8.3)': - dependencies: - '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2002.0(chokidar@4.0.3) - '@angular-devkit/build-webpack': 0.2002.0(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.101.2))(webpack@5.101.2(esbuild@0.25.9)) - '@angular-devkit/core': 20.2.0(chokidar@4.0.3) - '@angular/build': 20.2.0(@angular/compiler-cli@20.2.0(@angular/compiler@20.2.0)(typescript@5.8.3))(@angular/compiler@20.2.0)(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@types/node@22.15.33)(chokidar@4.0.3)(jiti@1.21.7)(karma@6.4.4)(less@4.4.0)(postcss@8.5.6)(terser@5.43.1)(tslib@2.8.1)(typescript@5.8.3) - '@angular/compiler-cli': 20.2.0(@angular/compiler@20.2.0)(typescript@5.8.3) - '@babel/core': 7.28.3 - '@babel/generator': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-split-export-declaration': 7.24.7 - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-runtime': 7.28.3(@babel/core@7.28.3) - '@babel/preset-env': 7.28.3(@babel/core@7.28.3) - '@babel/runtime': 7.28.3 - '@discoveryjs/json-ext': 0.6.3 - '@ngtools/webpack': 20.2.0(@angular/compiler-cli@20.2.0(@angular/compiler@20.2.0)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.101.2(esbuild@0.25.9)) - ansi-colors: 4.1.3 - autoprefixer: 10.4.21(postcss@8.5.6) - babel-loader: 10.0.0(@babel/core@7.28.3)(webpack@5.101.2(esbuild@0.25.9)) - browserslist: 4.24.4 - copy-webpack-plugin: 13.0.1(webpack@5.101.2(esbuild@0.25.9)) - css-loader: 7.1.2(webpack@5.101.2(esbuild@0.25.9)) - esbuild-wasm: 0.25.9 - fast-glob: 3.3.3 - http-proxy-middleware: 3.0.5 - istanbul-lib-instrument: 6.0.3 - jsonc-parser: 3.3.1 - karma-source-map-support: 1.4.0 - less: 4.4.0 - less-loader: 12.3.0(less@4.4.0)(webpack@5.101.2(esbuild@0.25.9)) - license-webpack-plugin: 4.0.2(webpack@5.101.2(esbuild@0.25.9)) - loader-utils: 3.3.1 - mini-css-extract-plugin: 2.9.4(webpack@5.101.2(esbuild@0.25.9)) - open: 10.2.0 - ora: 8.2.0 - picomatch: 4.0.3 - piscina: 5.1.3 - postcss: 8.5.6 - postcss-loader: 8.1.1(postcss@8.5.6)(typescript@5.8.3)(webpack@5.101.2(esbuild@0.25.9)) - resolve-url-loader: 5.0.0 - rxjs: 7.8.2 - sass: 1.90.0 - sass-loader: 16.0.5(sass@1.90.0)(webpack@5.101.2(esbuild@0.25.9)) - semver: 7.7.2 - source-map-loader: 5.0.0(webpack@5.101.2(esbuild@0.25.9)) - source-map-support: 0.5.21 - terser: 5.43.1 - tree-kill: 1.2.2 - tslib: 2.8.1 - typescript: 5.8.3 - webpack: 5.101.2(esbuild@0.25.9) - webpack-dev-middleware: 7.4.2(webpack@5.101.2) - webpack-dev-server: 5.2.2(webpack@5.101.2) - webpack-merge: 6.0.1 - webpack-subresource-integrity: 5.1.0(webpack@5.101.2(esbuild@0.25.9)) - optionalDependencies: - '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) - '@angular/platform-browser': 20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) - esbuild: 0.25.9 - karma: 6.4.4 - transitivePeerDependencies: - - '@angular/compiler' - - '@rspack/core' - - '@swc/core' - - '@types/node' - - bufferutil - - chokidar - - debug - - html-webpack-plugin - - jiti - - lightningcss - - node-sass - - sass-embedded - - stylus - - sugarss - - supports-color - - tsx - - uglify-js - - utf-8-validate - - vitest - - webpack-cli - - yaml - - '@angular-devkit/build-webpack@0.2002.0(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.101.2))(webpack@5.101.2(esbuild@0.25.9))': - dependencies: - '@angular-devkit/architect': 0.2002.0(chokidar@4.0.3) - rxjs: 7.8.2 - webpack: 5.101.2(esbuild@0.25.9) - webpack-dev-server: 5.2.2(webpack@5.101.2) - transitivePeerDependencies: - - chokidar - '@angular-devkit/core@20.2.0(chokidar@4.0.3)': dependencies: ajv: 8.17.1 @@ -4995,7 +3327,7 @@ snapshots: '@inquirer/confirm': 5.1.14(@types/node@22.15.33) '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.1.2(@types/node@22.15.33)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)) beasties: 0.3.5 - browserslist: 4.24.4 + browserslist: 4.25.4 esbuild: 0.25.9 https-proxy-agent: 7.0.6 istanbul-lib-instrument: 6.0.3 @@ -5017,841 +3349,221 @@ snapshots: watchpack: 2.4.4 optionalDependencies: '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) - '@angular/platform-browser': 20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) - karma: 6.4.4 - less: 4.4.0 - lmdb: 3.4.2 - postcss: 8.5.6 - transitivePeerDependencies: - - '@types/node' - - chokidar - - jiti - - lightningcss - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - '@angular/cdk@20.1.0-next.1(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)': - dependencies: - '@angular/common': 20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) - '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) - parse5: 7.2.1 - rxjs: 7.8.2 - tslib: 2.8.1 - - '@angular/cli@20.2.0(@types/node@22.15.33)(chokidar@4.0.3)': - dependencies: - '@angular-devkit/architect': 0.2002.0(chokidar@4.0.3) - '@angular-devkit/core': 20.2.0(chokidar@4.0.3) - '@angular-devkit/schematics': 20.2.0(chokidar@4.0.3) - '@inquirer/prompts': 7.8.2(@types/node@22.15.33) - '@listr2/prompt-adapter-inquirer': 3.0.1(@inquirer/prompts@7.8.2(@types/node@22.15.33))(@types/node@22.15.33)(listr2@9.0.1) - '@modelcontextprotocol/sdk': 1.17.3 - '@schematics/angular': 20.2.0(chokidar@4.0.3) - '@yarnpkg/lockfile': 1.1.0 - algoliasearch: 5.35.0 - ini: 5.0.0 - jsonc-parser: 3.3.1 - listr2: 9.0.1 - npm-package-arg: 13.0.0 - pacote: 21.0.0 - resolve: 1.22.10 - semver: 7.7.2 - yargs: 18.0.0 - zod: 3.25.76 - transitivePeerDependencies: - - '@types/node' - - chokidar - - supports-color - - '@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)': - dependencies: - '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) - rxjs: 7.8.2 - tslib: 2.8.1 - - '@angular/compiler-cli@20.2.0(@angular/compiler@20.2.0)(typescript@5.8.3)': - dependencies: - '@angular/compiler': 20.2.0 - '@babel/core': 7.28.3 - '@jridgewell/sourcemap-codec': 1.5.0 - chokidar: 4.0.3 - convert-source-map: 1.9.0 - reflect-metadata: 0.2.2 - semver: 7.7.2 - tslib: 2.8.1 - yargs: 18.0.0 - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@angular/compiler@20.2.0': - dependencies: - tslib: 2.8.1 - - '@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)': - dependencies: - rxjs: 7.8.2 - tslib: 2.8.1 - optionalDependencies: - '@angular/compiler': 20.2.0 - zone.js: 0.15.0 - - '@angular/forms@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2)': - dependencies: - '@angular/common': 20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) - '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) - '@angular/platform-browser': 20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) - rxjs: 7.8.2 - tslib: 2.8.1 - - '@angular/material@20.1.0-next.1(e3f61fe28cd1f106fd36f2f00f317744)': - dependencies: - '@angular/cdk': 20.1.0-next.1(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) - '@angular/common': 20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) - '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) - '@angular/forms': 20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2) - '@angular/platform-browser': 20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) - rxjs: 7.8.2 - tslib: 2.8.1 - - '@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))': - dependencies: - '@angular/common': 20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) - '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) - tslib: 2.8.1 - optionalDependencies: - '@angular/animations': 20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) - - '@angular/router@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2)': - dependencies: - '@angular/common': 20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) - '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) - '@angular/platform-browser': 20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) - rxjs: 7.8.2 - tslib: 2.8.1 - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.27.2': {} - - '@babel/compat-data@7.28.0': {} - - '@babel/core@7.27.1': - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.27.1 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1) - '@babel/helpers': 7.27.1 - '@babel/parser': 7.27.2 - '@babel/template': 7.27.2 - '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 - convert-source-map: 2.0.0 - debug: 4.4.0 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/core@7.28.3': - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) - '@babel/helpers': 7.28.3 - '@babel/parser': 7.28.3 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - convert-source-map: 2.0.0 - debug: 4.4.0 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.27.1': - dependencies: - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 3.1.0 - - '@babel/generator@7.28.3': - dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 - jsesc: 3.1.0 - - '@babel/helper-annotate-as-pure@7.27.3': - dependencies: - '@babel/types': 7.28.2 - - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.27.2 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.24.4 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-create-class-features-plugin@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.27.1 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - regexpu-core: 6.2.0 - semver: 6.3.1 - - '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.1 - lodash.debounce: 4.0.8 - resolve: 1.22.10 - transitivePeerDependencies: - - supports-color - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-member-expression-to-functions@7.27.1': - dependencies: - '@babel/traverse': 7.28.3 - '@babel/types': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1)': - dependencies: - '@babel/core': 7.27.1 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/helper-optimise-call-expression@7.27.1': - dependencies: - '@babel/types': 7.27.1 - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-wrap-function': 7.27.1 - '@babel/traverse': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - dependencies: - '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-split-export-declaration@7.24.7': - dependencies: - '@babel/types': 7.27.1 - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.27.1': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helper-wrap-function@7.27.1': - dependencies: - '@babel/template': 7.27.2 - '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/helpers@7.27.1': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.27.1 - - '@babel/helpers@7.28.3': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.2 - - '@babel/parser@7.27.2': - dependencies: - '@babel/types': 7.27.1 - - '@babel/parser@7.28.3': - dependencies: - '@babel/types': 7.28.2 - - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - - '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.3) - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-block-scoping@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-classes@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-globals': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/template': 7.27.2 - - '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-exponentiation-operator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.27.1 + '@angular/platform-browser': 20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) + karma: 6.4.4 + less: 4.4.0 + lmdb: 3.4.2 + postcss: 8.5.6 transitivePeerDependencies: + - '@types/node' + - chokidar + - jiti + - lightningcss + - sass-embedded + - stylus + - sugarss - supports-color + - terser + - tsx + - yaml - '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.3)': + '@angular/cdk@20.1.0-next.1(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-transforms': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + '@angular/common': 20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) + '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) + parse5: 7.2.1 + rxjs: 7.8.2 + tslib: 2.8.1 - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.3)': + '@angular/cli@20.2.0(@types/node@22.15.33)(chokidar@4.0.3)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-transforms': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@angular-devkit/architect': 0.2002.0(chokidar@4.0.3) + '@angular-devkit/core': 20.2.0(chokidar@4.0.3) + '@angular-devkit/schematics': 20.2.0(chokidar@4.0.3) + '@inquirer/prompts': 7.8.2(@types/node@22.15.33) + '@listr2/prompt-adapter-inquirer': 3.0.1(@inquirer/prompts@7.8.2(@types/node@22.15.33))(@types/node@22.15.33)(listr2@9.0.1) + '@modelcontextprotocol/sdk': 1.17.3 + '@schematics/angular': 20.2.0(chokidar@4.0.3) + '@yarnpkg/lockfile': 1.1.0 + algoliasearch: 5.35.0 + ini: 5.0.0 + jsonc-parser: 3.3.1 + listr2: 9.0.1 + npm-package-arg: 13.0.0 + pacote: 21.0.0 + resolve: 1.22.10 + semver: 7.7.2 + yargs: 18.0.0 + zod: 3.25.76 transitivePeerDependencies: + - '@types/node' + - chokidar - supports-color - '@babel/plugin-transform-modules-systemjs@7.27.1(@babel/core@7.28.3)': + '@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-transforms': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.27.1 - transitivePeerDependencies: - - supports-color + '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) + rxjs: 7.8.2 + tslib: 2.8.1 - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.3)': + '@angular/compiler-cli@20.2.0(@angular/compiler@20.2.0)(typescript@5.8.3)': dependencies: + '@angular/compiler': 20.2.0 '@babel/core': 7.28.3 - '@babel/helper-module-transforms': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@jridgewell/sourcemap-codec': 1.5.0 + chokidar: 4.0.3 + convert-source-map: 1.9.0 + reflect-metadata: 0.2.2 + semver: 7.7.2 + tslib: 2.8.1 + yargs: 18.0.0 + optionalDependencies: + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.3)': + '@angular/compiler@20.2.0': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + tslib: 2.8.1 - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.3)': + '@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + rxjs: 7.8.2 + tslib: 2.8.1 + optionalDependencies: + '@angular/compiler': 20.2.0 + zone.js: 0.15.0 - '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.3)': + '@angular/forms@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@angular/common': 20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) + '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) + '@angular/platform-browser': 20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) + rxjs: 7.8.2 + tslib: 2.8.1 - '@babel/plugin-transform-object-rest-spread@7.28.0(@babel/core@7.28.3)': + '@angular/material@20.1.0-next.1(e3f61fe28cd1f106fd36f2f00f317744)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.3) - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + '@angular/cdk': 20.1.0-next.1(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) + '@angular/common': 20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) + '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) + '@angular/forms': 20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2) + '@angular/platform-browser': 20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) + rxjs: 7.8.2 + tslib: 2.8.1 - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.3)': + '@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color + '@angular/common': 20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) + '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) + tslib: 2.8.1 + optionalDependencies: + '@angular/animations': 20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) - '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.3)': + '@angular/router@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@angular/common': 20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2) + '@angular/core': 20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0) + '@angular/platform-browser': 20.2.0(@angular/animations@20.2.0(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)))(@angular/common@20.2.0(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@20.2.0(@angular/compiler@20.2.0)(rxjs@7.8.2)(zone.js@0.15.0)) + rxjs: 7.8.2 + tslib: 2.8.1 - '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.3)': + '@babel/code-frame@7.27.1': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/compat-data@7.27.2': {} - '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.3)': + '@babel/core@7.28.3': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) + '@babel/helpers': 7.28.3 + '@babel/parser': 7.28.3 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.3 + '@babel/types': 7.28.2 + convert-source-map: 2.0.0 + debug: 4.4.0 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.3)': + '@babel/generator@7.27.1': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + '@babel/parser': 7.27.2 + '@babel/types': 7.28.2 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 - '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.3)': + '@babel/generator@7.28.3': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + jsesc: 3.1.0 - '@babel/plugin-transform-regenerator@7.28.3(@babel/core@7.28.3)': + '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/types': 7.28.2 - '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.3)': + '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/compat-data': 7.27.2 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.24.4 + lru-cache: 5.1.1 + semver: 6.3.1 - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-globals@7.28.0': {} - '@babel/plugin-transform-runtime@7.28.3(@babel/core@7.28.3)': + '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.3) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.3) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.3) - semver: 6.3.1 + '@babel/traverse': 7.27.1 + '@babel/types': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.3)': + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.3 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.3)': + '@babel/helper-split-export-declaration@7.24.7': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/types': 7.28.2 - '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-string-parser@7.27.1': {} - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier@7.27.1': {} - '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option@7.27.1': {} - '@babel/preset-env@7.28.3(@babel/core@7.28.3)': + '@babel/helpers@7.28.3': dependencies: - '@babel/compat-data': 7.28.0 - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.3) - '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.3) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-block-scoping': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-transform-classes': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-exponentiation-operator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-systemjs': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-object-rest-spread': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.3) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-regenerator': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.3) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.3) - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.3) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.3) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.3) - core-js-compat: 3.45.1 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.3)': + '@babel/parser@7.27.2': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 '@babel/types': 7.27.1 - esutils: 2.0.3 - '@babel/runtime@7.28.3': {} + '@babel/parser@7.28.3': + dependencies: + '@babel/types': 7.28.2 '@babel/template@7.27.2': dependencies: @@ -5893,14 +3605,13 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@colors/colors@1.5.0': {} + '@colors/colors@1.5.0': + optional: true '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@discoveryjs/json-ext@0.6.3': {} - '@emnapi/core@1.5.0': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -5995,12 +3706,6 @@ snapshots: '@esbuild/win32-x64@0.25.9': optional: true - '@hapi/hoek@9.3.0': {} - - '@hapi/topo@5.1.0': - dependencies: - '@hapi/hoek': 9.3.0 - '@inquirer/checkbox@4.2.2(@types/node@22.15.33)': dependencies: '@inquirer/core': 10.2.0(@types/node@22.15.33) @@ -6163,8 +3868,9 @@ snapshots: '@jridgewell/source-map@0.3.6': dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + optional: true '@jridgewell/sourcemap-codec@1.5.0': {} @@ -6179,27 +3885,9 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 - - '@jsonjoy.com/base64@1.1.2(tslib@2.8.1)': - dependencies: - tslib: 2.8.1 - - '@jsonjoy.com/json-pack@1.2.0(tslib@2.8.1)': - dependencies: - '@jsonjoy.com/base64': 1.1.2(tslib@2.8.1) - '@jsonjoy.com/util': 1.5.0(tslib@2.8.1) - hyperdyperid: 1.2.0 - thingies: 1.21.0(tslib@2.8.1) - tslib: 2.8.1 - - '@jsonjoy.com/util@1.5.0(tslib@2.8.1)': - dependencies: - tslib: 2.8.1 - - '@leichtgewicht/ip-codec@2.0.5': {} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 '@listr2/prompt-adapter-inquirer@3.0.1(@inquirer/prompts@7.8.2(@types/node@22.15.33))(@types/node@22.15.33)(listr2@9.0.1)': dependencies: @@ -6344,24 +4032,6 @@ snapshots: '@tybys/wasm-util': 0.10.0 optional: true - '@ngtools/webpack@20.2.0(@angular/compiler-cli@20.2.0(@angular/compiler@20.2.0)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.101.2(esbuild@0.25.9))': - dependencies: - '@angular/compiler-cli': 20.2.0(@angular/compiler@20.2.0)(typescript@5.8.3) - typescript: 5.8.3 - webpack: 5.101.2(esbuild@0.25.9) - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 - '@npmcli/agent@3.0.0': dependencies: agent-base: 7.1.3 @@ -6606,14 +4276,6 @@ snapshots: transitivePeerDependencies: - chokidar - '@sideway/address@4.1.5': - dependencies: - '@hapi/hoek': 9.3.0 - - '@sideway/formula@3.0.1': {} - - '@sideway/pinpoint@2.0.0': {} - '@sigstore/bundle@3.1.0': dependencies: '@sigstore/protobuf-specs': 0.4.1 @@ -6646,7 +4308,8 @@ snapshots: '@sigstore/core': 2.0.0 '@sigstore/protobuf-specs': 0.4.1 - '@socket.io/component-emitter@3.1.2': {} + '@socket.io/component-emitter@3.1.2': + optional: true '@tsconfig/node10@1.0.11': {} @@ -6668,189 +4331,25 @@ snapshots: tslib: 2.8.1 optional: true - '@types/body-parser@1.19.5': - dependencies: - '@types/connect': 3.4.38 - '@types/node': 22.15.33 - - '@types/bonjour@3.5.13': - dependencies: - '@types/node': 22.15.33 - - '@types/connect-history-api-fallback@1.5.4': - dependencies: - '@types/express-serve-static-core': 4.19.6 - '@types/node': 22.15.33 - - '@types/connect@3.4.38': - dependencies: - '@types/node': 22.15.33 - '@types/cors@2.8.17': dependencies: '@types/node': 22.15.33 - - '@types/eslint-scope@3.7.7': - dependencies: - '@types/eslint': 9.6.1 - '@types/estree': 1.0.8 - - '@types/eslint@9.6.1': - dependencies: - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 + optional: true '@types/estree@1.0.8': {} - '@types/express-serve-static-core@4.19.6': - dependencies: - '@types/node': 22.15.33 - '@types/qs': 6.9.18 - '@types/range-parser': 1.2.7 - '@types/send': 0.17.4 - - '@types/express@4.17.21': - dependencies: - '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.19.6 - '@types/qs': 6.9.18 - '@types/serve-static': 1.15.7 - - '@types/http-errors@2.0.4': {} - - '@types/http-proxy@1.17.16': - dependencies: - '@types/node': 22.15.33 - '@types/jasmine@5.1.8': {} - '@types/json-schema@7.0.15': {} - - '@types/mime@1.3.5': {} - - '@types/node-forge@1.3.11': - dependencies: - '@types/node': 22.15.33 - '@types/node@22.15.33': dependencies: undici-types: 6.21.0 - '@types/qs@6.9.18': {} - - '@types/range-parser@1.2.7': {} - - '@types/retry@0.12.2': {} - '@types/selenium-webdriver@3.0.26': {} - '@types/send@0.17.4': - dependencies: - '@types/mime': 1.3.5 - '@types/node': 22.15.33 - - '@types/serve-index@1.9.4': - dependencies: - '@types/express': 4.17.21 - - '@types/serve-static@1.15.7': - dependencies: - '@types/http-errors': 2.0.4 - '@types/node': 22.15.33 - '@types/send': 0.17.4 - - '@types/sockjs@0.3.36': - dependencies: - '@types/node': 22.15.33 - - '@types/ws@8.18.1': - dependencies: - '@types/node': 22.15.33 - '@vitejs/plugin-basic-ssl@2.1.0(vite@7.1.2(@types/node@22.15.33)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1))': dependencies: vite: 7.1.2(@types/node@22.15.33)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1) - '@webassemblyjs/ast@1.14.1': - dependencies: - '@webassemblyjs/helper-numbers': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - - '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - - '@webassemblyjs/helper-api-error@1.13.2': {} - - '@webassemblyjs/helper-buffer@1.14.1': {} - - '@webassemblyjs/helper-numbers@1.13.2': - dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.13.2 - '@webassemblyjs/helper-api-error': 1.13.2 - '@xtuc/long': 4.2.2 - - '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} - - '@webassemblyjs/helper-wasm-section@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/wasm-gen': 1.14.1 - - '@webassemblyjs/ieee754@1.13.2': - dependencies: - '@xtuc/ieee754': 1.2.0 - - '@webassemblyjs/leb128@1.13.2': - dependencies: - '@xtuc/long': 4.2.2 - - '@webassemblyjs/utf8@1.13.2': {} - - '@webassemblyjs/wasm-edit@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/helper-wasm-section': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-opt': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - '@webassemblyjs/wast-printer': 1.14.1 - - '@webassemblyjs/wasm-gen@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wasm-opt@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - - '@webassemblyjs/wasm-parser@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-api-error': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wast-printer@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@xtuc/long': 4.2.2 - - '@xtuc/ieee754@1.2.0': {} - - '@xtuc/long@4.2.2': {} - '@yarnpkg/lockfile@1.1.0': {} abbrev@3.0.1: {} @@ -6859,44 +4358,28 @@ snapshots: dependencies: mime-types: 2.1.35 negotiator: 0.6.3 + optional: true accepts@2.0.0: dependencies: mime-types: 3.0.1 negotiator: 1.0.0 - acorn-import-phases@1.0.4(acorn@8.15.0): - dependencies: - acorn: 8.15.0 - acorn-walk@8.3.4: dependencies: acorn: 8.14.1 acorn@8.14.1: {} - acorn@8.15.0: {} - - adjust-sourcemap-loader@4.0.0: - dependencies: - loader-utils: 2.0.4 - regex-parser: 2.3.1 + acorn@8.15.0: + optional: true agent-base@7.1.3: {} - ajv-formats@2.1.1(ajv@8.17.1): - optionalDependencies: - ajv: 8.17.1 - ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 - ajv-keywords@5.1.0(ajv@8.17.1): - dependencies: - ajv: 8.17.1 - fast-deep-equal: 3.1.3 - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -6928,8 +4411,6 @@ snapshots: '@algolia/requester-fetch': 5.35.0 '@algolia/requester-node-http': 5.35.0 - ansi-colors@4.1.3: {} - ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -6938,8 +4419,6 @@ snapshots: dependencies: environment: 1.1.0 - ansi-html-community@0.0.8: {} - ansi-regex@5.0.1: {} ansi-regex@6.1.0: {} @@ -6956,68 +4435,14 @@ snapshots: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 + optional: true arg@4.1.3: {} - argparse@2.0.1: {} - - array-flatten@1.1.1: {} - - asynckit@0.4.0: {} - - autoprefixer@10.4.21(postcss@8.5.6): - dependencies: - browserslist: 4.24.4 - caniuse-lite: 1.0.30001713 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.1.1 - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - - axios@1.9.0: - dependencies: - follow-redirects: 1.15.9(debug@4.4.0) - form-data: 4.0.2 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - babel-loader@10.0.0(@babel/core@7.28.3)(webpack@5.101.2(esbuild@0.25.9)): - dependencies: - '@babel/core': 7.28.3 - find-up: 5.0.0 - webpack: 5.101.2(esbuild@0.25.9) - - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.3): - dependencies: - '@babel/compat-data': 7.28.0 - '@babel/core': 7.28.3 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.3): - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) - core-js-compat: 3.45.1 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.3): - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color - balanced-match@1.0.2: {} - base64id@2.0.0: {} - - batch@0.6.1: {} + base64id@2.0.0: + optional: true beasties@0.3.5: dependencies: @@ -7030,9 +4455,8 @@ snapshots: postcss: 8.5.6 postcss-media-query-parser: 0.2.3 - big.js@5.2.2: {} - - binary-extensions@2.3.0: {} + binary-extensions@2.3.0: + optional: true body-parser@1.20.3: dependencies: @@ -7050,6 +4474,7 @@ snapshots: unpipe: 1.0.0 transitivePeerDependencies: - supports-color + optional: true body-parser@2.2.0: dependencies: @@ -7065,11 +4490,6 @@ snapshots: transitivePeerDependencies: - supports-color - bonjour-service@1.3.0: - dependencies: - fast-deep-equal: 3.1.3 - multicast-dns: 7.2.5 - boolbase@1.0.0: {} brace-expansion@1.1.11: @@ -7084,6 +4504,7 @@ snapshots: braces@3.0.3: dependencies: fill-range: 7.1.1 + optional: true browserslist@4.24.4: dependencies: @@ -7101,10 +4522,6 @@ snapshots: buffer-from@1.1.2: {} - bundle-name@4.1.0: - dependencies: - run-applescript: 7.0.0 - bytes@3.1.2: {} cacache@19.0.1: @@ -7132,8 +4549,6 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 - callsites@3.1.0: {} - caniuse-lite@1.0.30001713: {} caniuse-lite@1.0.30001739: {} @@ -7158,6 +4573,7 @@ snapshots: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 + optional: true chokidar@4.0.3: dependencies: @@ -7167,8 +4583,6 @@ snapshots: chownr@3.0.0: {} - chrome-trace-event@1.0.4: {} - cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -7187,6 +4601,7 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + optional: true cliui@8.0.1: dependencies: @@ -7200,12 +4615,6 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 9.0.0 - clone-deep@4.0.1: - dependencies: - is-plain-object: 2.0.4 - kind-of: 6.0.3 - shallow-clone: 3.0.1 - color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -7214,27 +4623,8 @@ snapshots: colorette@2.0.20: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - commander@2.20.3: {} - - compressible@2.0.18: - dependencies: - mime-db: 1.54.0 - - compression@1.8.0: - dependencies: - bytes: 3.1.2 - compressible: 2.0.18 - debug: 2.6.9 - negotiator: 0.6.4 - on-headers: 1.0.2 - safe-buffer: 5.2.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color + commander@2.20.3: + optional: true concat-map@0.0.1: {} @@ -7248,8 +4638,6 @@ snapshots: tree-kill: 1.2.2 yargs: 17.7.2 - connect-history-api-fallback@2.0.0: {} - connect@3.7.0: dependencies: debug: 2.6.9 @@ -7258,10 +4646,7 @@ snapshots: utils-merge: 1.0.1 transitivePeerDependencies: - supports-color - - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 + optional: true content-disposition@1.0.0: dependencies: @@ -7273,30 +4658,14 @@ snapshots: convert-source-map@2.0.0: {} - cookie-signature@1.0.6: {} - cookie-signature@1.2.2: {} - cookie@0.7.1: {} - cookie@0.7.2: {} copy-anything@2.0.6: dependencies: is-what: 3.14.1 - - copy-webpack-plugin@13.0.1(webpack@5.101.2(esbuild@0.25.9)): - dependencies: - glob-parent: 6.0.2 - normalize-path: 3.0.0 - schema-utils: 4.3.2 - serialize-javascript: 6.0.2 - tinyglobby: 0.2.13 - webpack: 5.101.2(esbuild@0.25.9) - - core-js-compat@3.45.1: - dependencies: - browserslist: 4.25.4 + optional: true core-util-is@1.0.3: {} @@ -7305,15 +4674,6 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - cosmiconfig@9.0.0(typescript@5.8.3): - dependencies: - env-paths: 2.2.1 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - parse-json: 5.2.0 - optionalDependencies: - typescript: 5.8.3 - create-require@1.1.1: {} cross-spawn@7.0.6: @@ -7322,19 +4682,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-loader@7.1.2(webpack@5.101.2(esbuild@0.25.9)): - dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.6) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.6) - postcss-modules-scope: 3.2.1(postcss@8.5.6) - postcss-modules-values: 4.0.0(postcss@8.5.6) - postcss-value-parser: 4.2.0 - semver: 7.7.2 - optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) - css-select@6.0.0: dependencies: boolbase: 1.0.0 @@ -7345,19 +4692,21 @@ snapshots: css-what@7.0.0: {} - cssesc@3.0.0: {} - - custom-event@1.0.1: {} + custom-event@1.0.1: + optional: true - date-format@4.0.14: {} + date-format@4.0.14: + optional: true debug@2.6.9: dependencies: ms: 2.0.0 + optional: true debug@4.3.7: dependencies: ms: 2.1.3 + optional: true debug@4.4.0: dependencies: @@ -7367,22 +4716,10 @@ snapshots: dependencies: ms: 2.1.3 - default-browser-id@5.0.0: {} - - default-browser@5.2.1: - dependencies: - bundle-name: 4.1.0 - default-browser-id: 5.0.0 - - define-lazy-prop@3.0.0: {} - - delayed-stream@1.0.0: {} - - depd@1.1.2: {} - depd@2.0.0: {} - destroy@1.2.0: {} + destroy@1.2.0: + optional: true detect-libc@1.0.3: optional: true @@ -7390,22 +4727,18 @@ snapshots: detect-libc@2.0.3: optional: true - detect-node@2.1.0: {} - - di@0.0.1: {} + di@0.0.1: + optional: true diff@4.0.2: {} - dns-packet@5.6.1: - dependencies: - '@leichtgewicht/ip-codec': 2.0.5 - dom-serialize@2.2.1: dependencies: custom-event: 1.0.1 ent: 2.2.2 extend: 3.0.2 void-elements: 2.0.1 + optional: true dom-serializer@2.0.0: dependencies: @@ -7445,9 +4778,8 @@ snapshots: emoji-regex@9.2.2: {} - emojis-list@3.0.0: {} - - encodeurl@1.0.2: {} + encodeurl@1.0.2: + optional: true encodeurl@2.0.0: {} @@ -7456,7 +4788,8 @@ snapshots: iconv-lite: 0.6.3 optional: true - engine.io-parser@5.2.3: {} + engine.io-parser@5.2.3: + optional: true engine.io@6.6.4: dependencies: @@ -7473,11 +4806,7 @@ snapshots: - bufferutil - supports-color - utf-8-validate - - enhanced-resolve@5.18.1: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.2.1 + optional: true ent@2.2.2: dependencies: @@ -7485,6 +4814,7 @@ snapshots: es-errors: 1.3.0 punycode: 1.4.1 safe-regex-test: 1.1.0 + optional: true entities@4.5.0: {} @@ -7501,29 +4831,14 @@ snapshots: prr: 1.0.1 optional: true - error-ex@1.3.2: - dependencies: - is-arrayish: 0.2.1 - es-define-property@1.0.1: {} es-errors@1.3.0: {} - es-module-lexer@1.6.0: {} - es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - esbuild-wasm@0.25.9: {} - esbuild@0.25.9: optionalDependencies: '@esbuild/aix-ppc64': 0.25.9 @@ -7550,36 +4865,20 @@ snapshots: '@esbuild/openharmony-arm64': 0.25.9 '@esbuild/sunos-x64': 0.25.9 '@esbuild/win32-arm64': 0.25.9 - '@esbuild/win32-ia32': 0.25.9 - '@esbuild/win32-x64': 0.25.9 - - escalade@3.2.0: {} - - escape-html@1.0.3: {} - - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@4.3.0: {} + '@esbuild/win32-ia32': 0.25.9 + '@esbuild/win32-x64': 0.25.9 - estraverse@5.3.0: {} + escalade@3.2.0: {} - esutils@2.0.3: {} + escape-html@1.0.3: {} etag@1.8.1: {} - eventemitter3@4.0.7: {} + eventemitter3@4.0.7: + optional: true eventemitter3@5.0.1: {} - events@3.3.0: {} - eventsource-parser@3.0.6: {} eventsource@3.0.7: @@ -7592,42 +4891,6 @@ snapshots: dependencies: express: 5.1.0 - express@4.21.2: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.3 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.1 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.12 - proxy-addr: 2.0.7 - qs: 6.13.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - express@5.1.0: dependencies: accepts: 2.0.0 @@ -7660,30 +4923,15 @@ snapshots: transitivePeerDependencies: - supports-color - extend@3.0.2: {} + extend@3.0.2: + optional: true fast-deep-equal@3.1.3: {} - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - fast-json-stable-stringify@2.1.0: {} fast-uri@3.0.6: {} - fastq@1.19.1: - dependencies: - reusify: 1.1.0 - - faye-websocket@0.11.4: - dependencies: - websocket-driver: 0.7.4 - fdir@6.4.4(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -7695,6 +4943,7 @@ snapshots: fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 + optional: true finalhandler@1.1.2: dependencies: @@ -7707,18 +4956,7 @@ snapshots: unpipe: 1.0.0 transitivePeerDependencies: - supports-color - - finalhandler@1.3.1: - dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color + optional: true finalhandler@2.1.0: dependencies: @@ -7731,37 +4969,19 @@ snapshots: transitivePeerDependencies: - supports-color - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat@5.0.2: {} - - flatted@3.3.3: {} + flatted@3.3.3: + optional: true - follow-redirects@1.15.9(debug@4.4.0): - optionalDependencies: - debug: 4.4.0 + follow-redirects@1.15.9: + optional: true foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data@4.0.2: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - mime-types: 2.1.35 - forwarded@0.2.0: {} - fraction.js@4.3.7: {} - - fresh@0.5.2: {} - fresh@2.0.0: {} fs-extra@8.1.0: @@ -7769,6 +4989,7 @@ snapshots: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 + optional: true fs-minipass@2.1.0: dependencies: @@ -7812,10 +5033,7 @@ snapshots: glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 + optional: true glob-to-regexp@0.4.1: {} @@ -7843,8 +5061,6 @@ snapshots: graceful-fs@4.2.11: {} - handle-thing@2.0.1: {} - has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -7852,6 +5068,7 @@ snapshots: has-tostringtag@1.0.2: dependencies: has-symbols: 1.1.0 + optional: true hasown@2.0.2: dependencies: @@ -7865,15 +5082,6 @@ snapshots: dependencies: lru-cache: 11.2.1 - hpack.js@2.1.6: - dependencies: - inherits: 2.0.4 - obuf: 1.1.2 - readable-stream: 2.3.8 - wbuf: 1.7.3 - - html-escaper@2.0.2: {} - htmlparser2@10.0.0: dependencies: domelementtype: 2.3.0 @@ -7883,15 +5091,6 @@ snapshots: http-cache-semantics@4.1.1: {} - http-deceiver@1.2.7: {} - - http-errors@1.6.3: - dependencies: - depd: 1.1.2 - inherits: 2.0.3 - setprototypeof: 1.1.0 - statuses: 1.5.0 - http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -7900,8 +5099,6 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 - http-parser-js@0.5.10: {} - http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 @@ -7909,49 +5106,26 @@ snapshots: transitivePeerDependencies: - supports-color - http-proxy-middleware@2.0.9(@types/express@4.17.21): - dependencies: - '@types/http-proxy': 1.17.16 - http-proxy: 1.18.1(debug@4.4.0) - is-glob: 4.0.3 - is-plain-obj: 3.0.0 - micromatch: 4.0.8 - optionalDependencies: - '@types/express': 4.17.21 - transitivePeerDependencies: - - debug - - http-proxy-middleware@3.0.5: - dependencies: - '@types/http-proxy': 1.17.16 - debug: 4.4.0 - http-proxy: 1.18.1(debug@4.4.0) - is-glob: 4.0.3 - is-plain-object: 5.0.0 - micromatch: 4.0.8 - transitivePeerDependencies: - - supports-color - - http-proxy@1.18.1(debug@4.4.0): + http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9 requires-port: 1.0.0 transitivePeerDependencies: - debug + optional: true https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.1 transitivePeerDependencies: - supports-color - hyperdyperid@1.2.0: {} - iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 + optional: true iconv-lite@0.6.3: dependencies: @@ -7961,10 +5135,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - icss-utils@5.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - ignore-walk@7.0.0: dependencies: minimatch: 9.0.5 @@ -7976,11 +5146,6 @@ snapshots: immutable@5.1.1: {} - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - imurmurhash@0.1.4: {} inflight@1.0.6: @@ -7988,8 +5153,6 @@ snapshots: once: 1.4.0 wrappy: 1.0.2 - inherits@2.0.3: {} - inherits@2.0.4: {} ini@5.0.0: {} @@ -8001,21 +5164,17 @@ snapshots: ipaddr.js@1.9.1: {} - ipaddr.js@2.2.0: {} - - is-arrayish@0.2.1: {} - is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 + optional: true is-core-module@2.16.1: dependencies: hasown: 2.0.2 - is-docker@3.0.0: {} - - is-extglob@2.1.1: {} + is-extglob@2.1.1: + optional: true is-fullwidth-code-point@3.0.0: {} @@ -8028,24 +5187,12 @@ snapshots: is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - - is-inside-container@1.0.0: - dependencies: - is-docker: 3.0.0 + optional: true is-interactive@2.0.0: {} - is-network-error@1.1.0: {} - - is-number@7.0.0: {} - - is-plain-obj@3.0.0: {} - - is-plain-object@2.0.4: - dependencies: - isobject: 3.0.1 - - is-plain-object@5.0.0: {} + is-number@7.0.0: + optional: true is-promise@4.0.0: {} @@ -8055,76 +5202,42 @@ snapshots: gopd: 1.2.0 has-tostringtag: 1.0.2 hasown: 2.0.2 + optional: true is-unicode-supported@1.3.0: {} is-unicode-supported@2.1.0: {} - is-what@3.14.1: {} - - is-wsl@3.1.0: - dependencies: - is-inside-container: 1.0.0 + is-what@3.14.1: + optional: true isarray@1.0.0: {} - isbinaryfile@4.0.10: {} + isbinaryfile@4.0.10: + optional: true isexe@2.0.0: {} isexe@3.1.1: {} - isobject@3.0.1: {} - istanbul-lib-coverage@3.2.2: {} - istanbul-lib-instrument@5.2.1: - dependencies: - '@babel/core': 7.27.1 - '@babel/parser': 7.27.2 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - istanbul-lib-instrument@6.0.3: dependencies: '@babel/core': 7.28.3 - '@babel/parser': 7.27.2 + '@babel/parser': 7.28.3 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 7.7.2 transitivePeerDependencies: - supports-color - istanbul-lib-report@3.0.1: - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - - istanbul-lib-source-maps@4.0.1: - dependencies: - debug: 4.4.0 - istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - - istanbul-reports@3.1.7: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jasmine-core@3.99.1: {} - jasmine-core@5.8.0: {} jasmine@5.8.0: @@ -8132,36 +5245,15 @@ snapshots: glob: 10.4.5 jasmine-core: 5.8.0 - jest-worker@27.5.1: - dependencies: - '@types/node': 22.15.33 - merge-stream: 2.0.0 - supports-color: 8.1.1 - - jiti@1.21.7: {} - - joi@17.13.3: - dependencies: - '@hapi/hoek': 9.3.0 - '@hapi/topo': 5.1.0 - '@sideway/address': 4.1.5 - '@sideway/formula': 3.0.1 - '@sideway/pinpoint': 2.0.0 + jiti@1.21.7: + optional: true js-tokens@4.0.0: {} - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - jsbn@1.1.0: {} - jsesc@3.0.2: {} - jsesc@3.1.0: {} - json-parse-even-better-errors@2.3.1: {} - json-parse-even-better-errors@4.0.0: {} json-schema-traverse@0.4.1: {} @@ -8175,6 +5267,7 @@ snapshots: jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 + optional: true jsonparse@1.3.1: {} @@ -8185,36 +5278,6 @@ snapshots: readable-stream: 2.3.8 setimmediate: 1.0.5 - karma-chrome-launcher@3.2.0: - dependencies: - which: 1.3.1 - - karma-coverage@2.2.1: - dependencies: - istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 5.2.1 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.7 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - karma-jasmine-html-reporter@2.1.0(jasmine-core@5.8.0)(karma-jasmine@4.0.2(karma@6.4.4))(karma@6.4.4): - dependencies: - jasmine-core: 5.8.0 - karma: 6.4.4 - karma-jasmine: 4.0.2(karma@6.4.4) - - karma-jasmine@4.0.2(karma@6.4.4): - dependencies: - jasmine-core: 3.99.1 - karma: 6.4.4 - - karma-source-map-support@1.4.0: - dependencies: - source-map-support: 0.5.21 - karma@6.4.4: dependencies: '@colors/colors': 1.5.0 @@ -8226,7 +5289,7 @@ snapshots: dom-serialize: 2.2.1 glob: 7.2.3 graceful-fs: 4.2.11 - http-proxy: 1.18.1(debug@4.4.0) + http-proxy: 1.18.1 isbinaryfile: 4.0.10 lodash: 4.17.21 log4js: 6.9.1 @@ -8246,19 +5309,7 @@ snapshots: - debug - supports-color - utf-8-validate - - kind-of@6.0.3: {} - - launch-editor@2.10.0: - dependencies: - picocolors: 1.1.1 - shell-quote: 1.8.2 - - less-loader@12.3.0(less@4.4.0)(webpack@5.101.2(esbuild@0.25.9)): - dependencies: - less: 4.4.0 - optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) + optional: true less@4.4.0: dependencies: @@ -8273,19 +5324,12 @@ snapshots: mime: 1.6.0 needle: 3.3.1 source-map: 0.6.1 - - license-webpack-plugin@4.0.2(webpack@5.101.2(esbuild@0.25.9)): - dependencies: - webpack-sources: 3.2.3 - optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) + optional: true lie@3.3.0: dependencies: immediate: 3.0.6 - lines-and-columns@1.2.4: {} - listr2@9.0.1: dependencies: cli-truncate: 4.0.0 @@ -8312,22 +5356,6 @@ snapshots: '@lmdb/lmdb-win32-x64': 3.4.2 optional: true - loader-runner@4.3.0: {} - - loader-utils@2.0.4: - dependencies: - big.js: 5.2.2 - emojis-list: 3.0.0 - json5: 2.2.3 - - loader-utils@3.3.1: {} - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.debounce@4.0.8: {} - lodash@4.17.21: {} log-symbols@6.0.0: @@ -8346,12 +5374,13 @@ snapshots: log4js@6.9.1: dependencies: date-format: 4.0.14 - debug: 4.4.0 + debug: 4.4.1 flatted: 3.3.3 rfdc: 1.4.1 streamroller: 3.1.5 transitivePeerDependencies: - supports-color + optional: true lru-cache@10.4.3: {} @@ -8371,10 +5400,6 @@ snapshots: semver: 5.7.2 optional: true - make-dir@4.0.0: - dependencies: - semver: 7.7.2 - make-error@1.3.6: {} make-fetch-happen@14.0.3: @@ -8395,58 +5420,41 @@ snapshots: math-intrinsics@1.1.0: {} - media-typer@0.3.0: {} + media-typer@0.3.0: + optional: true media-typer@1.1.0: {} - memfs@4.17.0: - dependencies: - '@jsonjoy.com/json-pack': 1.2.0(tslib@2.8.1) - '@jsonjoy.com/util': 1.5.0(tslib@2.8.1) - tree-dump: 1.0.2(tslib@2.8.1) - tslib: 2.8.1 - - merge-descriptors@1.0.3: {} - merge-descriptors@2.0.0: {} - merge-stream@2.0.0: {} - - merge2@1.4.1: {} - - methods@1.1.2: {} - micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 + optional: true - mime-db@1.52.0: {} + mime-db@1.52.0: + optional: true mime-db@1.54.0: {} mime-types@2.1.35: dependencies: mime-db: 1.52.0 + optional: true mime-types@3.0.1: dependencies: mime-db: 1.54.0 - mime@1.6.0: {} + mime@1.6.0: + optional: true - mime@2.6.0: {} + mime@2.6.0: + optional: true mimic-function@5.0.1: {} - mini-css-extract-plugin@2.9.4(webpack@5.101.2(esbuild@0.25.9)): - dependencies: - schema-utils: 4.3.2 - tapable: 2.2.1 - webpack: 5.101.2(esbuild@0.25.9) - - minimalistic-assert@1.0.1: {} - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -8455,7 +5463,8 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimist@1.2.8: {} + minimist@1.2.8: + optional: true minipass-collect@2.0.1: dependencies: @@ -8501,6 +5510,7 @@ snapshots: mkdirp@0.5.6: dependencies: minimist: 1.2.8 + optional: true mkdirp@1.0.4: {} @@ -8508,7 +5518,8 @@ snapshots: mrmime@2.0.1: {} - ms@2.0.0: {} + ms@2.0.0: + optional: true ms@2.1.3: {} @@ -8529,11 +5540,6 @@ snapshots: msgpackr-extract: 3.0.3 optional: true - multicast-dns@7.2.5: - dependencies: - dns-packet: 5.6.1 - thunky: 1.1.0 - mute-stream@2.0.0: {} nanoid@3.3.11: {} @@ -8544,22 +5550,17 @@ snapshots: sax: 1.4.1 optional: true - negotiator@0.6.3: {} - - negotiator@0.6.4: {} + negotiator@0.6.3: + optional: true negotiator@1.0.0: {} - neo-async@2.6.2: {} - node-addon-api@6.1.0: optional: true node-addon-api@7.1.1: optional: true - node-forge@1.3.1: {} - node-gyp-build-optional-packages@5.2.2: dependencies: detect-libc: 2.0.3 @@ -8586,9 +5587,8 @@ snapshots: dependencies: abbrev: 3.0.1 - normalize-path@3.0.0: {} - - normalize-range@0.1.2: {} + normalize-path@3.0.0: + optional: true npm-bundled@4.0.0: dependencies: @@ -8646,18 +5646,15 @@ snapshots: object-inspect@1.13.4: {} - obuf@1.1.2: {} - on-finished@2.3.0: dependencies: ee-first: 1.1.1 + optional: true on-finished@2.4.1: dependencies: ee-first: 1.1.1 - on-headers@1.0.2: {} - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -8666,13 +5663,6 @@ snapshots: dependencies: mimic-function: 5.0.1 - open@10.2.0: - dependencies: - default-browser: 5.2.1 - define-lazy-prop: 3.0.0 - is-inside-container: 1.0.0 - wsl-utils: 0.1.0 - ora@8.2.0: dependencies: chalk: 5.4.1 @@ -8690,22 +5680,8 @@ snapshots: os-tmpdir@1.0.2: {} - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - p-map@7.0.3: {} - p-retry@6.2.1: - dependencies: - '@types/retry': 0.12.2 - is-network-error: 1.1.0 - retry: 0.13.1 - package-json-from-dist@1.0.1: {} pacote@21.0.0: @@ -8732,18 +5708,8 @@ snapshots: pako@1.0.11: {} - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-json@5.2.0: - dependencies: - '@babel/code-frame': 7.27.1 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - - parse-node-version@1.0.1: {} + parse-node-version@1.0.1: + optional: true parse5-html-rewriting-stream@8.0.0: dependencies: @@ -8765,8 +5731,6 @@ snapshots: parseurl@1.3.3: {} - path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} path-key@3.1.1: {} @@ -8778,13 +5742,12 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 - path-to-regexp@0.1.12: {} - path-to-regexp@8.3.0: {} picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@2.3.1: + optional: true picomatch@4.0.3: {} @@ -8797,47 +5760,8 @@ snapshots: pkce-challenge@5.0.0: {} - postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.8.3)(webpack@5.101.2(esbuild@0.25.9)): - dependencies: - cosmiconfig: 9.0.0(typescript@5.8.3) - jiti: 1.21.7 - postcss: 8.5.6 - semver: 7.7.2 - optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) - transitivePeerDependencies: - - typescript - postcss-media-query-parser@0.2.3: {} - postcss-modules-extract-imports@3.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - - postcss-modules-local-by-default@4.2.0(postcss@8.5.6): - dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-selector-parser: 7.1.0 - postcss-value-parser: 4.2.0 - - postcss-modules-scope@3.2.1(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-selector-parser: 7.1.0 - - postcss-modules-values@4.0.0(postcss@8.5.6): - dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 - - postcss-selector-parser@7.1.0: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss-value-parser@4.2.0: {} - postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -8858,31 +5782,26 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - proxy-from-env@1.1.0: {} - prr@1.0.1: optional: true - punycode@1.4.1: {} + punycode@1.4.1: + optional: true punycode@2.3.1: {} - qjobs@1.2.0: {} + qjobs@1.2.0: + optional: true qs@6.13.0: dependencies: side-channel: 1.1.0 + optional: true qs@6.14.0: dependencies: side-channel: 1.1.0 - queue-microtask@1.2.3: {} - - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - range-parser@1.2.1: {} raw-body@2.5.2: @@ -8891,6 +5810,7 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 + optional: true raw-body@3.0.1: dependencies: @@ -8909,58 +5829,21 @@ snapshots: string_decoder: 1.1.1 util-deprecate: 1.0.2 - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - readdirp@3.6.0: dependencies: picomatch: 2.3.1 + optional: true readdirp@4.1.2: {} reflect-metadata@0.2.2: {} - regenerate-unicode-properties@10.2.0: - dependencies: - regenerate: 1.4.2 - - regenerate@1.4.2: {} - - regex-parser@2.3.1: {} - - regexpu-core@6.2.0: - dependencies: - regenerate: 1.4.2 - regenerate-unicode-properties: 10.2.0 - regjsgen: 0.8.0 - regjsparser: 0.12.0 - unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.2.0 - - regjsgen@0.8.0: {} - - regjsparser@0.12.0: - dependencies: - jsesc: 3.0.2 - require-directory@2.1.1: {} require-from-string@2.0.2: {} - requires-port@1.0.0: {} - - resolve-from@4.0.0: {} - - resolve-url-loader@5.0.0: - dependencies: - adjust-sourcemap-loader: 4.0.0 - convert-source-map: 1.9.0 - loader-utils: 2.0.4 - postcss: 8.5.6 - source-map: 0.6.1 + requires-port@1.0.0: + optional: true resolve@1.22.10: dependencies: @@ -8975,10 +5858,6 @@ snapshots: retry@0.12.0: {} - retry@0.13.1: {} - - reusify@1.1.0: {} - rfdc@1.4.1: {} rimraf@2.7.1: @@ -8988,6 +5867,7 @@ snapshots: rimraf@3.0.2: dependencies: glob: 7.2.3 + optional: true rolldown@1.0.0-beta.32: dependencies: @@ -9048,12 +5928,6 @@ snapshots: transitivePeerDependencies: - supports-color - run-applescript@7.0.0: {} - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - rxjs@7.8.2: dependencies: tslib: 2.8.1 @@ -9067,16 +5941,10 @@ snapshots: call-bound: 1.0.4 es-errors: 1.3.0 is-regex: 1.2.1 + optional: true safer-buffer@2.1.2: {} - sass-loader@16.0.5(sass@1.90.0)(webpack@5.101.2(esbuild@0.25.9)): - dependencies: - neo-async: 2.6.2 - optionalDependencies: - sass: 1.90.0 - webpack: 5.101.2(esbuild@0.25.9) - sass@1.90.0: dependencies: chokidar: 4.0.3 @@ -9087,15 +5955,6 @@ snapshots: sax@1.4.1: {} - schema-utils@4.3.2: - dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) - - select-hose@2.0.0: {} - selenium-webdriver@3.6.0: dependencies: jszip: 3.10.1 @@ -9103,11 +5962,6 @@ snapshots: tmp: 0.0.30 xml2js: 0.4.23 - selfsigned@2.4.1: - dependencies: - '@types/node-forge': 1.3.11 - node-forge: 1.3.1 - semver@5.7.2: optional: true @@ -9115,24 +5969,6 @@ snapshots: semver@7.7.2: {} - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - send@1.2.0: dependencies: debug: 4.4.0 @@ -9149,31 +5985,6 @@ snapshots: transitivePeerDependencies: - supports-color - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 - - serve-index@1.9.1: - dependencies: - accepts: 1.3.8 - batch: 0.6.1 - debug: 2.6.9 - escape-html: 1.0.3 - http-errors: 1.6.3 - mime-types: 2.1.35 - parseurl: 1.3.3 - transitivePeerDependencies: - - supports-color - - serve-static@1.16.2: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.0 - transitivePeerDependencies: - - supports-color - serve-static@2.2.0: dependencies: encodeurl: 2.0.0 @@ -9185,14 +5996,8 @@ snapshots: setimmediate@1.0.5: {} - setprototypeof@1.1.0: {} - setprototypeof@1.2.0: {} - shallow-clone@3.0.1: - dependencies: - kind-of: 6.0.3 - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -9262,6 +6067,7 @@ snapshots: - bufferutil - supports-color - utf-8-validate + optional: true socket.io-parser@4.2.4: dependencies: @@ -9269,6 +6075,7 @@ snapshots: debug: 4.3.7 transitivePeerDependencies: - supports-color + optional: true socket.io@4.8.1: dependencies: @@ -9283,12 +6090,7 @@ snapshots: - bufferutil - supports-color - utf-8-validate - - sockjs@0.3.24: - dependencies: - faye-websocket: 0.11.4 - uuid: 8.3.2 - websocket-driver: 0.7.4 + optional: true socks-proxy-agent@8.0.5: dependencies: @@ -9305,12 +6107,6 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@5.0.0(webpack@5.101.2(esbuild@0.25.9)): - dependencies: - iconv-lite: 0.6.3 - source-map-js: 1.2.1 - webpack: 5.101.2(esbuild@0.25.9) - source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 @@ -9334,34 +6130,14 @@ snapshots: spdx-license-ids@3.0.21: {} - spdy-transport@3.0.0: - dependencies: - debug: 4.4.0 - detect-node: 2.1.0 - hpack.js: 2.1.6 - obuf: 1.1.2 - readable-stream: 3.6.2 - wbuf: 1.7.3 - transitivePeerDependencies: - - supports-color - - spdy@4.0.2: - dependencies: - debug: 4.4.0 - handle-thing: 2.0.1 - http-deceiver: 1.2.7 - select-hose: 2.0.0 - spdy-transport: 3.0.0 - transitivePeerDependencies: - - supports-color - sprintf-js@1.1.3: {} ssri@12.0.0: dependencies: minipass: 7.1.2 - statuses@1.5.0: {} + statuses@1.5.0: + optional: true statuses@2.0.1: {} @@ -9370,10 +6146,11 @@ snapshots: streamroller@3.1.5: dependencies: date-format: 4.0.14 - debug: 4.4.0 + debug: 4.4.1 fs-extra: 8.1.0 transitivePeerDependencies: - supports-color + optional: true string-width@4.2.3: dependencies: @@ -9397,10 +6174,6 @@ snapshots: dependencies: safe-buffer: 5.1.2 - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -9419,8 +6192,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - tapable@2.2.1: {} - tar@6.2.1: dependencies: chownr: 2.0.0 @@ -9439,29 +6210,13 @@ snapshots: mkdirp: 3.0.1 yallist: 5.0.0 - terser-webpack-plugin@5.3.14(esbuild@0.25.9)(webpack@5.101.2): - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - jest-worker: 27.5.1 - schema-utils: 4.3.2 - serialize-javascript: 6.0.2 - terser: 5.43.1 - webpack: 5.101.2(esbuild@0.25.9) - optionalDependencies: - esbuild: 0.25.9 - terser@5.43.1: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.14.1 + acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21 - - thingies@1.21.0(tslib@2.8.1): - dependencies: - tslib: 2.8.1 - - thunky@1.1.0: {} + optional: true tinyglobby@0.2.13: dependencies: @@ -9470,25 +6225,23 @@ snapshots: tinyglobby@0.2.14: dependencies: - fdir: 6.4.4(picomatch@4.0.3) + fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 tmp@0.0.30: dependencies: os-tmpdir: 1.0.2 - tmp@0.2.3: {} + tmp@0.2.3: + optional: true to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + optional: true toidentifier@1.0.1: {} - tree-dump@1.0.2(tslib@2.8.1): - dependencies: - tslib: 2.8.1 - tree-kill@1.2.2: {} ts-node@10.9.2(@types/node@22.15.33)(typescript@5.8.3): @@ -9525,6 +6278,7 @@ snapshots: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 + optional: true type-is@2.0.1: dependencies: @@ -9532,25 +6286,13 @@ snapshots: media-typer: 1.1.0 mime-types: 3.0.1 - typed-assert@1.0.9: {} - typescript@5.8.3: {} - ua-parser-js@0.7.40: {} + ua-parser-js@0.7.40: + optional: true undici-types@6.21.0: {} - unicode-canonical-property-names-ecmascript@2.0.1: {} - - unicode-match-property-ecmascript@2.0.0: - dependencies: - unicode-canonical-property-names-ecmascript: 2.0.1 - unicode-property-aliases-ecmascript: 2.1.0 - - unicode-match-property-value-ecmascript@2.2.0: {} - - unicode-property-aliases-ecmascript@2.1.0: {} - unique-filename@4.0.0: dependencies: unique-slug: 5.0.0 @@ -9559,7 +6301,8 @@ snapshots: dependencies: imurmurhash: 0.1.4 - universalify@0.1.2: {} + universalify@0.1.2: + optional: true unpipe@1.0.0: {} @@ -9581,9 +6324,8 @@ snapshots: util-deprecate@1.0.2: {} - utils-merge@1.0.1: {} - - uuid@8.3.2: {} + utils-merge@1.0.1: + optional: true v8-compile-cache-lib@3.0.1: {} @@ -9612,143 +6354,17 @@ snapshots: sass: 1.90.0 terser: 5.43.1 - void-elements@2.0.1: {} - - wait-on@8.0.3: - dependencies: - axios: 1.9.0 - joi: 17.13.3 - lodash: 4.17.21 - minimist: 1.2.8 - rxjs: 7.8.2 - transitivePeerDependencies: - - debug - - watchpack@2.4.2: - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 + void-elements@2.0.1: + optional: true watchpack@2.4.4: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - wbuf@1.7.3: - dependencies: - minimalistic-assert: 1.0.1 - weak-lru-cache@1.2.2: optional: true - webpack-dev-middleware@7.4.2(webpack@5.101.2): - dependencies: - colorette: 2.0.20 - memfs: 4.17.0 - mime-types: 2.1.35 - on-finished: 2.4.1 - range-parser: 1.2.1 - schema-utils: 4.3.2 - optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) - - webpack-dev-server@5.2.2(webpack@5.101.2): - dependencies: - '@types/bonjour': 3.5.13 - '@types/connect-history-api-fallback': 1.5.4 - '@types/express': 4.17.21 - '@types/express-serve-static-core': 4.19.6 - '@types/serve-index': 1.9.4 - '@types/serve-static': 1.15.7 - '@types/sockjs': 0.3.36 - '@types/ws': 8.18.1 - ansi-html-community: 0.0.8 - bonjour-service: 1.3.0 - chokidar: 3.6.0 - colorette: 2.0.20 - compression: 1.8.0 - connect-history-api-fallback: 2.0.0 - express: 4.21.2 - graceful-fs: 4.2.11 - http-proxy-middleware: 2.0.9(@types/express@4.17.21) - ipaddr.js: 2.2.0 - launch-editor: 2.10.0 - open: 10.2.0 - p-retry: 6.2.1 - schema-utils: 4.3.2 - selfsigned: 2.4.1 - serve-index: 1.9.1 - sockjs: 0.3.24 - spdy: 4.0.2 - webpack-dev-middleware: 7.4.2(webpack@5.101.2) - ws: 8.18.1 - optionalDependencies: - webpack: 5.101.2(esbuild@0.25.9) - transitivePeerDependencies: - - bufferutil - - debug - - supports-color - - utf-8-validate - - webpack-merge@6.0.1: - dependencies: - clone-deep: 4.0.1 - flat: 5.0.2 - wildcard: 2.0.1 - - webpack-sources@3.2.3: {} - - webpack-sources@3.3.3: {} - - webpack-subresource-integrity@5.1.0(webpack@5.101.2(esbuild@0.25.9)): - dependencies: - typed-assert: 1.0.9 - webpack: 5.101.2(esbuild@0.25.9) - - webpack@5.101.2(esbuild@0.25.9): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.24.4 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.1 - es-module-lexer: 1.6.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.2 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.14(esbuild@0.25.9)(webpack@5.101.2) - watchpack: 2.4.2 - webpack-sources: 3.3.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - websocket-driver@0.7.4: - dependencies: - http-parser-js: 0.5.10 - safe-buffer: 5.2.1 - websocket-extensions: 0.1.4 - - websocket-extensions@0.1.4: {} - - which@1.3.1: - dependencies: - isexe: 2.0.0 - which@2.0.2: dependencies: isexe: 2.0.0 @@ -9757,8 +6373,6 @@ snapshots: dependencies: isexe: 3.1.1 - wildcard@2.0.1: {} - wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -9785,13 +6399,8 @@ snapshots: wrappy@1.0.2: {} - ws@8.17.1: {} - - ws@8.18.1: {} - - wsl-utils@0.1.0: - dependencies: - is-wsl: 3.1.0 + ws@8.17.1: + optional: true xml2js@0.4.23: dependencies: @@ -9808,7 +6417,8 @@ snapshots: yallist@5.0.0: {} - yargs-parser@20.2.9: {} + yargs-parser@20.2.9: + optional: true yargs-parser@21.1.1: {} @@ -9823,6 +6433,7 @@ snapshots: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 20.2.9 + optional: true yargs@17.7.2: dependencies: @@ -9845,8 +6456,6 @@ snapshots: yn@3.1.1: {} - yocto-queue@0.1.0: {} - yoctocolors-cjs@2.1.2: {} zod-to-json-schema@3.24.6(zod@3.25.76): diff --git a/integration/harness-e2e-cli/pnpm-workspace.yaml b/integration/harness-e2e-cli/pnpm-workspace.yaml index fcf4541cbe97..d37afeb21e69 100644 --- a/integration/harness-e2e-cli/pnpm-workspace.yaml +++ b/integration/harness-e2e-cli/pnpm-workspace.yaml @@ -1,3 +1,5 @@ +packages: + - . # The minimum age of a release to be considered for dependency installation. # The value is in minutes (1440 minutes = 1 day). diff --git a/integration/harness-e2e-cli/src/polyfills.ts b/integration/harness-e2e-cli/src/polyfills.ts deleted file mode 100644 index a5f4cc12dd0b..000000000000 --- a/integration/harness-e2e-cli/src/polyfills.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes recent versions of Safari, Chrome (including - * Opera), Edge on the desktop, and iOS and Chrome on mobile. - * - * Learn more in https://angular.dev/reference/versions#browser-support - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** - * By default, zone.js will patch all possible macroTask and DomEvents - * user can disable parts of macroTask/DomEvents patch by setting following flags - * because those flags need to be set before `zone.js` being loaded, and webpack - * will put import in the top of bundle, so user need to create a separate file - * in this directory (for example: zone-flags.ts), and put the following flags - * into that file, and then add the following code before importing zone.js. - * import './zone-flags'; - * - * The flags allowed in zone-flags.ts are listed here. - * - * The following flags will work for all browsers. - * - * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames - * - * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js - * with the following flag, it will bypass `zone.js` patch for IE/Edge - * - * (window as any).__Zone_enable_cross_context_check = true; - * - */ - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js'; // Included with Angular CLI. - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ diff --git a/integration/harness-e2e-cli/src/styles.scss b/integration/harness-e2e-cli/src/styles.css similarity index 100% rename from integration/harness-e2e-cli/src/styles.scss rename to integration/harness-e2e-cli/src/styles.css diff --git a/integration/harness-e2e-cli/tsconfig.app.json b/integration/harness-e2e-cli/tsconfig.app.json index ff396d4ce2d8..84f1f992d275 100644 --- a/integration/harness-e2e-cli/tsconfig.app.json +++ b/integration/harness-e2e-cli/tsconfig.app.json @@ -5,6 +5,6 @@ "outDir": "./out-tsc/app", "types": [] }, - "files": ["src/main.ts", "src/polyfills.ts"], + "files": ["src/main.ts"], "include": ["src/**/*.d.ts"] } diff --git a/integration/harness-e2e-cli/tsconfig.json b/integration/harness-e2e-cli/tsconfig.json index 45621ffb19eb..261341b1897f 100644 --- a/integration/harness-e2e-cli/tsconfig.json +++ b/integration/harness-e2e-cli/tsconfig.json @@ -1,29 +1,20 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "compileOnSave": false, "compilerOptions": { "baseUrl": "./", "outDir": "./dist/out-tsc", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, "sourceMap": true, + "esModuleInterop": true, "declaration": false, - "downlevelIteration": true, "experimentalDecorators": true, + "module": "es2022", "moduleResolution": "bundler", "importHelpers": true, - "target": "es2017", - "module": "es2020", - "lib": ["es2020", "dom"] + "target": "es2022", + "typeRoots": ["node_modules/@types"], + "lib": ["es2018", "dom"] }, "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, "strictTemplates": true } } diff --git a/integration/harness-e2e-cli/tsconfig.spec.json b/integration/harness-e2e-cli/tsconfig.spec.json deleted file mode 100644 index 669344f8d2b7..000000000000 --- a/integration/harness-e2e-cli/tsconfig.spec.json +++ /dev/null @@ -1,10 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "types": ["jasmine"] - }, - "files": ["src/test.ts", "src/polyfills.ts"], - "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] -} diff --git a/integration/module-tests/BUILD.bazel b/integration/module-tests/BUILD.bazel index 7f054902ae2c..8a63a493ed81 100644 --- a/integration/module-tests/BUILD.bazel +++ b/integration/module-tests/BUILD.bazel @@ -1,5 +1,5 @@ -load("//tools:defaults.bzl", "ts_project") load("//integration/module-tests:index.bzl", "module_test") +load("//tools:defaults.bzl", "ts_project") ts_project( name = "test_lib", diff --git a/integration/ng-add-standalone/pnpm-workspace.yaml b/integration/ng-add-standalone/pnpm-workspace.yaml index fcf4541cbe97..d37afeb21e69 100644 --- a/integration/ng-add-standalone/pnpm-workspace.yaml +++ b/integration/ng-add-standalone/pnpm-workspace.yaml @@ -1,3 +1,5 @@ +packages: + - . # The minimum age of a release to be considered for dependency installation. # The value is in minutes (1440 minutes = 1 day). diff --git a/integration/ng-add/pnpm-workspace.yaml b/integration/ng-add/pnpm-workspace.yaml index fcf4541cbe97..d37afeb21e69 100644 --- a/integration/ng-add/pnpm-workspace.yaml +++ b/integration/ng-add/pnpm-workspace.yaml @@ -1,3 +1,5 @@ +packages: + - . # The minimum age of a release to be considered for dependency installation. # The value is in minutes (1440 minutes = 1 day). diff --git a/integration/ts-compat/BUILD.bazel b/integration/ts-compat/BUILD.bazel index b1acfbd51a31..08d3da9c098f 100644 --- a/integration/ts-compat/BUILD.bazel +++ b/integration/ts-compat/BUILD.bazel @@ -1,5 +1,5 @@ -load("@bazel_skylib//rules:write_file.bzl", "write_file") load("@aspect_rules_js//js:defs.bzl", "js_test") +load("@bazel_skylib//rules:write_file.bzl", "write_file") load("//integration/ts-compat:import-all-entry-points.bzl", "generate_import_all_entry_points_file") package(default_visibility = ["//visibility:public"]) diff --git a/package.json b/package.json index dfa4439b9dda..1a6879d42377 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,11 @@ "url": "https://github.com/angular/components.git" }, "license": "MIT", - "packageManager": "pnpm@10.18.3", + "packageManager": "pnpm@10.24.0", "engines": { "npm": "Please use pnpm instead of NPM to install dependencies", "yarn": "Please use pnpm instead of Yarn to install dependencies", - "pnpm": "10.18.3" + "pnpm": "10.24.0" }, "scripts": { "ng-dev": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only node_modules/@angular/ng-dev/bundles/cli.mjs", @@ -20,6 +20,7 @@ "build": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only ./scripts/build-packages-dist-main.mts", "build-docs-content": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only ./scripts/build-docs-content-main.mts", "build-and-check-release-output": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only scripts/build-and-check-release-output.mts", + "build-snapshots": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only scripts/build-packages-dist-main.mts", "dev-app": "ibazel run //src/dev-app:devserver", "docs-app": "ibazel run //docs:serve", "universal-app": "bazel run //src/universal-app:server", @@ -27,7 +28,7 @@ "test-local": "pnpm -s test --local", "test-firefox": "pnpm -s test --firefox", "test-tsec": "pnpm bazelisk test //... --build_tag_filters=tsec --test_tag_filters=tsec", - "lint": "pnpm -s tslint && pnpm -s stylelint && pnpm -s ownerslint && pnpm -s ng-dev format changed --check", + "lint": "pnpm -s tslint && pnpm -s stylelint && pnpm -s ng-dev format changed --check", "e2e": "bazel test //src/... --build_tag_filters=e2e --test_tag_filters=e2e --build_tests_only", "deploy-dev-app": "node ./scripts/deploy-dev-app.js", "breaking-changes": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only scripts/breaking-changes.mts", @@ -35,7 +36,6 @@ "check-package-externals": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only scripts/check-package-externals.mts", "format": "pnpm -s ng-dev format changed", "cherry-pick-patch": "ts-node --project tools/cherry-pick-patch/tsconfig.json tools/cherry-pick-patch/cherry-pick-patch.ts", - "ownerslint": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only scripts/ownerslint.mts", "detect-component-id-collisions": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only scripts/detect-component-id-collisions.mts", "tslint": "tslint -c tslint.json --project ./tsconfig.json", "stylelint": "stylelint \"(src|docs)/**/*.+(css|scss)\" --config .stylelintrc.json", @@ -53,7 +53,7 @@ "ci-docs-monitor-test": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only scripts/docs-deploy/monitoring/ci-test.mts", "prepare": "husky" }, - "version": "21.0.0-next.9", + "version": "21.0.5", "dependencies": { "@angular-devkit/core": "catalog:", "@angular-devkit/schematics": "catalog:", @@ -76,7 +76,7 @@ "devDependencies": { "@angular/compiler-cli": "catalog:", "@angular/localize": "catalog:", - "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e", + "@angular/ng-dev": "https://github.com/angular/dev-infra-private-ng-dev-builds.git#24c98502339594196a800db33dd4294e359ea952", "@angular/platform-server": "catalog:", "@angular/router": "catalog:", "@babel/core": "^7.16.12", @@ -147,6 +147,7 @@ "tsutils": "^3.21.0", "typescript": "5.9.2", "vrsource-tslint-rules": "6.0.0", + "yaml": "^2.8.1", "yargs": "^18.0.0", "zx": "^8.0.0" }, diff --git a/pkg-externals.bzl b/pkg-externals.bzl index 6daef8043202..1729c610c585 100644 --- a/pkg-externals.bzl +++ b/pkg-externals.bzl @@ -20,6 +20,7 @@ PKG_EXTERNALS = [ "@angular/common/testing", "@angular/localize/init", "@angular/core", + "@angular/core/primitives/signals", "@angular/core/rxjs-interop", "@angular/core/testing", "@angular/forms", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3554c443a74a..2b3650c3924c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,53 +7,53 @@ settings: catalogs: default: '@angular-devkit/build-angular': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.3 + version: 21.0.3 '@angular-devkit/core': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.3 + version: 21.0.3 '@angular-devkit/schematics': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.3 + version: 21.0.3 '@angular/cli': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.3 + version: 21.0.3 '@angular/common': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.5 + version: 21.0.5 '@angular/compiler': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.5 + version: 21.0.5 '@angular/compiler-cli': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.5 + version: 21.0.5 '@angular/core': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.5 + version: 21.0.5 '@angular/forms': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.5 + version: 21.0.5 '@angular/localize': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.5 + version: 21.0.5 '@angular/platform-browser': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.5 + version: 21.0.5 '@angular/platform-browser-dynamic': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.5 + version: 21.0.5 '@angular/platform-server': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.5 + version: 21.0.5 '@angular/router': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.5 + version: 21.0.5 '@angular/ssr': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.3 + version: 21.0.3 '@schematics/angular': - specifier: 21.0.0-next.8 - version: 21.0.0-next.8 + specifier: 21.0.3 + version: 21.0.3 rxjs: specifier: ^6.6.7 version: 6.6.7 @@ -69,25 +69,25 @@ importers: dependencies: '@angular-devkit/core': specifier: 'catalog:' - version: 21.0.0-next.8(chokidar@4.0.3) + version: 21.0.3(chokidar@4.0.3) '@angular-devkit/schematics': specifier: 'catalog:' - version: 21.0.0-next.8(chokidar@4.0.3) + version: 21.0.3(chokidar@4.0.3) '@angular/common': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) + version: 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) '@angular/compiler': specifier: 'catalog:' - version: 21.0.0-next.8 + version: 21.0.5 '@angular/core': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) + version: 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) '@angular/forms': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) + version: 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) '@angular/platform-browser': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)) + version: 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)) '@types/google.maps': specifier: ^3.54.10 version: 3.58.1 @@ -121,22 +121,22 @@ importers: devDependencies: '@angular/compiler-cli': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2) + version: 21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2) '@angular/localize': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/compiler@21.0.0-next.8) + version: 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/compiler@21.0.5) '@angular/ng-dev': - specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e - version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e(@modelcontextprotocol/sdk@1.20.0) + specifier: https://github.com/angular/dev-infra-private-ng-dev-builds.git#24c98502339594196a800db33dd4294e359ea952 + version: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/24c98502339594196a800db33dd4294e359ea952(@modelcontextprotocol/sdk@1.24.3) '@angular/platform-server': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/compiler@21.0.0-next.8)(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) + version: 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/compiler@21.0.5)(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) '@angular/router': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) + version: 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) '@babel/core': specifier: ^7.16.12 - version: 7.28.4 + version: 7.28.5 '@bazel/bazelisk': specifier: 1.26.0 version: 1.26.0 @@ -160,13 +160,13 @@ importers: version: 22.0.0 '@rollup/plugin-commonjs': specifier: ^28.0.0 - version: 28.0.6(rollup@4.52.4) + version: 28.0.9(rollup@4.53.3) '@rollup/plugin-node-resolve': specifier: ^16.0.0 - version: 16.0.2(rollup@4.52.4) + version: 16.0.3(rollup@4.53.3) '@schematics/angular': specifier: 'catalog:' - version: 21.0.0-next.8(chokidar@4.0.3) + version: 21.0.3(chokidar@4.0.3) '@types/babel__core': specifier: ^7.1.18 version: 7.20.5 @@ -175,13 +175,13 @@ importers: version: 11.0.4 '@types/jasmine': specifier: ^5.0.0 - version: 5.1.9 + version: 5.1.12 '@types/luxon': specifier: ^3.0.0 version: 3.7.1 '@types/node': specifier: ^22.14.1 - version: 22.18.8 + version: 22.19.2 '@types/selenium-webdriver': specifier: ^3.0.17 version: 3.0.26 @@ -193,13 +193,13 @@ importers: version: 0.8.17 '@types/yargs': specifier: ^17.0.8 - version: 17.0.33 + version: 17.0.35 autoprefixer: specifier: ^10.4.2 - version: 10.4.21(postcss@8.5.6) + version: 10.4.22(postcss@8.5.6) axe-core: specifier: ^4.10.3 - version: 4.10.3 + version: 4.11.0 chalk: specifier: ^5.4.1 version: 5.6.2 @@ -211,16 +211,16 @@ importers: version: 0.30.0(dgeni@0.4.14) esbuild: specifier: ^0.25.0 - version: 0.25.10 + version: 0.25.12 firebase-tools: specifier: 14.20.0 - version: 14.20.0(@types/node@22.18.8)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2) + version: 14.20.0(@types/node@22.19.2)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2) fs-extra: specifier: ^11.0.0 version: 11.3.2 glob: specifier: ^11.0.3 - version: 11.0.3 + version: 11.1.0 highlight.js: specifier: ^11.0.0 version: 11.11.1 @@ -229,7 +229,7 @@ importers: version: 9.1.7 jasmine: specifier: ^5.6.0 - version: 5.11.0 + version: 5.13.0 jasmine-core: specifier: 5.12.0 version: 5.12.0 @@ -262,10 +262,10 @@ importers: version: 0.30.19 marked: specifier: ^16.0.0 - version: 16.3.0 + version: 16.4.2 minimatch: specifier: ^10.0.3 - version: 10.0.3 + version: 10.1.1 parse5: specifier: ^8.0.0 version: 8.0.0 @@ -277,22 +277,22 @@ importers: version: 4.0.9(postcss@8.5.6) prettier: specifier: ^3.5.3 - version: 3.6.2 + version: 3.7.4 protractor: specifier: ^7.0.0 version: 7.0.0 requirejs: specifier: ^2.3.6 - version: 2.3.7 + version: 2.3.8 rollup: specifier: ^4.52.3 - version: 4.52.4 + version: 4.53.3 rollup-plugin-dts: specifier: 6.2.3 - version: 6.2.3(rollup@4.52.4)(typescript@5.9.2) + version: 6.2.3(rollup@4.53.3)(typescript@5.9.2) rollup-plugin-sourcemaps2: specifier: 0.5.4 - version: 0.5.4(@types/node@22.18.8)(rollup@4.52.4) + version: 0.5.4(@types/node@22.19.2)(rollup@4.53.3) sass: specifier: ^1.80.6 version: 1.93.2 @@ -301,7 +301,7 @@ importers: version: 3.6.0 semver: specifier: ^7.3.5 - version: 7.7.2 + version: 7.7.3 shelljs: specifier: ^0.10.0 version: 0.10.0 @@ -316,10 +316,10 @@ importers: version: 14.16.1 terser: specifier: ^5.10.0 - version: 5.44.0 + version: 5.44.1 ts-node: specifier: ^10.9.1 - version: 10.9.2(@types/node@22.18.8)(typescript@5.9.2) + version: 10.9.2(@types/node@22.19.2)(typescript@5.9.2) tsec: specifier: 0.2.9 version: 0.2.9(@bazel/bazelisk@1.26.0)(typescript@5.9.2) @@ -338,12 +338,15 @@ importers: vrsource-tslint-rules: specifier: 6.0.0 version: 6.0.0(tslint@6.1.3(typescript@5.9.2))(typescript@5.9.2) + yaml: + specifier: ^2.8.1 + version: 2.8.2 yargs: specifier: ^18.0.0 version: 18.0.0 zx: specifier: ^8.0.0 - version: 8.8.4 + version: 8.8.5 docs: dependencies: @@ -358,25 +361,25 @@ importers: version: link:../src/cdk-experimental '@angular/common': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) + version: 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) '@angular/compiler': specifier: 'catalog:' - version: 21.0.0-next.8 + version: 21.0.5 '@angular/components-examples': specifier: workspace:* version: link:../src/components-examples '@angular/core': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) + version: 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) '@angular/forms': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) + version: 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) '@angular/google-maps': specifier: workspace:* version: link:../src/google-maps '@angular/localize': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/compiler@21.0.0-next.8) + version: 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/compiler@21.0.5) '@angular/material': specifier: workspace:* version: link:../src/material @@ -388,16 +391,16 @@ importers: version: link:../src/material-luxon-adapter '@angular/platform-browser': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)) + version: 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)) '@angular/platform-browser-dynamic': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler@21.0.0-next.8)(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))) + version: 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler@21.0.5)(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))) '@angular/router': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) + version: 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) '@angular/ssr': specifier: 'catalog:' - version: 21.0.0-next.8(97a956334e4483b817e98b9a94c98525) + version: 21.0.3(29820ad2842b06a07ed5fa27341aa1ea) '@angular/youtube-player': specifier: workspace:* version: link:../src/youtube-player @@ -422,13 +425,13 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 'catalog:' - version: 21.0.0-next.8(cfe8a97e2176695474f8a07e88e10fe8) + version: 21.0.3(a4728fe13469fa501a2f42d499133d45) '@angular/cli': specifier: 'catalog:' - version: 21.0.0-next.8(@types/node@22.18.8)(chokidar@4.0.3) + version: 21.0.3(@types/node@22.19.2)(chokidar@4.0.3) '@angular/compiler-cli': specifier: 'catalog:' - version: 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2) + version: 21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2) '@bazel/bazelisk': specifier: ^1.12.1 version: 1.26.0 @@ -437,13 +440,13 @@ importers: version: 5.1.12 '@types/node': specifier: ^22.14.1 - version: 22.18.8 + version: 22.19.2 '@types/shelljs': specifier: 0.8.17 version: 0.8.17 firebase-tools: specifier: ^14.0.0 - version: 14.17.0(@types/node@22.18.8)(bufferutil@4.0.9)(encoding@0.1.13) + version: 14.20.0(@types/node@22.19.2)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2) jasmine-core: specifier: 5.12.0 version: 5.12.0 @@ -473,7 +476,7 @@ importers: version: 2.9.1(bufferutil@4.0.9) lighthouse: specifier: ^13.0.0 - version: 13.0.0(bufferutil@4.0.9) + version: 13.0.1(bufferutil@4.0.9) lighthouse-logger: specifier: ~2.0.0 version: 2.0.2 @@ -485,7 +488,7 @@ importers: version: 7.0.0 puppeteer-core: specifier: ^24.6.1 - version: 24.23.0(bufferutil@4.0.9) + version: 24.32.1(bufferutil@4.0.9) sass: specifier: 1.93.2 version: 1.93.2 @@ -494,7 +497,7 @@ importers: version: 0.10.0 ts-node: specifier: 10.9.2 - version: 10.9.2(@types/node@22.18.8)(typescript@5.9.2) + version: 10.9.2(@types/node@22.19.2)(typescript@5.9.2) typescript: specifier: 5.9.2 version: 5.9.2 @@ -719,99 +722,99 @@ importers: packages: - '@actions/core@1.11.1': - resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==} + '@actions/core@2.0.1': + resolution: {integrity: sha512-oBfqT3GwkvLlo1fjvhQLQxuwZCGTarTE5OuZ2Wg10hvhBj7LRIlF611WT4aZS6fDhO5ZKlY7lCAZTlpmyaHaeg==} - '@actions/exec@1.1.1': - resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==} + '@actions/exec@2.0.0': + resolution: {integrity: sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw==} - '@actions/http-client@2.2.3': - resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==} + '@actions/http-client@3.0.0': + resolution: {integrity: sha512-1s3tXAfVMSz9a4ZEBkXXRQD4QhY3+GAsWSbaYpeknPOKEeyRiU3lH+bHiLMZdo2x/fIeQ/hscL1wCkDLVM2DZQ==} - '@actions/io@1.1.3': - resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==} + '@actions/io@2.0.0': + resolution: {integrity: sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg==} - '@algolia/abtesting@1.6.0': - resolution: {integrity: sha512-c4M/Z/KWkEG+RHpZsWKDTTlApXu3fe4vlABNcpankWBhdMe4oPZ/r4JxEr2zKUP6K+BT66tnp8UbHmgOd/vvqQ==} + '@algolia/abtesting@1.6.1': + resolution: {integrity: sha512-wV/gNRkzb7sI9vs1OneG129hwe3Q5zPj7zigz3Ps7M5Lpo2hSorrOnXNodHEOV+yXE/ks4Pd+G3CDFIjFTWhMQ==} engines: {node: '>= 14.0.0'} - '@algolia/client-abtesting@5.40.0': - resolution: {integrity: sha512-qegVlgHtmiS8m9nEsuKUVhlw1FHsIshtt5nhNnA6EYz3g+tm9+xkVZZMzkrMLPP7kpoheHJZAwz2MYnHtwFa9A==} + '@algolia/client-abtesting@5.40.1': + resolution: {integrity: sha512-cxKNATPY5t+Mv8XAVTI57altkaPH+DZi4uMrnexPxPHODMljhGYY+GDZyHwv9a+8CbZHcY372OkxXrDMZA4Lnw==} engines: {node: '>= 14.0.0'} - '@algolia/client-analytics@5.40.0': - resolution: {integrity: sha512-Dw2c+6KGkw7mucnnxPyyMsIGEY8+hqv6oB+viYB612OMM3l8aNaWToBZMnNvXsyP+fArwq7XGR+k3boPZyV53A==} + '@algolia/client-analytics@5.40.1': + resolution: {integrity: sha512-XP008aMffJCRGAY8/70t+hyEyvqqV7YKm502VPu0+Ji30oefrTn2al7LXkITz7CK6I4eYXWRhN6NaIUi65F1OA==} engines: {node: '>= 14.0.0'} - '@algolia/client-common@5.40.0': - resolution: {integrity: sha512-dbE4+MJIDsTghG3hUYWBq7THhaAmqNqvW9g2vzwPf5edU4IRmuYpKtY3MMotes8/wdTasWG07XoaVhplJBlvdg==} + '@algolia/client-common@5.40.1': + resolution: {integrity: sha512-gWfQuQUBtzUboJv/apVGZMoxSaB0M4Imwl1c9Ap+HpCW7V0KhjBddqF2QQt5tJZCOFsfNIgBbZDGsEPaeKUosw==} engines: {node: '>= 14.0.0'} - '@algolia/client-insights@5.40.0': - resolution: {integrity: sha512-SH6zlROyGUCDDWg71DlCnbbZ/zEHYPZC8k901EAaBVhvY43Ju8Wa6LAcMPC4tahcDBgkG2poBy8nJZXvwEWAlQ==} + '@algolia/client-insights@5.40.1': + resolution: {integrity: sha512-RTLjST/t+lsLMouQ4zeLJq2Ss+UNkLGyNVu+yWHanx6kQ3LT5jv8UvPwyht9s7R6jCPnlSI77WnL80J32ZuyJg==} engines: {node: '>= 14.0.0'} - '@algolia/client-personalization@5.40.0': - resolution: {integrity: sha512-EgHjJEEf7CbUL9gJHI1ULmAtAFeym2cFNSAi1uwHelWgLPcnLjYW2opruPxigOV7NcetkGu+t2pcWOWmZFuvKQ==} + '@algolia/client-personalization@5.40.1': + resolution: {integrity: sha512-2FEK6bUomBzEYkTKzD0iRs7Ljtjb45rKK/VSkyHqeJnG+77qx557IeSO0qVFE3SfzapNcoytTofnZum0BQ6r3Q==} engines: {node: '>= 14.0.0'} - '@algolia/client-query-suggestions@5.40.0': - resolution: {integrity: sha512-HvE1jtCag95DR41tDh7cGwrMk4X0aQXPOBIhZRmsBPolMeqRJz0kvfVw8VCKvA1uuoAkjFfTG0X0IZED+rKXoA==} + '@algolia/client-query-suggestions@5.40.1': + resolution: {integrity: sha512-Nju4NtxAvXjrV2hHZNLKVJLXjOlW6jAXHef/CwNzk1b2qIrCWDO589ELi5ZHH1uiWYoYyBXDQTtHmhaOVVoyXg==} engines: {node: '>= 14.0.0'} - '@algolia/client-search@5.40.0': - resolution: {integrity: sha512-nlr/MMgoLNUHcfWC5Ns2ENrzKx9x51orPc6wJ8Ignv1DsrUmKm0LUih+Tj3J+kxYofzqQIQRU495d4xn3ozMbg==} + '@algolia/client-search@5.40.1': + resolution: {integrity: sha512-Mw6pAUF121MfngQtcUb5quZVqMC68pSYYjCRZkSITC085S3zdk+h/g7i6FxnVdbSU6OztxikSDMh1r7Z+4iPlA==} engines: {node: '>= 14.0.0'} - '@algolia/ingestion@1.40.0': - resolution: {integrity: sha512-OfHnhE+P0f+p3i90Kmshf9Epgesw5oPV1IEUOY4Mq1HV7cQk16gvklVN1EaY/T9sVavl+Vc3g4ojlfpIwZFA4g==} + '@algolia/ingestion@1.40.1': + resolution: {integrity: sha512-z+BPlhs45VURKJIxsR99NNBWpUEEqIgwt10v/fATlNxc4UlXvALdOsWzaFfe89/lbP5Bu4+mbO59nqBC87ZM/g==} engines: {node: '>= 14.0.0'} - '@algolia/monitoring@1.40.0': - resolution: {integrity: sha512-SWANV32PTKhBYvwKozeWP9HOnVabOixAuPdFFGoqtysTkkwutrtGI/rrh80tvG+BnQAmZX0vUmD/RqFZVfr/Yg==} + '@algolia/monitoring@1.40.1': + resolution: {integrity: sha512-VJMUMbO0wD8Rd2VVV/nlFtLJsOAQvjnVNGkMkspFiFhpBA7s/xJOb+fJvvqwKFUjbKTUA7DjiSi1ljSMYBasXg==} engines: {node: '>= 14.0.0'} - '@algolia/recommend@5.40.0': - resolution: {integrity: sha512-1Qxy9I5bSb3mrhPk809DllMa561zl5hLsMR6YhIqNkqQ0OyXXQokvJ2zApSxvd39veRZZnhN+oGe+XNoNwLgkw==} + '@algolia/recommend@5.40.1': + resolution: {integrity: sha512-ehvJLadKVwTp9Scg9NfzVSlBKH34KoWOQNTaN8i1Ac64AnO6iH2apJVSP6GOxssaghZ/s8mFQsDH3QIZoluFHA==} engines: {node: '>= 14.0.0'} - '@algolia/requester-browser-xhr@5.40.0': - resolution: {integrity: sha512-MGt94rdHfkrVjfN/KwUfWcnaeohYbWGINrPs96f5J7ZyRYpVLF+VtPQ2FmcddFvK4gnKXSu8BAi81hiIhUpm3w==} + '@algolia/requester-browser-xhr@5.40.1': + resolution: {integrity: sha512-PbidVsPurUSQIr6X9/7s34mgOMdJnn0i6p+N6Ab+lsNhY5eiu+S33kZEpZwkITYBCIbhzDLOvb7xZD3gDi+USA==} engines: {node: '>= 14.0.0'} - '@algolia/requester-fetch@5.40.0': - resolution: {integrity: sha512-wXQ05JZZ10Dr642QVAkAZ4ZZlU+lh5r6dIBGmm9WElz+1EaQ6BNYtEOTV6pkXuFYsZpeJA89JpDOiwBOP9j24w==} + '@algolia/requester-fetch@5.40.1': + resolution: {integrity: sha512-ThZ5j6uOZCF11fMw9IBkhigjOYdXGXQpj6h4k+T9UkZrF2RlKcPynFzDeRgaLdpYk8Yn3/MnFbwUmib7yxj5Lw==} engines: {node: '>= 14.0.0'} - '@algolia/requester-node-http@5.40.0': - resolution: {integrity: sha512-5qCRoySnzpbQVg2IPLGFCm4LF75pToxI5tdjOYgUMNL/um91aJ4dH3SVdBEuFlVsalxl8mh3bWPgkUmv6NpJiQ==} + '@algolia/requester-node-http@5.40.1': + resolution: {integrity: sha512-H1gYPojO6krWHnUXu/T44DrEun/Wl95PJzMXRcM/szstNQczSbwq6wIFJPI9nyE95tarZfUNU3rgorT+wZ6iCQ==} engines: {node: '>= 14.0.0'} '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@angular-devkit/architect@0.2100.0-next.8': - resolution: {integrity: sha512-tY3Q3cr+GuRwWKvXWMUqPf0h9kJNeUYwEdXyHuVbp5lLBAraL9JSXmtE6EZewprUGco5DsYQshh9zedr4AGwiw==} + '@angular-devkit/architect@0.2100.3': + resolution: {integrity: sha512-PcruWF0+IxXOTZd9MN/3y4A5aTfblALzT/+zWym26PtisaBgWQ3tRPQsf/CgT8EdmZl8eUOAWlNBSkbUj/S/lQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-devkit/build-angular@21.0.0-next.8': - resolution: {integrity: sha512-IISlniBqsSjRkSLyGliJ41xXrnzvGFiYifQTgsoq1sdl3xJIToJDgcWlDa2kOSxVslWG/HtHFF5gK8qZvgpe0A==} + '@angular-devkit/build-angular@21.0.3': + resolution: {integrity: sha512-KcaI9sDvY6rVsVvILSNBIzJaE5+KcapULShMInD90px9X0QoajXgm8l63FiQOBCNkZt+todMM0h3+u6y7UPsYQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: - '@angular/compiler-cli': ^21.0.0-next.0 - '@angular/core': ^21.0.0-next.0 - '@angular/localize': ^21.0.0-next.0 - '@angular/platform-browser': ^21.0.0-next.0 - '@angular/platform-server': ^21.0.0-next.0 - '@angular/service-worker': ^21.0.0-next.0 - '@angular/ssr': ^21.0.0-next.8 + '@angular/compiler-cli': ^21.0.0 + '@angular/core': ^21.0.0 + '@angular/localize': ^21.0.0 + '@angular/platform-browser': ^21.0.0 + '@angular/platform-server': ^21.0.0 + '@angular/service-worker': ^21.0.0 + '@angular/ssr': ^21.0.3 '@web/test-runner': ^0.20.0 browser-sync: ^3.0.2 jest: ^30.2.0 jest-environment-jsdom: ^30.2.0 karma: ^6.3.0 - ng-packagr: ^21.0.0-next.0 + ng-packagr: ^21.0.0 protractor: ^7.0.0 tailwindcss: ^2.0.0 || ^3.0.0 || ^4.0.0 typescript: 5.9.2 @@ -845,15 +848,15 @@ packages: tailwindcss: optional: true - '@angular-devkit/build-webpack@0.2100.0-next.8': - resolution: {integrity: sha512-zANZET32iXj37Na+XQBUwO4Yhkdxxz0vEdxOs6rKN3iOdYZOR8KXOLvV2YUyMP3xOwZxDA+yAFhi/qZFypAJ4w==} + '@angular-devkit/build-webpack@0.2100.3': + resolution: {integrity: sha512-q76y3iwua3eL3pF3zlKRvDYgnICVWexyReQWIEcCHb4Q4K5hDeJCAO1eLX9no+xmTzbavCADmqcJ6hOkyRjw6g==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: webpack: ^5.30.0 webpack-dev-server: ^5.0.2 - '@angular-devkit/core@21.0.0-next.8': - resolution: {integrity: sha512-LsIs9UUYOQUcuobiEcBqgqkKpq6pa8dQEVTTj/g42V82ZjTb36Xq3SqiEJGwwbS0gIehFRTsCvKsSgzUSan/ig==} + '@angular-devkit/core@21.0.3': + resolution: {integrity: sha512-X1y3GMYru9+Vt7vz+R8SFAEmDtgf0aZ+1JOpiE7ubHsQOnhA++Pb94HBjQ6CHqlUhQli/XPOBksKNdZkpup8rQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: chokidar: ^4.0.0 @@ -861,30 +864,30 @@ packages: chokidar: optional: true - '@angular-devkit/schematics@21.0.0-next.8': - resolution: {integrity: sha512-GQx2g1pye/Z2tnvC7zNpWdzzFkJ6wTyRB2dlpZfzkS81MB0KZSouhGSByRBF9uW4KUQ/uQDWVfjIq8nrVArpJQ==} + '@angular-devkit/schematics@21.0.3': + resolution: {integrity: sha512-E/Nja+RIyMzjqLXREOnTRwv7GMrycpAD7kGwDg7l8cWrNQ7phqBZcXAt74Jv9K9aYsOC8tw2Ms9t59aQ6iow8w==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular/build@21.0.0-next.8': - resolution: {integrity: sha512-2D6KXdh8cn6lFjzqEfIlY5rwZdBSN6iqi83+fFCIC3qITcai7E4dI6R/5REuZFVo0YMa4KK9KQzFRqGPdrod9A==} + '@angular/build@21.0.3': + resolution: {integrity: sha512-3h2s0Igruei1RB/Hmu7nwbKvjJQ2ykNaiicXYuS2muWUBhDg+lm0QsGTGXrQV2BD0M9YdHU4Byh9upiZgMYpjA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: - '@angular/compiler': ^21.0.0-next.0 - '@angular/compiler-cli': ^21.0.0-next.0 - '@angular/core': ^21.0.0-next.0 - '@angular/localize': ^21.0.0-next.0 - '@angular/platform-browser': ^21.0.0-next.0 - '@angular/platform-server': ^21.0.0-next.0 - '@angular/service-worker': ^21.0.0-next.0 - '@angular/ssr': ^21.0.0-next.8 + '@angular/compiler': ^21.0.0 + '@angular/compiler-cli': ^21.0.0 + '@angular/core': ^21.0.0 + '@angular/localize': ^21.0.0 + '@angular/platform-browser': ^21.0.0 + '@angular/platform-server': ^21.0.0 + '@angular/service-worker': ^21.0.0 + '@angular/ssr': ^21.0.3 karma: ^6.4.0 less: ^4.2.0 - ng-packagr: ^21.0.0-next.0 + ng-packagr: ^21.0.0 postcss: ^8.4.0 tailwindcss: ^2.0.0 || ^3.0.0 || ^4.0.0 tslib: ^2.3.0 typescript: 5.9.2 - vitest: ^3.1.1 + vitest: ^4.0.8 peerDependenciesMeta: '@angular/core': optional: true @@ -911,115 +914,115 @@ packages: vitest: optional: true - '@angular/cli@21.0.0-next.8': - resolution: {integrity: sha512-+pVNpTQonKnjVAME9pvttqcOKKfR+qsZbA8YGVfT4OaneDc4Y8N/wVgz90yxOCv7axQXbXHNtx3Nx9TQiEPtGA==} + '@angular/cli@21.0.3': + resolution: {integrity: sha512-3lMR3J231JhLgAt37yEULSHFte3zPeta9VYpIIf92JiBsTnWrvKnaK8RXhfdiSQrvhqQ9FMQdl5AG62r1c4dbA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} hasBin: true - '@angular/common@21.0.0-next.8': - resolution: {integrity: sha512-x9sh/uhFVFrrOwVC+FC7gufkZxs1IPOCIx5lps6mqykQ30ihZ6vQLfJqY+XJ/N1y73o50qCAVK3IpzLNBWkgMQ==} + '@angular/common@21.0.5': + resolution: {integrity: sha512-/ZI11F6Wxr8TZRVO4O7pmhBJ9YxDg9mvA76e0PiivmqZggM02HY0y3XPMP3hAOe4K+PfaVBgMAu3P9t32klzfA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/core': 21.0.0-next.8 + '@angular/core': 21.0.5 rxjs: ^6.5.3 || ^7.4.0 - '@angular/compiler-cli@21.0.0-next.8': - resolution: {integrity: sha512-o1B9/B7jM2GuDrfUw1UzkJpMCZ8ycpUi2DrcHtIiOZtqBbnfodASNLmzGaW8uEbNeB0h7PdYXxdFMvVYpWQv8g==} + '@angular/compiler-cli@21.0.5': + resolution: {integrity: sha512-45sFKqt+badXl6Ab2XsxuOsdi0BbIZgcc9TdwmFPdXMNfcSUYDcPiOA0l1iPwDIZiu4VyqzepMfnHB9IwCatgA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} hasBin: true peerDependencies: - '@angular/compiler': 21.0.0-next.8 + '@angular/compiler': 21.0.5 typescript: 5.9.2 peerDependenciesMeta: typescript: optional: true - '@angular/compiler@21.0.0-next.8': - resolution: {integrity: sha512-5Fkzhs5zpCy2IhIK0Osw3RyRqlrwUdcJNGJ/UbkUJuEE4VBEFXbd1evZa/mf5YIQFNhK0WW2zY3zMABTtGMweg==} + '@angular/compiler@21.0.5': + resolution: {integrity: sha512-92sv9pVm9o/8KfPM7T8j5VQmTaSOqmIajrJF8evXE2dNJcwkBpVtzZUqDzr23AV3vg94C7eYU64i8qrsmJ+cYQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@angular/core@21.0.0-next.8': - resolution: {integrity: sha512-+omCS1MesfEPVuebs/wUWj6f5xeiRQWjLe70lpbuRPdEgmgOzPOgZKG8828yhPqU1XqJEUjjghfiAIdM6+tYhw==} + '@angular/core@21.0.5': + resolution: {integrity: sha512-HFXfO5YsBVM+IEaU8h3DZSxO98yDZM2v49NlSVNDzFD3fhnkpTmcgT2NKz9ulIiuV9N376itt+x+NG12sg/+Fw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/compiler': 21.0.0-next.8 + '@angular/compiler': 21.0.5 rxjs: ^6.5.3 || ^7.4.0 - zone.js: ~0.15.0 + zone.js: ~0.15.0 || ~0.16.0 peerDependenciesMeta: '@angular/compiler': optional: true zone.js: optional: true - '@angular/forms@21.0.0-next.8': - resolution: {integrity: sha512-Xsdyd3/76phasRu6xs79llRai4kioh/AJsD2WpZ1c9pWh4hFoYcmfTDYle0KmKPZs2+HJPUmQ6DjS152LD21OA==} + '@angular/forms@21.0.5': + resolution: {integrity: sha512-RcmXs/LgKyc7D70xVT+3aK/H2SCFEyuebAiw72Iz1te1Gbql2GDFF6hgEOaNwOUglDg8ogN5MdVif2DbRLD3Hw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 21.0.0-next.8 - '@angular/core': 21.0.0-next.8 - '@angular/platform-browser': 21.0.0-next.8 + '@angular/common': 21.0.5 + '@angular/core': 21.0.5 + '@angular/platform-browser': 21.0.5 '@standard-schema/spec': ^1.0.0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/localize@21.0.0-next.8': - resolution: {integrity: sha512-fIIjunzHQSPy9yka7VWo4RnnMM/A/vQsD/zylykG4EPr4PZpuKXKd6LmEX1DBRNOUa9N1cmkrH00zkCKfy81eQ==} + '@angular/localize@21.0.5': + resolution: {integrity: sha512-IbpddjCnwxsP//VQwMffrQgrr5WcqS6AWg5Ebyr/YKF67ttvvJa9w/wpSdNYleoDwL6/Pia/GYTcbkG4odTafA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} hasBin: true peerDependencies: - '@angular/compiler': 21.0.0-next.8 - '@angular/compiler-cli': 21.0.0-next.8 + '@angular/compiler': 21.0.5 + '@angular/compiler-cli': 21.0.5 - '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e': - resolution: {tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e} - version: 0.0.0-c584c3565b71c7a8cda81d55bb14e3e66ef934da + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/24c98502339594196a800db33dd4294e359ea952': + resolution: {tarball: https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/24c98502339594196a800db33dd4294e359ea952} + version: 0.0.0-dd5658bd720370542913e23b21d80450bac94b60 hasBin: true - '@angular/platform-browser-dynamic@21.0.0-next.8': - resolution: {integrity: sha512-xWbDsZy3NZArnZ5H/dr2uSvloTWTy1ABYyEG22H6fkOtwwqyjXMZY5x8WtUww7R4UZ+kAfVvvVLX3nuwE5L3jw==} + '@angular/platform-browser-dynamic@21.0.5': + resolution: {integrity: sha512-0P5vFSS6UhiU7IBeVqPEKmRhMtyQqyXGN9+zF7kLK8H0cx1j0eGVmHRsVuY2YKoVp97fXDIeVGSbO0t5ZcFhoA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 21.0.0-next.8 - '@angular/compiler': 21.0.0-next.8 - '@angular/core': 21.0.0-next.8 - '@angular/platform-browser': 21.0.0-next.8 + '@angular/common': 21.0.5 + '@angular/compiler': 21.0.5 + '@angular/core': 21.0.5 + '@angular/platform-browser': 21.0.5 - '@angular/platform-browser@21.0.0-next.8': - resolution: {integrity: sha512-nOdVbkHDGpi0pNTFd/uhyBXX/z1zzq72p3m7G3yoCME3e/soekJMK5E0yRlliL7bK2yA3gH8UjOuh1hXsExMQg==} + '@angular/platform-browser@21.0.5': + resolution: {integrity: sha512-UVCrqOxFmX6kAG3Y6jqjCWvLoTP7fxeY96AsxTMp1fkBdqbQbEPleWQpwngNimsuUPvf+rA6XOxsqiDmRex5mA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/animations': 21.0.0-next.8 - '@angular/common': 21.0.0-next.8 - '@angular/core': 21.0.0-next.8 + '@angular/animations': 21.0.5 + '@angular/common': 21.0.5 + '@angular/core': 21.0.5 peerDependenciesMeta: '@angular/animations': optional: true - '@angular/platform-server@21.0.0-next.8': - resolution: {integrity: sha512-Yfc4GtHh+w9LKJccI5Quo5NSnxodyZ4yy/CwcAkF3WrWbvxjjGel1Fv3U2ZU6JzDkLtkeTk7tibs9CZghdG9qQ==} + '@angular/platform-server@21.0.5': + resolution: {integrity: sha512-Yw8f4XRZp4OTtLaGiF2ekGwF7zjWVKzErwNXRaJb6tERKua/+3JpLKWQMkreJQolqEplPk3ngkoyExDGMB+DNQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 21.0.0-next.8 - '@angular/compiler': 21.0.0-next.8 - '@angular/core': 21.0.0-next.8 - '@angular/platform-browser': 21.0.0-next.8 + '@angular/common': 21.0.5 + '@angular/compiler': 21.0.5 + '@angular/core': 21.0.5 + '@angular/platform-browser': 21.0.5 rxjs: ^6.5.3 || ^7.4.0 - '@angular/router@21.0.0-next.8': - resolution: {integrity: sha512-1tqI7+jy1JtCXUdRkemDSAFttUZkYn8ZmAHvDJLVQIz1hlkDUYNu/482J6HbOBVvnsKFO/gTdc43Z5pUKzj9eQ==} + '@angular/router@21.0.5': + resolution: {integrity: sha512-IFmf0Wd7jSOoZ8TI+4RXMsYmnIfHQG+kGxeMQVKrefTdr3uEHW/TEsNzbW5bkCpVJHRm4EhkH4hSu8D8tUQffQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 21.0.0-next.8 - '@angular/core': 21.0.0-next.8 - '@angular/platform-browser': 21.0.0-next.8 + '@angular/common': 21.0.5 + '@angular/core': 21.0.5 + '@angular/platform-browser': 21.0.5 rxjs: ^6.5.3 || ^7.4.0 - '@angular/ssr@21.0.0-next.8': - resolution: {integrity: sha512-ow3Ew2MLSx7lEnJ4JCRIh8j9xW1jAW1NdhN7ZId7UN9PFCFRb5HoX8qAklKxgX8/BARpfbvgmqmpyugKal6szg==} + '@angular/ssr@21.0.3': + resolution: {integrity: sha512-waHJ1hEhDoKMJlABiaysbWqwaxDE5S/MQ9Ykq1GdudFuj+T7e/S4KKmy2pusEShVX4ztrJiBskT9zeO6P1qvAg==} peerDependencies: - '@angular/common': ^21.0.0-next.0 - '@angular/core': ^21.0.0-next.0 - '@angular/platform-server': ^21.0.0-next.0 - '@angular/router': ^21.0.0-next.0 + '@angular/common': ^21.0.0 + '@angular/core': ^21.0.0 + '@angular/platform-server': ^21.0.0 + '@angular/router': ^21.0.0 peerDependenciesMeta: '@angular/platform-server': optional: true @@ -1027,19 +1030,22 @@ packages: '@apidevtools/json-schema-ref-parser@9.1.2': resolution: {integrity: sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==} - '@apphosting/build@0.1.6': - resolution: {integrity: sha512-nXK1wsR1tehaq9uSRDCGQmN+Dp0xbyGohssYd7g4W8ZbzHfUiab+Pabv34pHVTS03VaSVkjdNcR1g9hezi6s8g==} + '@apphosting/build@0.1.7': + resolution: {integrity: sha512-zNgQGiAWDOj6c+4ylv5ej3nLGXzMAVmzCGMqlbSarHe4bvBmZ2C5GfBRdJksedP7C9pqlwTWpxU5+GSzhJ+nKA==} hasBin: true '@apphosting/common@0.0.8': resolution: {integrity: sha512-RJu5gXs2HYV7+anxpVPpp04oXeuHbV3qn402AdXVlnuYM/uWo7aceqmngpfp6Bi376UzRqGjfpdwFHxuwsEGXQ==} + '@apphosting/common@0.0.9': + resolution: {integrity: sha512-ZbPZDcVhEN+8m0sf90PmQN4xWaKmmySnBSKKPaIOD0JvcDsRr509WenFEFlojP++VSxwFZDGG/TYsHs1FMMqpw==} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.4': - resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} engines: {node: '>=6.9.0'} '@babel/core@7.26.10': @@ -1050,10 +1056,18 @@ packages: resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} engines: {node: '>=6.9.0'} + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.28.3': resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -1062,14 +1076,14 @@ packages: resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.3': - resolution: {integrity: sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==} + '@babel/helper-create-class-features-plugin@7.28.5': + resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.27.1': - resolution: {integrity: sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==} + '@babel/helper-create-regexp-features-plugin@7.28.5': + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1083,8 +1097,8 @@ packages: resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.27.1': - resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.27.1': @@ -1129,8 +1143,8 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} '@babel/helper-validator-option@7.27.1': @@ -1145,13 +1159,13 @@ packages: resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.4': - resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1': - resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1228,8 +1242,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.28.4': - resolution: {integrity: sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==} + '@babel/plugin-transform-block-scoping@7.28.5': + resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1258,8 +1272,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.28.0': - resolution: {integrity: sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==} + '@babel/plugin-transform-destructuring@7.28.5': + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1294,8 +1308,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.27.1': - resolution: {integrity: sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==} + '@babel/plugin-transform-exponentiation-operator@7.28.5': + resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1330,8 +1344,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.27.1': - resolution: {integrity: sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==} + '@babel/plugin-transform-logical-assignment-operators@7.28.5': + resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1354,8 +1368,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.27.1': - resolution: {integrity: sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==} + '@babel/plugin-transform-modules-systemjs@7.28.5': + resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1408,8 +1422,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.27.1': - resolution: {integrity: sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==} + '@babel/plugin-transform-optional-chaining@7.28.5': + resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1535,12 +1549,12 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.4': - resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.4': - resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} '@bazel/bazelisk@1.26.0': @@ -1595,178 +1609,490 @@ packages: resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==} engines: {node: '>=14.17.0'} - '@electric-sql/pglite-tools@0.2.15': - resolution: {integrity: sha512-PPvfCaYWjYmVVFykB/KLcWDktm3YtuJEeAGL82LhEAzb5IMjUeLiCtsfH80S0N+lF267x+0D2Y1203up6Gb1FA==} + '@electric-sql/pglite-tools@0.2.19': + resolution: {integrity: sha512-Ls4ZcSymnFRlEHtDyO3k9qPXLg7awfRAE3YnXk4WLsint17JBsU4UEX8le9YE8SgPkWNnQC898SqbFGGU/5JUA==} peerDependencies: - '@electric-sql/pglite': 0.3.10 + '@electric-sql/pglite': 0.3.14 '@electric-sql/pglite@0.2.17': resolution: {integrity: sha512-qEpKRT2oUaWDH6tjRxLHjdzMqRUGYDnGZlKrnL4dJ77JVMcP2Hpo3NYnOSPKdZdeec57B6QPprCUFg0picx5Pw==} - '@electric-sql/pglite@0.3.10': - resolution: {integrity: sha512-1XtXXprd848aR4hvjNqBc3Gc86zNGmd60x+MgOUShbHYxt+J76N8A81DqTEl275T8xBD0vdTgqR/dJ4yJyz0NQ==} + '@electric-sql/pglite@0.3.14': + resolution: {integrity: sha512-3DB258dhqdsArOI1fIt7cb9RpUOgcDg5hXWVgVHAeqVQ/qxtFy605QKs4gx6mFq3jWsSPqDN8TgSEsqC3OfV9Q==} - '@emnapi/core@1.5.0': - resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} - '@emnapi/runtime@1.5.0': - resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@esbuild/aix-ppc64@0.25.10': - resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.10': - resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} + '@esbuild/aix-ppc64@0.26.0': + resolution: {integrity: sha512-hj0sKNCQOOo2fgyII3clmJXP28VhgDfU5iy3GNHlWO76KG6N7x4D9ezH5lJtQTG+1J6MFDAJXC1qsI+W+LvZoA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.1': + resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.26.0': + resolution: {integrity: sha512-DDnoJ5eoa13L8zPh87PUlRd/IyFaIKOlRbxiwcSbeumcJ7UZKdtuMCHa1Q27LWQggug6W4m28i4/O2qiQQ5NZQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.10': - resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} + '@esbuild/android-arm64@0.27.1': + resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.26.0': + resolution: {integrity: sha512-C0hkDsYNHZkBtPxxDx177JN90/1MiCpvBNjz1f5yWJo1+5+c5zr8apjastpEG+wtPjo9FFtGG7owSsAxyKiHxA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.10': - resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} + '@esbuild/android-arm@0.27.1': + resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.26.0': + resolution: {integrity: sha512-bKDkGXGZnj0T70cRpgmv549x38Vr2O3UWLbjT2qmIkdIWcmlg8yebcFWoT9Dku7b5OV3UqPEuNKRzlNhjwUJ9A==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.27.1': + resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.10': - resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.26.0': + resolution: {integrity: sha512-6Z3naJgOuAIB0RLlJkYc81An3rTlQ/IeRdrU3dOea8h/PvZSgitZV+thNuIccw0MuK1GmIAnAmd5TrMZad8FTQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.10': - resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} + '@esbuild/darwin-arm64@0.27.1': + resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.10': - resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} + '@esbuild/darwin-x64@0.26.0': + resolution: {integrity: sha512-OPnYj0zpYW0tHusMefyaMvNYQX5pNQuSsHFTHUBNp3vVXupwqpxofcjVsUx11CQhGVkGeXjC3WLjh91hgBG2xw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.1': + resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.26.0': + resolution: {integrity: sha512-jix2fa6GQeZhO1sCKNaNMjfj5hbOvoL2F5t+w6gEPxALumkpOV/wq7oUBMHBn2hY2dOm+mEV/K+xfZy3mrsxNQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.1': + resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.10': - resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.26.0': + resolution: {integrity: sha512-tccJaH5xHJD/239LjbVvJwf6T4kSzbk6wPFerF0uwWlkw/u7HL+wnAzAH5GB2irGhYemDgiNTp8wJzhAHQ64oA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.10': - resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} + '@esbuild/freebsd-x64@0.27.1': + resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.10': - resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} + '@esbuild/linux-arm64@0.26.0': + resolution: {integrity: sha512-IMJYN7FSkLttYyTbsbme0Ra14cBO5z47kpamo16IwggzzATFY2lcZAwkbcNkWiAduKrTgFJP7fW5cBI7FzcuNQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.27.1': + resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.26.0': + resolution: {integrity: sha512-JY8NyU31SyRmRpuc5W8PQarAx4TvuYbyxbPIpHAZdr/0g4iBr8KwQBS4kiiamGl2f42BBecHusYCsyxi7Kn8UQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.10': - resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} + '@esbuild/linux-arm@0.27.1': + resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.26.0': + resolution: {integrity: sha512-XITaGqGVLgk8WOHw8We9Z1L0lbLFip8LyQzKYFKO4zFo1PFaaSKsbNjvkb7O8kEXytmSGRkYpE8LLVpPJpsSlw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.1': + resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.10': - resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.10': - resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} + '@esbuild/linux-loong64@0.26.0': + resolution: {integrity: sha512-MkggfbDIczStUJwq9wU7gQ7kO33d8j9lWuOCDifN9t47+PeI+9m2QVh51EI/zZQ1spZtFMC1nzBJ+qNGCjJnsg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.27.1': + resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.10': - resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} + '@esbuild/linux-mips64el@0.26.0': + resolution: {integrity: sha512-fUYup12HZWAeccNLhQ5HwNBPr4zXCPgUWzEq2Rfw7UwqwfQrFZ0SR/JljaURR8xIh9t+o1lNUFTECUTmaP7yKA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.1': + resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.10': - resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} + '@esbuild/linux-ppc64@0.26.0': + resolution: {integrity: sha512-MzRKhM0Ip+//VYwC8tialCiwUQ4G65WfALtJEFyU0GKJzfTYoPBw5XNWf0SLbCUYQbxTKamlVwPmcw4DgZzFxg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.1': + resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.10': - resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} + '@esbuild/linux-riscv64@0.26.0': + resolution: {integrity: sha512-QhCc32CwI1I4Jrg1enCv292sm3YJprW8WHHlyxJhae/dVs+KRWkbvz2Nynl5HmZDW/m9ZxrXayHzjzVNvQMGQA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.1': + resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.10': - resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} + '@esbuild/linux-s390x@0.26.0': + resolution: {integrity: sha512-1D6vi6lfI18aNT1aTf2HV+RIlm6fxtlAp8eOJ4mmnbYmZ4boz8zYDar86sIYNh0wmiLJEbW/EocaKAX6Yso2fw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.1': + resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.26.0': + resolution: {integrity: sha512-rnDcepj7LjrKFvZkx+WrBv6wECeYACcFjdNPvVPojCPJD8nHpb3pv3AuR9CXgdnjH1O23btICj0rsp0L9wAnHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.1': + resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.10': - resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.26.0': + resolution: {integrity: sha512-FSWmgGp0mDNjEXXFcsf12BmVrb+sZBBBlyh3LwB/B9ac3Kkc8x5D2WimYW9N7SUkolui8JzVnVlWh7ZmjCpnxw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.27.1': + resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.10': - resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.10': - resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} + '@esbuild/netbsd-x64@0.26.0': + resolution: {integrity: sha512-0QfciUDFryD39QoSPUDshj4uNEjQhp73+3pbSAaxjV2qGOEDsM67P7KbJq7LzHoVl46oqhIhJ1S+skKGR7lMXA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.1': + resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.10': - resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} + '@esbuild/openbsd-arm64@0.26.0': + resolution: {integrity: sha512-vmAK+nHhIZWImwJ3RNw9hX3fU4UGN/OqbSE0imqljNbUQC3GvVJ1jpwYoTfD6mmXmQaxdJY6Hn4jQbLGJKg5Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.1': + resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.26.0': + resolution: {integrity: sha512-GPXF7RMkJ7o9bTyUsnyNtrFMqgM3X+uM/LWw4CeHIjqc32fm0Ir6jKDnWHpj8xHFstgWDUYseSABK9KCkHGnpg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.1': + resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.10': - resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.10': - resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} + '@esbuild/openharmony-arm64@0.26.0': + resolution: {integrity: sha512-nUHZ5jEYqbBthbiBksbmHTlbb5eElyVfs/s1iHQ8rLBq1eWsd5maOnDpCocw1OM8kFK747d1Xms8dXJHtduxSw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.27.1': + resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.26.0': + resolution: {integrity: sha512-TMg3KCTCYYaVO+R6P5mSORhcNDDlemUVnUbb8QkboUtOhb5JWKAzd5uMIMECJQOxHZ/R+N8HHtDF5ylzLfMiLw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.1': + resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.10': - resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.26.0': + resolution: {integrity: sha512-apqYgoAUd6ZCb9Phcs8zN32q6l0ZQzQBdVXOofa6WvHDlSOhwCWgSfVQabGViThS40Y1NA4SCvQickgZMFZRlA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.1': + resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.10': - resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.10': - resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} + '@esbuild/win32-ia32@0.26.0': + resolution: {integrity: sha512-FGJAcImbJNZzLWu7U6WB0iKHl4RuY4TsXEwxJPl9UZLS47agIZuILZEX3Pagfw7I4J3ddflomt9f0apfaJSbaw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.1': + resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.26.0': + resolution: {integrity: sha512-WAckBKaVnmFqbEhbymrPK7M086DQMpL1XoRbpmN0iW8k5JSXjDRQBhcZNa0VweItknLq9eAeCL34jK7/CDcw7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.1': + resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1775,8 +2101,8 @@ packages: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} - '@firebase/ai@2.4.0': - resolution: {integrity: sha512-YilG6AJ/nYpCKtxZyvEzBRAQv5bU+2tBOKX4Ps0rNNSdxN39aT37kGhjATbk1kq1z5Lq7mkWglw/ajAF3lOWUg==} + '@firebase/ai@2.6.1': + resolution: {integrity: sha512-qJd9bpABqsanFnwdbjZEDbKKr1jRtuUZ+cHyNBLWsxobH4pd73QncvuO3XlMq4eKBLlg1f5jNdFpJ3G3ABu2Tg==} engines: {node: '>=20.0.0'} peerDependencies: '@firebase/app': 0.x @@ -1813,19 +2139,19 @@ packages: peerDependencies: '@firebase/app': 0.x - '@firebase/app-compat@0.5.4': - resolution: {integrity: sha512-T7ifGmb+awJEcp542Ek4HtNfBxcBrnuk1ggUdqyFEdsXHdq7+wVlhvE6YukTL7NS8hIkEfL7TMAPx/uCNqt30g==} + '@firebase/app-compat@0.5.6': + resolution: {integrity: sha512-YYGARbutghQY4zZUWMYia0ib0Y/rb52y72/N0z3vglRHL7ii/AaK9SA7S/dzScVOlCdnbHXz+sc5Dq+r8fwFAg==} engines: {node: '>=20.0.0'} '@firebase/app-types@0.9.3': resolution: {integrity: sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==} - '@firebase/app@0.14.4': - resolution: {integrity: sha512-pUxEGmR+uu21OG/icAovjlu1fcYJzyVhhT0rsCrn+zi+nHtrS43Bp9KPn9KGa4NMspCUE++nkyiqziuIvJdwzw==} + '@firebase/app@0.14.6': + resolution: {integrity: sha512-4uyt8BOrBsSq6i4yiOV/gG6BnnrvTeyymlNcaN/dKvyU1GoolxAafvIvaNP1RCGPlNab3OuE4MKUQuv2lH+PLQ==} engines: {node: '>=20.0.0'} - '@firebase/auth-compat@0.6.0': - resolution: {integrity: sha512-J0lGSxXlG/lYVi45wbpPhcWiWUMXevY4fvLZsN1GHh+po7TZVng+figdHBVhFheaiipU8HZyc7ljw1jNojM2nw==} + '@firebase/auth-compat@0.6.2': + resolution: {integrity: sha512-8UhCzF6pav9bw/eXA8Zy1QAKssPRYEYXaWagie1ewLTwHkXv6bKp/j6/IwzSYQP67sy/BMFXIFaCCsoXzFLr7A==} engines: {node: '>=20.0.0'} peerDependencies: '@firebase/app-compat': 0.x @@ -1839,12 +2165,12 @@ packages: '@firebase/app-types': 0.x '@firebase/util': 1.x - '@firebase/auth@1.11.0': - resolution: {integrity: sha512-5j7+ua93X+IRcJ1oMDTClTo85l7Xe40WSkoJ+shzPrX7OISlVWLdE1mKC57PSD+/LfAbdhJmvKixINBw2ESK6w==} + '@firebase/auth@1.12.0': + resolution: {integrity: sha512-zkvLpsrxynWHk07qGrUDfCSqKf4AvfZGEqJ7mVCtYGjNNDbGE71k0Yn84rg8QEZu4hQw1BC0qDEHzpNVBcSVmA==} engines: {node: '>=20.0.0'} peerDependencies: '@firebase/app': 0.x - '@react-native-async-storage/async-storage': ^1.18.1 + '@react-native-async-storage/async-storage': ^2.2.0 peerDependenciesMeta: '@react-native-async-storage/async-storage': optional: true @@ -1853,8 +2179,8 @@ packages: resolution: {integrity: sha512-wR9En2A+WESUHexjmRHkqtaVH94WLNKt6rmeqZhSLBybg4Wyf0Umk04SZsS6sBq4102ZsDBFwoqMqJYj2IoDSg==} engines: {node: '>=20.0.0'} - '@firebase/data-connect@0.3.11': - resolution: {integrity: sha512-G258eLzAD6im9Bsw+Qm1Z+P4x0PGNQ45yeUuuqe5M9B1rn0RJvvsQCRHXgE52Z+n9+WX1OJd/crcuunvOGc7Vw==} + '@firebase/data-connect@0.3.12': + resolution: {integrity: sha512-baPddcoNLj/+vYo+HSJidJUdr5W4OkhT109c5qhR8T1dJoZcyJpkv/dFpYlw/VJ3dV66vI8GHQFrmAZw/xUS4g==} peerDependencies: '@firebase/app': 0.x @@ -1869,8 +2195,8 @@ packages: resolution: {integrity: sha512-gM6MJFae3pTyNLoc9VcJNuaUDej0ctdjn3cVtILo3D5lpp0dmUHHLFN/pUKe7ImyeB1KAvRlEYxvIHNF04Filg==} engines: {node: '>=20.0.0'} - '@firebase/firestore-compat@0.4.2': - resolution: {integrity: sha512-cy7ov6SpFBx+PHwFdOOjbI7kH00uNKmIFurAn560WiPCZXy9EMnil1SOG7VF4hHZKdenC+AHtL4r3fNpirpm0w==} + '@firebase/firestore-compat@0.4.3': + resolution: {integrity: sha512-1ylF/njF68Pmb6p0erP0U78XQv1w77Wap4bUmqZ7ZVkmN1oMgplyu0TyirWtCBoKFRV2+SUZfWXvIij/z39LYg==} engines: {node: '>=20.0.0'} peerDependencies: '@firebase/app-compat': 0.x @@ -1881,8 +2207,8 @@ packages: '@firebase/app-types': 0.x '@firebase/util': 1.x - '@firebase/firestore@4.9.2': - resolution: {integrity: sha512-iuA5+nVr/IV/Thm0Luoqf2mERUvK9g791FZpUJV1ZGXO6RL2/i/WFJUj5ZTVXy5pRjpWYO+ZzPcReNrlilmztA==} + '@firebase/firestore@4.9.3': + resolution: {integrity: sha512-RVuvhcQzs1sD5Osr2naQS71H0bQMbSnib16uOWAKk3GaKb/WBPyCYSr2Ry7MqlxDP/YhwknUxECL07lw9Rq1nA==} engines: {node: '>=20.0.0'} peerDependencies: '@firebase/app': 0.x @@ -1985,23 +2311,23 @@ packages: '@firebase/webchannel-wrapper@1.0.5': resolution: {integrity: sha512-+uGNN7rkfn41HLO0vekTFhTxk61eKa8mTpRGLO0QSqlQdKvIoGAvLp3ppdVIWbTGYJWM6Kp0iN+PjMIOcnVqTw==} - '@formatjs/ecma402-abstract@2.3.5': - resolution: {integrity: sha512-1HTESOq1IUa23g1lFZEGIXsfZKZOwWmB9RROwGn+xariiQnd++wwTMvlRAbZ8wtXRHFUamJPxsKcxpSzeCvFWQ==} + '@formatjs/ecma402-abstract@2.3.6': + resolution: {integrity: sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw==} '@formatjs/fast-memoize@2.2.7': resolution: {integrity: sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==} - '@formatjs/icu-messageformat-parser@2.11.3': - resolution: {integrity: sha512-H/KfWSosaiDiOaW4nHe1Fn4Cgzm+oFQ8giTmB5RJzTBNSMmd+j2NVrvvZHAmlxJHcuOelzKBLjQ2EDcyH4NSWw==} + '@formatjs/icu-messageformat-parser@2.11.4': + resolution: {integrity: sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==} - '@formatjs/icu-skeleton-parser@1.8.15': - resolution: {integrity: sha512-qNrKxWJmnWxin5U4A4Evy7C0rgRiNw3IqXu9OGuT31B8lDxBGl+OgT8kcq0ZVKK0gqA4l4SQB9x+SFAvLT5hcQ==} + '@formatjs/icu-skeleton-parser@1.8.16': + resolution: {integrity: sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==} '@formatjs/intl-localematcher@0.6.2': resolution: {integrity: sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==} - '@google-cloud/cloud-sql-connector@1.8.3': - resolution: {integrity: sha512-Xmh1U0cw5goTWchBqvXfcffz2B6eGUnMH+iY6NTz6A+WlsvlDtAi87NlMst4yKYNfF7gRmNnnJTcK25I6TR6cA==} + '@google-cloud/cloud-sql-connector@1.8.4': + resolution: {integrity: sha512-dX36ksbh4xrIsALCHxNYXwvRUtlZ/msQ/PL0LpSYWHnfMenRM+watAzM/XIVr8tQOtzhT7mrmrAb/W/bgayQAQ==} engines: {node: '>=18'} '@google-cloud/common@6.0.0': @@ -2048,11 +2374,11 @@ packages: resolution: {integrity: sha512-IJn+8A3QZJfe7FUtWqHVNo3xJs7KFpurCWGWCiCz3oEh+BkRymKZ1QxfAbU2yGMDzTytLGQ2IV6T2r3cuo75/w==} engines: {node: '>=18'} - '@google/genai@1.25.0': - resolution: {integrity: sha512-IBNyel/umavam98SQUfvQSvh/Rp6Ql2fysQLqPyWZr5K8d768X9AO+JZU4o+3qvFDUBA0dVYUSkxyYonVcICvA==} + '@google/genai@1.33.0': + resolution: {integrity: sha512-ThUjFZ1N0DU88peFjnQkb8K198EWaW2RmmnDShFQ+O+xkIH9itjpRe358x3L/b4X/A7dimkvq63oz49Vbh7Cog==} engines: {node: '>=20.0.0'} peerDependencies: - '@modelcontextprotocol/sdk': ^1.11.4 + '@modelcontextprotocol/sdk': ^1.24.0 peerDependenciesMeta: '@modelcontextprotocol/sdk': optional: true @@ -2061,8 +2387,8 @@ packages: resolution: {integrity: sha512-k4lXSFCFuZmWtYuW/OH/PcHimZP5P/uDLK0+ACbgoZFB8qmlgcyF0531aJt6JHIdBwCRlHXZlMW4LDC5Gqra5w==} engines: {node: '>=12.0.0'} - '@grpc/grpc-js@1.14.0': - resolution: {integrity: sha512-N8Jx6PaYzcTRNzirReJCtADVoq4z7+1KQ4E70jTg/koQiMoUSN1kbNjPOqpPbhMFhfU1/l7ixspPl8dNY+FoUg==} + '@grpc/grpc-js@1.14.2': + resolution: {integrity: sha512-QzVUtEFyu05UNx2xr0fCQmStUO17uVQhGNowtxs00IgTZT6/W2PBLfUkj30s0FKJ29VtTa3ArVNIhNP6akQhqA==} engines: {node: '>=12.10.0'} '@grpc/grpc-js@1.9.15': @@ -2079,16 +2405,16 @@ packages: engines: {node: '>=6'} hasBin: true - '@inquirer/ansi@1.0.0': - resolution: {integrity: sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==} + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} engines: {node: '>=18'} - '@inquirer/ansi@1.0.1': - resolution: {integrity: sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==} - engines: {node: '>=18'} + '@inquirer/ansi@2.0.2': + resolution: {integrity: sha512-SYLX05PwJVnW+WVegZt1T4Ip1qba1ik+pNJPDiqvk6zS5Y/i8PhRzLpGEtVd7sW0G8cMtkD8t4AZYhQwm8vnww==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - '@inquirer/checkbox@4.2.4': - resolution: {integrity: sha512-2n9Vgf4HSciFq8ttKXk+qy+GsyTXPV1An6QAwe/8bkbbqvG4VW1I/ZY1pNu2rf+h9bdzMLPbRSfcNxkHBy/Ydw==} + '@inquirer/checkbox@4.3.2': + resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2096,17 +2422,17 @@ packages: '@types/node': optional: true - '@inquirer/checkbox@4.3.0': - resolution: {integrity: sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==} - engines: {node: '>=18'} + '@inquirer/checkbox@5.0.3': + resolution: {integrity: sha512-xtQP2eXMFlOcAhZ4ReKP2KZvDIBb1AnCfZ81wWXG3DXLVH0f0g4obE0XDPH+ukAEMRcZT0kdX2AS1jrWGXbpxw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/confirm@5.1.18': - resolution: {integrity: sha512-MilmWOzHa3Ks11tzvuAmFoAd/wRuaP3SwlT1IZhyMke31FKLxPiuDWcGXhU+PKveNOpAc4axzAgrgxuIJJRmLw==} + '@inquirer/confirm@5.1.19': + resolution: {integrity: sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2114,8 +2440,8 @@ packages: '@types/node': optional: true - '@inquirer/confirm@5.1.19': - resolution: {integrity: sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==} + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2123,17 +2449,17 @@ packages: '@types/node': optional: true - '@inquirer/core@10.2.2': - resolution: {integrity: sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==} - engines: {node: '>=18'} + '@inquirer/confirm@6.0.3': + resolution: {integrity: sha512-lyEvibDFL+NA5R4xl8FUmNhmu81B+LDL9L/MpKkZlQDJZXzG8InxiqYxiAlQYa9cqLLhYqKLQwZqXmSTqCLjyw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/core@10.3.0': - resolution: {integrity: sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==} + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2141,17 +2467,17 @@ packages: '@types/node': optional: true - '@inquirer/editor@4.2.20': - resolution: {integrity: sha512-7omh5y5bK672Q+Brk4HBbnHNowOZwrb/78IFXdrEB9PfdxL3GudQyDk8O9vQ188wj3xrEebS2M9n18BjJoI83g==} - engines: {node: '>=18'} + '@inquirer/core@11.1.0': + resolution: {integrity: sha512-+jD/34T1pK8M5QmZD/ENhOfXdl9Zr+BrQAUc5h2anWgi7gggRq15ZbiBeLoObj0TLbdgW7TAIQRU2boMc9uOKQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/editor@4.2.21': - resolution: {integrity: sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==} + '@inquirer/editor@4.2.23': + resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2159,17 +2485,17 @@ packages: '@types/node': optional: true - '@inquirer/expand@4.0.20': - resolution: {integrity: sha512-Dt9S+6qUg94fEvgn54F2Syf0Z3U8xmnBI9ATq2f5h9xt09fs2IJXSCIXyyVHwvggKWFXEY/7jATRo2K6Dkn6Ow==} - engines: {node: '>=18'} + '@inquirer/editor@5.0.3': + resolution: {integrity: sha512-wYyQo96TsAqIciP/r5D3cFeV8h4WqKQ/YOvTg5yOfP2sqEbVVpbxPpfV3LM5D0EP4zUI3EZVHyIUIllnoIa8OQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/expand@4.0.21': - resolution: {integrity: sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==} + '@inquirer/expand@4.0.23': + resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2177,25 +2503,43 @@ packages: '@types/node': optional: true - '@inquirer/external-editor@1.0.2': - resolution: {integrity: sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==} - engines: {node: '>=18'} + '@inquirer/expand@5.0.3': + resolution: {integrity: sha512-2oINvuL27ujjxd95f6K2K909uZOU2x1WiAl7Wb1X/xOtL8CgQ1kSxzykIr7u4xTkXkXOAkCuF45T588/YKee7w==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/figures@1.0.13': - resolution: {integrity: sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==} + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/external-editor@2.0.2': + resolution: {integrity: sha512-X/fMXK7vXomRWEex1j8mnj7s1mpnTeP4CO/h2gysJhHLT2WjBnLv4ZQEGpm/kcYI8QfLZ2fgW+9kTKD+jeopLg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true - '@inquirer/figures@1.0.14': - resolution: {integrity: sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==} + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} engines: {node: '>=18'} - '@inquirer/input@4.2.4': - resolution: {integrity: sha512-cwSGpLBMwpwcZZsc6s1gThm0J+it/KIJ+1qFL2euLmSKUMGumJ5TcbMgxEjMjNHRGadouIYbiIgruKoDZk7klw==} + '@inquirer/figures@2.0.2': + resolution: {integrity: sha512-qXm6EVvQx/FmnSrCWCIGtMHwqeLgxABP8XgcaAoywsL0NFga9gD5kfG0gXiv80GjK9Hsoz4pgGwF/+CjygyV9A==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + + '@inquirer/input@4.3.1': + resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2203,17 +2547,17 @@ packages: '@types/node': optional: true - '@inquirer/input@4.2.5': - resolution: {integrity: sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==} - engines: {node: '>=18'} + '@inquirer/input@5.0.3': + resolution: {integrity: sha512-4R0TdWl53dtp79Vs6Df2OHAtA2FVNqya1hND1f5wjHWxZJxwDMSNB1X5ADZJSsQKYAJ5JHCTO+GpJZ42mK0Otw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/number@3.0.20': - resolution: {integrity: sha512-bbooay64VD1Z6uMfNehED2A2YOPHSJnQLs9/4WNiV/EK+vXczf/R988itL2XLDGTgmhMF2KkiWZo+iEZmc4jqg==} + '@inquirer/number@3.0.23': + resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2221,17 +2565,17 @@ packages: '@types/node': optional: true - '@inquirer/number@3.0.21': - resolution: {integrity: sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==} - engines: {node: '>=18'} + '@inquirer/number@4.0.3': + resolution: {integrity: sha512-TjQLe93GGo5snRlu83JxE38ZPqj5ZVggL+QqqAF2oBA5JOJoxx25GG3EGH/XN/Os5WOmKfO8iLVdCXQxXRZIMQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/password@4.0.20': - resolution: {integrity: sha512-nxSaPV2cPvvoOmRygQR+h0B+Av73B01cqYLcr7NXcGXhbmsYfUb8fDdw2Us1bI2YsX+VvY7I7upgFYsyf8+Nug==} + '@inquirer/password@4.0.23': + resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2239,17 +2583,17 @@ packages: '@types/node': optional: true - '@inquirer/password@4.0.21': - resolution: {integrity: sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==} - engines: {node: '>=18'} + '@inquirer/password@5.0.3': + resolution: {integrity: sha512-rCozGbUMAHedTeYWEN8sgZH4lRCdgG/WinFkit6ZPsp8JaNg2T0g3QslPBS5XbpORyKP/I+xyBO81kFEvhBmjA==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/prompts@7.8.6': - resolution: {integrity: sha512-68JhkiojicX9SBUD8FE/pSKbOKtwoyaVj1kwqLfvjlVXZvOy3iaSWX4dCLsZyYx/5Ur07Fq+yuDNOen+5ce6ig==} + '@inquirer/prompts@7.10.1': + resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2266,17 +2610,17 @@ packages: '@types/node': optional: true - '@inquirer/rawlist@4.1.8': - resolution: {integrity: sha512-CQ2VkIASbgI2PxdzlkeeieLRmniaUU1Aoi5ggEdm6BIyqopE9GuDXdDOj9XiwOqK5qm72oI2i6J+Gnjaa26ejg==} - engines: {node: '>=18'} + '@inquirer/prompts@8.1.0': + resolution: {integrity: sha512-LsZMdKcmRNF5LyTRuZE5nWeOjganzmN3zwbtNfcs6GPh3I2TsTtF1UYZlbxVfhxd+EuUqLGs/Lm3Xt4v6Az1wA==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/rawlist@4.1.9': - resolution: {integrity: sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==} + '@inquirer/rawlist@4.1.11': + resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2284,17 +2628,17 @@ packages: '@types/node': optional: true - '@inquirer/search@3.1.3': - resolution: {integrity: sha512-D5T6ioybJJH0IiSUK/JXcoRrrm8sXwzrVMjibuPs+AgxmogKslaafy1oxFiorNI4s3ElSkeQZbhYQgLqiL8h6Q==} - engines: {node: '>=18'} + '@inquirer/rawlist@5.1.0': + resolution: {integrity: sha512-yUCuVh0jW026Gr2tZlG3kHignxcrLKDR3KBp+eUgNz+BAdSeZk0e18yt2gyBr+giYhj/WSIHCmPDOgp1mT2niQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/search@3.2.0': - resolution: {integrity: sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==} + '@inquirer/search@3.2.2': + resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2302,17 +2646,17 @@ packages: '@types/node': optional: true - '@inquirer/select@4.3.4': - resolution: {integrity: sha512-Qp20nySRmfbuJBBsgPU7E/cL62Hf250vMZRzYDcBHty2zdD1kKCnoDFWRr0WO2ZzaXp3R7a4esaVGJUx0E6zvA==} - engines: {node: '>=18'} + '@inquirer/search@4.0.3': + resolution: {integrity: sha512-lzqVw0YwuKYetk5VwJ81Ba+dyVlhseHPx9YnRKQgwXdFS0kEavCz2gngnNhnMIxg8+j1N/rUl1t5s1npwa7bqg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/select@4.4.0': - resolution: {integrity: sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==} + '@inquirer/select@4.4.2': + resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2320,8 +2664,17 @@ packages: '@types/node': optional: true - '@inquirer/type@3.0.9': - resolution: {integrity: sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==} + '@inquirer/select@5.0.3': + resolution: {integrity: sha512-M+ynbwS0ecQFDYMFrQrybA0qL8DV0snpc4kKevCCNaTpfghsRowRY7SlQBeIYNzHqXtiiz4RG9vTOeb/udew7w==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2329,6 +2682,15 @@ packages: '@types/node': optional: true + '@inquirer/type@4.0.2': + resolution: {integrity: sha512-cae7mzluplsjSdgFA6ACLygb5jC8alO0UUnFPyu0E7tNRPrL+q/f8VcSXp+cjZQ7l5CMpDpi2G1+IQvkOiL1Lw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + '@isaacs/balanced-match@4.0.1': resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} @@ -2383,8 +2745,8 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/buffers@1.0.0': - resolution: {integrity: sha512-NDigYR3PHqCnQLXYyoLbnEdzMMvzeiCWo1KOut7Q0CoIqg9tUAPKJ1iq/2nFhc5kZtexzutNY0LFjdwWL3Dw3Q==} + '@jsonjoy.com/buffers@1.2.1': + resolution: {integrity: sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -2395,8 +2757,8 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/json-pack@1.14.0': - resolution: {integrity: sha512-LpWbYgVnKzphN5S6uss4M25jJ/9+m6q6UJoeN6zTkK4xAGhKsiBRPVeF7OYMWonn5repMQbE5vieRXcMUrKDKw==} + '@jsonjoy.com/json-pack@1.21.0': + resolution: {integrity: sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -2416,12 +2778,12 @@ packages: '@leichtgewicht/ip-codec@2.0.5': resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} - '@listr2/prompt-adapter-inquirer@3.0.4': - resolution: {integrity: sha512-Dta7PtlCrlZK6UVvlV1Ym3ZHYZ6+7C4mflkI6tOudbl0kh8hoEikSkk6qFQa2tHPprz+8yLHbh5u948HQIOuKg==} + '@listr2/prompt-adapter-inquirer@3.0.5': + resolution: {integrity: sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==} engines: {node: '>=20.0.0'} peerDependencies: '@inquirer/prompts': '>= 3 < 8' - listr2: 9.0.4 + listr2: 9.0.5 '@lmdb/lmdb-darwin-arm64@3.4.3': resolution: {integrity: sha512-zR6Y45VNtW5s+A+4AyhrJk0VJKhXdkLhrySCpCu7PSdnakebsOzNxf58p5Xoq66vOSuueGAxlqDAF49HwdrSTQ==} @@ -2461,13 +2823,23 @@ packages: '@material/material-color-utilities@0.3.0': resolution: {integrity: sha512-ztmtTd6xwnuh2/xu+Vb01btgV8SQWYCaK56CkRK8gEkWe5TuDyBcYJ0wgkMRn+2VcE9KUmhvkz+N9GHrqw/C0g==} - '@modelcontextprotocol/sdk@1.19.1': - resolution: {integrity: sha512-3Y2h3MZKjec1eAqSTBclATlX+AbC6n1LgfVzRMJLt3v6w0RCYgwLrjbxPDbhsYHt6Wdqc/aCceNJYgj448ELQQ==} + '@modelcontextprotocol/sdk@1.24.0': + resolution: {integrity: sha512-D8h5KXY2vHFW8zTuxn2vuZGN0HGrQ5No6LkHwlEA9trVgNdPL3TF1dSqKA7Dny6BbBYKSW/rOBDXdC8KJAjUCg==} engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true - '@modelcontextprotocol/sdk@1.20.0': - resolution: {integrity: sha512-kOQ4+fHuT4KbR2iq2IjeV32HiihueuOf1vJkq18z08CLZ1UQrTc8BXJpVfxZkq45+inLLD+D4xx4nBjUelJa4Q==} + '@modelcontextprotocol/sdk@1.24.3': + resolution: {integrity: sha512-YgSHW29fuzKKAHTGe9zjNoo+yF8KaQPzDC2W9Pv41E7/57IfY+AMGJ/aDFlgTLcVVELoggKE4syABCE75u3NCw==} engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} @@ -2499,8 +2871,8 @@ packages: cpu: [x64] os: [win32] - '@mswjs/interceptors@0.39.7': - resolution: {integrity: sha512-sURvQbbKsq5f8INV54YJgJEdk8oxBanqkTiXXd33rKmofFCwZLhLRszPduMZ9TA9b8/1CHc/IJmOlBHJk2Q5AQ==} + '@mswjs/interceptors@0.39.8': + resolution: {integrity: sha512-2+BzZbjRO7Ct61k8fMNHEtoKjeWI9pIlHFTqBwZ5icHpqszIgEZbjb1MW5Z0+bITTCTl3gk4PDBxs9tA/csXvA==} engines: {node: '>=18'} '@napi-rs/nice-android-arm-eabi@1.1.1': @@ -2616,19 +2988,19 @@ packages: resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} engines: {node: '>= 10'} - '@napi-rs/wasm-runtime@1.0.7': - resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} + '@napi-rs/wasm-runtime@1.1.0': + resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==} '@nginfra/angular-linking@1.0.9': resolution: {integrity: sha512-25cph8loaVTzSxD6Ll5vjUhm/xxbr1OHLaH/kh464yOMaiK2eKYpNdnIPpfsTFStrwh5/3wKTWTNSCFvjgeTiQ==} peerDependencies: '@angular/compiler-cli': '*' - '@ngtools/webpack@21.0.0-next.8': - resolution: {integrity: sha512-VmKPwjqtBeB4SdGIhleauqOOp4DNwqO5D39HzkTbONhffGYWz+TfNbRhKEhKnMVTXkhyzaf9IpVtFW/Liyp2wA==} + '@ngtools/webpack@21.0.3': + resolution: {integrity: sha512-JDO+KOpNBL5bKgHugjLLgDNDt3odBZLYDaKyeC7s9xv3nAPu0UXQHkMcZe+sOJVMZS0zkSTTQ7zMO8BC6MDj3w==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: - '@angular/compiler-cli': ^21.0.0-next.0 + '@angular/compiler-cli': ^21.0.0 typescript: 5.9.2 webpack: ^5.54.0 @@ -2656,8 +3028,12 @@ packages: resolution: {integrity: sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==} engines: {node: ^18.17.0 || >=20.5.0} - '@npmcli/git@7.0.0': - resolution: {integrity: sha512-vnz7BVGtOctJAIHouCJdvWBhsTVSICMeUgZo2c7XAi5d5Rrl80S1H7oPym7K03cRuinK5Q6s2dw36+PgXQTcMA==} + '@npmcli/fs@5.0.0': + resolution: {integrity: sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/git@7.0.1': + resolution: {integrity: sha512-+XTFxK2jJF/EJJ5SoAzXk3qwIDfvFc5/g+bD274LZ7uY7LE8sTfG6Z8rOanPl2ZEvZWqNvmEdtXC25cE54VcoA==} engines: {node: ^20.17.0 || >=22.9.0} '@npmcli/installed-package-contents@3.0.0': @@ -2665,12 +3041,12 @@ packages: engines: {node: ^18.17.0 || >=20.5.0} hasBin: true - '@npmcli/node-gyp@4.0.0': - resolution: {integrity: sha512-+t5DZ6mO/QFh78PByMq1fGSAub/agLJZDRfJRMeOSNCt8s9YVlTjmGpIPwPhvXTGUIJk+WszlT0rQa1W33yzNA==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/node-gyp@5.0.0': + resolution: {integrity: sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==} + engines: {node: ^20.17.0 || >=22.9.0} - '@npmcli/package-json@7.0.1': - resolution: {integrity: sha512-956YUeI0YITbk2+KnirCkD19HLzES0habV+Els+dyZaVsaM6VGSiNwnRu6t3CZaqDLz4KXy2zx+0N/Zy6YjlAA==} + '@npmcli/package-json@7.0.4': + resolution: {integrity: sha512-0wInJG3j/K40OJt/33ax47WfWMzZTm6OQxB9cDhTt5huCP2a9g2GnlsxmfN+PulItNPIpPrZ+kfwwUil7eHcZQ==} engines: {node: ^20.17.0 || >=22.9.0} '@npmcli/promise-spawn@3.0.0': @@ -2681,62 +3057,75 @@ packages: resolution: {integrity: sha512-Yb00SWaL4F8w+K8YGhQ55+xE4RUNdMHV43WZGsiTM92gS+lC0mGsn7I4hLug7pbao035S6bj3Y3w0cUNGLfmkg==} engines: {node: ^18.17.0 || >=20.5.0} - '@npmcli/redact@3.2.2': - resolution: {integrity: sha512-7VmYAmk4csGv08QzrDKScdzn11jHPFGyqJW39FyPgPuAp3zIaUmuCo1yxw9aGs+NEJuTGQ9Gwqpt93vtJubucg==} - engines: {node: ^18.17.0 || >=20.5.0} + '@npmcli/promise-spawn@9.0.1': + resolution: {integrity: sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==} + engines: {node: ^20.17.0 || >=22.9.0} - '@npmcli/run-script@10.0.0': - resolution: {integrity: sha512-vaQj4nccJbAslopIvd49pQH2NhUp7G9pY4byUtmwhe37ZZuubGrx0eB9hW2F37uVNRuDDK6byFGXF+7JCuMSZg==} + '@npmcli/redact@4.0.0': + resolution: {integrity: sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==} engines: {node: ^20.17.0 || >=22.9.0} - '@octokit/auth-app@8.1.1': - resolution: {integrity: sha512-yW9YUy1cuqWlz8u7908ed498wJFt42VYsYWjvepjojM4BdZSp4t+5JehFds7LfvYi550O/GaUI94rgbhswvxfA==} + '@npmcli/run-script@10.0.3': + resolution: {integrity: sha512-ER2N6itRkzWbbtVmZ9WKaWxVlKlOeBFF1/7xx+KA5J1xKa4JjUwBdb6tDpk0v1qA+d+VDwHI9qmLcXSWcmi+Rw==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@octokit/auth-app@8.1.2': + resolution: {integrity: sha512-db8VO0PqXxfzI6GdjtgEFHY9tzqUql5xMFXYA12juq8TeTgPAuiiP3zid4h50lwlIP457p5+56PnJOgd2GGBuw==} engines: {node: '>= 20'} - '@octokit/auth-oauth-app@9.0.2': - resolution: {integrity: sha512-vmjSHeuHuM+OxZLzOuoYkcY3OPZ8erJ5lfswdTmm+4XiAKB5PmCk70bA1is4uwSl/APhRVAv4KHsgevWfEKIPQ==} + '@octokit/auth-oauth-app@9.0.3': + resolution: {integrity: sha512-+yoFQquaF8OxJSxTb7rnytBIC2ZLbLqA/yb71I4ZXT9+Slw4TziV9j/kyGhUFRRTF2+7WlnIWsePZCWHs+OGjg==} engines: {node: '>= 20'} - '@octokit/auth-oauth-device@8.0.2': - resolution: {integrity: sha512-KW7Ywrz7ei7JX+uClWD2DN1259fnkoKuVdhzfpQ3/GdETaCj4Tx0IjvuJrwhP/04OhcMu5yR6tjni0V6LBihdw==} + '@octokit/auth-oauth-device@8.0.3': + resolution: {integrity: sha512-zh2W0mKKMh/VWZhSqlaCzY7qFyrgd9oTWmTmHaXnHNeQRCZr/CXy2jCgHo4e4dJVTiuxP5dLa0YM5p5QVhJHbw==} engines: {node: '>= 20'} - '@octokit/auth-oauth-user@6.0.1': - resolution: {integrity: sha512-vlKsL1KUUPvwXpv574zvmRd+/4JiDFXABIZNM39+S+5j2kODzGgjk7w5WtiQ1x24kRKNaE7v9DShNbw43UA3Hw==} + '@octokit/auth-oauth-user@6.0.2': + resolution: {integrity: sha512-qLoPPc6E6GJoz3XeDG/pnDhJpTkODTGG4kY0/Py154i/I003O9NazkrwJwRuzgCalhzyIeWQ+6MDvkUmKXjg/A==} engines: {node: '>= 20'} '@octokit/auth-token@6.0.0': resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} engines: {node: '>= 20'} - '@octokit/core@7.0.5': - resolution: {integrity: sha512-t54CUOsFMappY1Jbzb7fetWeO0n6K0k/4+/ZpkS+3Joz8I4VcvY9OiEBFRYISqaI2fq5sCiPtAjRDOzVYG8m+Q==} + '@octokit/core@7.0.6': + resolution: {integrity: sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==} engines: {node: '>= 20'} - '@octokit/endpoint@11.0.1': - resolution: {integrity: sha512-7P1dRAZxuWAOPI7kXfio88trNi/MegQ0IJD3vfgC3b+LZo1Qe6gRJc2v0mz2USWWJOKrB2h5spXCzGbw+fAdqA==} + '@octokit/endpoint@11.0.2': + resolution: {integrity: sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==} engines: {node: '>= 20'} - '@octokit/graphql-schema@15.26.0': - resolution: {integrity: sha512-SoVbh+sXe9nsoweFbLT3tAk3XWYbYLs5ku05wij1zhyQ2U3lewdrhjo5Tb7lfaOGWNHSkPZT4uuPZp8neF7P7A==} + '@octokit/graphql-schema@15.26.1': + resolution: {integrity: sha512-RFDC2MpRBd4AxSRvUeBIVeBU7ojN/SxDfALUd7iVYOSeEK3gZaqR2MGOysj4Zh2xj2RY5fQAUT+Oqq7hWTraMA==} - '@octokit/graphql@9.0.2': - resolution: {integrity: sha512-iz6KzZ7u95Fzy9Nt2L8cG88lGRMr/qy1Q36ih/XVzMIlPDMYwaNLE/ENhqmIzgPrlNWiYJkwmveEetvxAgFBJw==} + '@octokit/graphql@9.0.3': + resolution: {integrity: sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==} engines: {node: '>= 20'} '@octokit/oauth-authorization-url@8.0.0': resolution: {integrity: sha512-7QoLPRh/ssEA/HuHBHdVdSgF8xNLz/Bc5m9fZkArJE5bb6NmVkDm3anKxXPmN1zh6b5WKZPRr3697xKT/yM3qQ==} engines: {node: '>= 20'} - '@octokit/oauth-methods@6.0.1': - resolution: {integrity: sha512-xi6Iut3izMCFzXBJtxxJehxJmAKjE8iwj6L5+raPRwlTNKAbOOBJX7/Z8AF5apD4aXvc2skwIdOnC+CQ4QuA8Q==} + '@octokit/oauth-methods@6.0.2': + resolution: {integrity: sha512-HiNOO3MqLxlt5Da5bZbLV8Zarnphi4y9XehrbaFMkcoJ+FL7sMxH/UlUsCVxpddVu4qvNDrBdaTVE2o4ITK8ng==} engines: {node: '>= 20'} '@octokit/openapi-types@26.0.0': resolution: {integrity: sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==} - '@octokit/plugin-paginate-rest@13.2.0': - resolution: {integrity: sha512-YuAlyjR8o5QoRSOvMHxSJzPtogkNMgeMv2mpccrvdUGeC3MKyfi/hS+KiFwyH/iRKIKyx+eIMsDjbt3p9r2GYA==} + '@octokit/openapi-types@27.0.0': + resolution: {integrity: sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==} + + '@octokit/plugin-paginate-rest@13.2.1': + resolution: {integrity: sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-paginate-rest@14.0.0': + resolution: {integrity: sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' @@ -2747,26 +3136,39 @@ packages: peerDependencies: '@octokit/core': '>=6' - '@octokit/plugin-rest-endpoint-methods@16.1.0': - resolution: {integrity: sha512-nCsyiKoGRnhH5LkH8hJEZb9swpqOcsW+VXv1QoyUNQXJeVODG4+xM6UICEqyqe9XFr6LkL8BIiFCPev8zMDXPw==} + '@octokit/plugin-rest-endpoint-methods@16.1.1': + resolution: {integrity: sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' - '@octokit/request-error@7.0.1': - resolution: {integrity: sha512-CZpFwV4+1uBrxu7Cw8E5NCXDWFNf18MSY23TdxCBgjw1tXXHvTrZVsXlW8hgFTOLw8RQR1BBrMvYRtuyaijHMA==} + '@octokit/plugin-rest-endpoint-methods@17.0.0': + resolution: {integrity: sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/request-error@7.1.0': + resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==} engines: {node: '>= 20'} - '@octokit/request@10.0.5': - resolution: {integrity: sha512-TXnouHIYLtgDhKo+N6mXATnDBkV05VwbR0TtMWpgTHIoQdRQfCSzmy/LGqR1AbRMbijq/EckC/E3/ZNcU92NaQ==} + '@octokit/request@10.0.7': + resolution: {integrity: sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==} engines: {node: '>= 20'} '@octokit/rest@22.0.0': resolution: {integrity: sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA==} engines: {node: '>= 20'} - '@octokit/types@15.0.0': - resolution: {integrity: sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==} + '@octokit/rest@22.0.1': + resolution: {integrity: sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==} + engines: {node: '>= 20'} + + '@octokit/types@15.0.2': + resolution: {integrity: sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q==} + + '@octokit/types@16.0.0': + resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} '@open-draft/deferred-promise@2.2.0': resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} @@ -2791,8 +3193,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/context-async-hooks@2.1.0': - resolution: {integrity: sha512-zOyetmZppnwTyPrt4S7jMfXiSX9yyfF0hxlA8B5oo2TtKl+/RGCy7fi4DrBfIf3lCPrkKsRBWZZD7RFojK7FDg==} + '@opentelemetry/context-async-hooks@2.2.0': + resolution: {integrity: sha512-qRkLWiUEZNAmYapZ7KGS5C4OmBLcP/H2foXeOEaowYCR0wi89fHejrfYfbuLVCMLp/dWZXKvQusdbUEZjERfwQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -2803,8 +3205,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/core@2.1.0': - resolution: {integrity: sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==} + '@opentelemetry/core@2.2.0': + resolution: {integrity: sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -2971,8 +3373,8 @@ packages: resolution: {integrity: sha512-4VlGgo32k2EQ2wcCY3vEU28A0O13aOtHz3Xt2/2U5FAh9EfhD6t6DqL5Z6yAnRCntbTFDU4YfbpyzSlHNWycPw==} engines: {node: '>=14'} - '@opentelemetry/semantic-conventions@1.37.0': - resolution: {integrity: sha512-JD6DerIKdJGmRp4jQyX5FlrQjA4tjOw1cvfsPAZXfOOEErMUHjPcPSICS+6WnM0nB0efSFARh0KAZss+bvExOA==} + '@opentelemetry/semantic-conventions@1.38.0': + resolution: {integrity: sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==} engines: {node: '>=14'} '@opentelemetry/sql-common@0.40.1': @@ -2981,8 +3383,8 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 - '@oxc-project/types@0.94.0': - resolution: {integrity: sha512-+UgQT/4o59cZfH6Cp7G0hwmqEQ0wE+AdIwhikdwnhWI9Dp8CgSY081+Q3O67/wq3VJu8mgUEB93J9EHHn70fOw==} + '@oxc-project/types@0.96.0': + resolution: {integrity: sha512-r/xkmoXA0xEpU6UGtn18CNVjXH6erU3KCpCDbpLmbVxBFor1U9MqN5Z2uMmCHJuXjJzlnDR+hWY+yPoLo8oHDw==} '@parcel/watcher-android-arm64@2.5.1': resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} @@ -3096,8 +3498,8 @@ packages: resolution: {integrity: sha512-tNe7a6U4rCpxLMBaR0SIYTdjxGdL0Vwb3G1zY8++sPtHSvy7qd54u8CIB0Z+Y6t5tc9pNYMYCMwhE/wdSY7ltg==} engines: {node: '>=18.12'} - '@pnpm/dependency-path@1001.1.2': - resolution: {integrity: sha512-fih99/lY+HRRak0U0KMKAO7+nacilWMcvFTH6YDKzjCBTOhxDr6Eeap2mF7uf4ED4dnKsQVNUGmFpvaSXSuFCQ==} + '@pnpm/dependency-path@1001.1.8': + resolution: {integrity: sha512-+/SabdOsq4ycO/s1F82mUTmYb9KTE7e74qbXE9caM6slbaJesVqQOKDxSP4RqCy5jkjDz26kpkWzxeNJLowdNQ==} engines: {node: '>=18.12'} '@pnpm/graceful-fs@1000.0.1': @@ -3112,8 +3514,8 @@ packages: resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} engines: {node: '>=12'} - '@pnpm/types@1000.8.0': - resolution: {integrity: sha512-yx86CGHHquWAI0GgKIuV/RnYewcf5fVFZemC45C/K2cX0uV8GB8TUP541ZrokWola2fZx5sn1vL7xzbceRZfoQ==} + '@pnpm/types@1001.2.0': + resolution: {integrity: sha512-UIju+OadUVS0q5q/MbRAzMS5M9HZcZyT6evyrgPUH0DV9przkcW7/LH1Sj33Q2MpJO9Nzqw4b4w72x8mvtUAew==} engines: {node: '>=18.12'} '@prisma/instrumentation@6.11.1': @@ -3151,103 +3553,103 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - '@puppeteer/browsers@2.10.10': - resolution: {integrity: sha512-3ZG500+ZeLql8rE0hjfhkycJjDj0pI/btEh3L9IkWUYcOrgP0xCNRq3HbtbqOPbvDhFaAWD88pDFtlLv8ns8gA==} + '@puppeteer/browsers@2.11.0': + resolution: {integrity: sha512-n6oQX6mYkG8TRPuPXmbPidkUbsSRalhmaaVAQxvH1IkQy63cwsH+kOjB3e4cpCDHg0aSvsiX9bQ4s2VB6mGWUQ==} engines: {node: '>=18'} hasBin: true - '@rolldown/binding-android-arm64@1.0.0-beta.43': - resolution: {integrity: sha512-TP8bcPOb1s6UmY5syhXrDn9k0XkYcw+XaoylTN4cJxf0JOVS2j682I3aTcpfT51hOFGr2bRwNKN9RZ19XxeQbA==} + '@rolldown/binding-android-arm64@1.0.0-beta.47': + resolution: {integrity: sha512-vPP9/MZzESh9QtmvQYojXP/midjgkkc1E4AdnPPAzQXo668ncHJcVLKjJKzoBdsQmaIvNjrMdsCwES8vTQHRQw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-beta.43': - resolution: {integrity: sha512-kuVWnZsE4vEjMF/10SbSUyzucIW2zmdsqFghYMqy+fsjXnRHg0luTU6qWF8IqJf4Cbpm9NEZRnjIEPpAbdiSNQ==} + '@rolldown/binding-darwin-arm64@1.0.0-beta.47': + resolution: {integrity: sha512-Lc3nrkxeaDVCVl8qR3qoxh6ltDZfkQ98j5vwIr5ALPkgjZtDK4BGCrrBoLpGVMg+csWcaqUbwbKwH5yvVa0oOw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-beta.43': - resolution: {integrity: sha512-u9Ps4sh6lcmJ3vgLtyEg/x4jlhI64U0mM93Ew+tlfFdLDe7yKyA+Fe80cpr2n1mNCeZXrvTSbZluKpXQ0GxLjw==} + '@rolldown/binding-darwin-x64@1.0.0-beta.47': + resolution: {integrity: sha512-eBYxQDwP0O33plqNVqOtUHqRiSYVneAknviM5XMawke3mwMuVlAsohtOqEjbCEl/Loi/FWdVeks5WkqAkzkYWQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-beta.43': - resolution: {integrity: sha512-h9lUtVtXgfbk/tnicMpbFfZ3DJvk5Zn2IvmlC1/e0+nUfwoc/TFqpfrRRqcNBXk/e+xiWMSKv6b0MF8N+Rtvlg==} + '@rolldown/binding-freebsd-x64@1.0.0-beta.47': + resolution: {integrity: sha512-Ns+kgp2+1Iq/44bY/Z30DETUSiHY7ZuqaOgD5bHVW++8vme9rdiWsN4yG4rRPXkdgzjvQ9TDHmZZKfY4/G11AA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.43': - resolution: {integrity: sha512-IX2C6bA6wM2rX/RvD75ko+ix9yxPKjKGGq7pOhB8wGI4Z4fqX5B1nDHga/qMDmAdCAR1m9ymzxkmqhm/AFYf7A==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.47': + resolution: {integrity: sha512-4PecgWCJhTA2EFOlptYJiNyVP2MrVP4cWdndpOu3WmXqWqZUmSubhb4YUAIxAxnXATlGjC1WjxNPhV7ZllNgdA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.43': - resolution: {integrity: sha512-mcjd57vEj+CEQbZAzUiaxNzNgwwgOpFtZBWcINm8DNscvkXl5b/s622Z1dqGNWSdrZmdjdC6LWMvu8iHM6v9sQ==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.47': + resolution: {integrity: sha512-CyIunZ6D9U9Xg94roQI1INt/bLkOpPsZjZZkiaAZ0r6uccQdICmC99M9RUPlMLw/qg4yEWLlQhG73W/mG437NA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.43': - resolution: {integrity: sha512-Pa8QMwlkrztTo/1mVjZmPIQ44tCSci10TBqxzVBvXVA5CFh5EpiEi99fPSll2dHG2uT4dCOMeC6fIhyDdb0zXA==} + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.47': + resolution: {integrity: sha512-doozc/Goe7qRCSnzfJbFINTHsMktqmZQmweull6hsZZ9sjNWQ6BWQnbvOlfZJe4xE5NxM1NhPnY5Giqnl3ZrYQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.43': - resolution: {integrity: sha512-BgynXKMjeaX4AfWLARhOKDetBOOghnSiVRjAHVvhiAaDXgdQN8e65mSmXRiVoVtD3cHXx/cfU8Gw0p0K+qYKVQ==} + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.47': + resolution: {integrity: sha512-fodvSMf6Aqwa0wEUSTPewmmZOD44rc5Tpr5p9NkwQ6W1SSpUKzD3SwpJIgANDOhwiYhDuiIaYPGB7Ujkx1q0UQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.43': - resolution: {integrity: sha512-VIsoPlOB/tDSAw9CySckBYysoIBqLeps1/umNSYUD8pMtalJyzMTneAVI1HrUdf4ceFmQ5vARoLIXSsPwVFxNg==} + '@rolldown/binding-linux-x64-musl@1.0.0-beta.47': + resolution: {integrity: sha512-Rxm5hYc0mGjwLh5sjlGmMygxAaV2gnsx7CNm2lsb47oyt5UQyPDZf3GP/ct8BEcwuikdqzsrrlIp8+kCSvMFNQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.43': - resolution: {integrity: sha512-YDXTxVJG67PqTQMKyjVJSddoPbSWJ4yRz/E3xzTLHqNrTDGY0UuhG8EMr8zsYnfH/0cPFJ3wjQd/hJWHuR6nkA==} + '@rolldown/binding-openharmony-arm64@1.0.0-beta.47': + resolution: {integrity: sha512-YakuVe+Gc87jjxazBL34hbr8RJpRuFBhun7NEqoChVDlH5FLhLXjAPHqZd990TVGVNkemourf817Z8u2fONS8w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-beta.43': - resolution: {integrity: sha512-3M+2DmorXvDuAIGYQ9Z93Oy1G9ETkejLwdXXb1uRTgKN9pMcu7N+KG2zDrJwqyxeeLIFE22AZGtSJm3PJbNu9Q==} + '@rolldown/binding-wasm32-wasi@1.0.0-beta.47': + resolution: {integrity: sha512-ak2GvTFQz3UAOw8cuQq8pWE+TNygQB6O47rMhvevvTzETh7VkHRFtRUwJynX5hwzFvQMP6G0az5JrBGuwaMwYQ==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.43': - resolution: {integrity: sha512-/B1j1pJs33y9ywtslOMxryUPHq8zIGu/OGEc2gyed0slimJ8fX2uR/SaJVhB4+NEgCFIeYDR4CX6jynAkeRuCA==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.47': + resolution: {integrity: sha512-o5BpmBnXU+Cj+9+ndMcdKjhZlPb79dVPBZnWwMnI4RlNSSq5yOvFZqvfPYbyacvnW03Na4n5XXQAPhu3RydZ0w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.43': - resolution: {integrity: sha512-29oG1swCz7hNP+CQYrsM4EtylsKwuYzM8ljqbqC5TsQwmKat7P8ouDpImsqg/GZxFSXcPP9ezQm0Q0wQwGM3JA==} + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.47': + resolution: {integrity: sha512-FVOmfyYehNE92IfC9Kgs913UerDog2M1m+FADJypKz0gmRg3UyTt4o1cZMCAl7MiR89JpM9jegNO1nXuP1w1vw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.43': - resolution: {integrity: sha512-eWBV1Ef3gfGNehxVGCyXs7wLayRIgCmyItuCZwYYXW5bsk4EvR4n2GP5m3ohjnx7wdiY3nLmwQfH2Knb5gbNZw==} + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.47': + resolution: {integrity: sha512-by/70F13IUE101Bat0oeH8miwWX5mhMFPk1yjCdxoTNHTyTdLgb0THNaebRM6AP7Kz+O3O2qx87sruYuF5UxHg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-beta.43': - resolution: {integrity: sha512-5Uxg7fQUCmfhax7FJke2+8B6cqgeUJUD9o2uXIKXhD+mG0mL6NObmVoi9wXEU1tY89mZKgAYA6fTbftx3q2ZPQ==} + '@rolldown/pluginutils@1.0.0-beta.47': + resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==} - '@rollup/plugin-commonjs@28.0.6': - resolution: {integrity: sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==} + '@rollup/plugin-commonjs@28.0.9': + resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==} engines: {node: '>=16.0.0 || 14 >= 14.17'} peerDependencies: rollup: ^2.68.0||^3.0.0||^4.0.0 @@ -3255,8 +3657,8 @@ packages: rollup: optional: true - '@rollup/plugin-node-resolve@16.0.2': - resolution: {integrity: sha512-tCtHJ2BlhSoK4cCs25NMXfV7EALKr0jyasmqVCq3y9cBrKdmJhtsy1iTz36Xhk/O+pDJbzawxF4K6ZblqCnITQ==} + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 @@ -3282,137 +3684,137 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.52.4': - resolution: {integrity: sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==} + '@rollup/rollup-android-arm-eabi@4.53.3': + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.52.4': - resolution: {integrity: sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==} + '@rollup/rollup-android-arm64@4.53.3': + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.52.4': - resolution: {integrity: sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==} + '@rollup/rollup-darwin-arm64@4.53.3': + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.52.4': - resolution: {integrity: sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==} + '@rollup/rollup-darwin-x64@4.53.3': + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.52.4': - resolution: {integrity: sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==} + '@rollup/rollup-freebsd-arm64@4.53.3': + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.4': - resolution: {integrity: sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==} + '@rollup/rollup-freebsd-x64@4.53.3': + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.52.4': - resolution: {integrity: sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.52.4': - resolution: {integrity: sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==} + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.52.4': - resolution: {integrity: sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==} + '@rollup/rollup-linux-arm64-gnu@4.53.3': + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.52.4': - resolution: {integrity: sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==} + '@rollup/rollup-linux-arm64-musl@4.53.3': + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.52.4': - resolution: {integrity: sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==} + '@rollup/rollup-linux-loong64-gnu@4.53.3': + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-gnu@4.52.4': - resolution: {integrity: sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==} + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-gnu@4.52.4': - resolution: {integrity: sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==} + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.52.4': - resolution: {integrity: sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==} + '@rollup/rollup-linux-riscv64-musl@4.53.3': + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.52.4': - resolution: {integrity: sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==} + '@rollup/rollup-linux-s390x-gnu@4.53.3': + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.52.4': - resolution: {integrity: sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==} + '@rollup/rollup-linux-x64-gnu@4.53.3': + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.52.4': - resolution: {integrity: sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==} + '@rollup/rollup-linux-x64-musl@4.53.3': + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openharmony-arm64@4.52.4': - resolution: {integrity: sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==} + '@rollup/rollup-openharmony-arm64@4.53.3': + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.52.4': - resolution: {integrity: sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==} + '@rollup/rollup-win32-arm64-msvc@4.53.3': + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.4': - resolution: {integrity: sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==} + '@rollup/rollup-win32-ia32-msvc@4.53.3': + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.52.4': - resolution: {integrity: sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==} + '@rollup/rollup-win32-x64-gnu@4.53.3': + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.52.4': - resolution: {integrity: sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==} + '@rollup/rollup-win32-x64-msvc@4.53.3': + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} cpu: [x64] os: [win32] - '@schematics/angular@21.0.0-next.8': - resolution: {integrity: sha512-9ilY3gf5Mr84abt/wTfnxNGBQOv2hPjJ61vKyIeV2mCTClsco/RctQIc4peDHToI2YMf9r7/AJZVKPUNwFoXJw==} + '@schematics/angular@21.0.3': + resolution: {integrity: sha512-XYOI2WOz8B+ydJ8iUHRXrUyjTx+YGdCQ8b2FlXnU46ksIctVU+zt4Zgu6462xeaPwOFYw6+r+TvaBAZ14a82Gw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@sentry/core@9.46.0': - resolution: {integrity: sha512-it7JMFqxVproAgEtbLgCVBYtQ9fIb+Bu0JD+cEplTN/Ukpe6GaolyYib5geZqslVxhp2sQgT+58aGvfd/k0N8Q==} + '@sentry/core@9.47.1': + resolution: {integrity: sha512-KX62+qIt4xgy8eHKHiikfhz2p5fOciXd0Cl+dNzhgPFq8klq4MGMNaf148GB3M/vBqP4nw/eFvRMAayFCgdRQw==} engines: {node: '>=18'} - '@sentry/node-core@9.46.0': - resolution: {integrity: sha512-XRVu5pqoklZeh4wqhxCLZkz/ipoKhitctgEFXX9Yh1e1BoHM2pIxT52wf+W6hHM676TFmFXW3uKBjsmRM3AjgA==} + '@sentry/node-core@9.47.1': + resolution: {integrity: sha512-7TEOiCGkyShJ8CKtsri9lbgMCbB+qNts2Xq37itiMPN2m+lIukK3OX//L8DC5nfKYZlgikrefS63/vJtm669hQ==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -3423,12 +3825,12 @@ packages: '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.0.0 '@opentelemetry/semantic-conventions': ^1.34.0 - '@sentry/node@9.46.0': - resolution: {integrity: sha512-pRLqAcd7GTGvN8gex5FtkQR5Mcol8gOy1WlyZZFq4rBbVtMbqKOQRhohwqnb+YrnmtFpj7IZ7KNDo077MvNeOQ==} + '@sentry/node@9.47.1': + resolution: {integrity: sha512-CDbkasBz3fnWRKSFs6mmaRepM2pa+tbZkrqhPWifFfIkJDidtVW40p6OnquTvPXyPAszCnDZRnZT14xyvNmKPQ==} engines: {node: '>=18'} - '@sentry/opentelemetry@9.46.0': - resolution: {integrity: sha512-w2zTxqrdmwRok0cXBoh+ksXdGRUHUZhlpfL/H2kfTodOL+Mk8rW72qUmfqQceXoqgbz8UyK8YgJbyt+XS5H4Qg==} + '@sentry/opentelemetry@9.47.1': + resolution: {integrity: sha512-STtFpjF7lwzeoedDJV+5XA6P89BfmFwFftmHSGSe3UTI8z8IoiR5yB6X2vCjSPvXlfeOs13qCNNCEZyznxM8Xw==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -3481,8 +3883,8 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - '@tsconfig/node10@1.0.11': - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + '@tsconfig/node10@1.0.12': + resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} '@tsconfig/node12@1.0.11': resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} @@ -3540,8 +3942,8 @@ packages: '@types/cors@2.8.19': resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} - '@types/duplexify@3.6.4': - resolution: {integrity: sha512-2eahVPsd+dy3CL6FugAzJcxoraWhUghZGEQJns1kTKfCXWKJ5iG/VkaB05wRVrDKHfOFKqb0X0kXh91eE99RZg==} + '@types/duplexify@3.6.5': + resolution: {integrity: sha512-fB56ACzlW91UdZ5F3VXplVMDngO8QaX5Y2mjvADtN01TT2TMy4WjF0Lg+tFDvt4uMBeTe4SgaD+qCrA7dL5/tA==} '@types/ejs@3.1.5': resolution: {integrity: sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==} @@ -3558,11 +3960,11 @@ packages: '@types/events@3.0.3': resolution: {integrity: sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==} - '@types/express-serve-static-core@4.19.6': - resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} + '@types/express-serve-static-core@4.19.7': + resolution: {integrity: sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==} - '@types/express@4.17.23': - resolution: {integrity: sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==} + '@types/express@4.17.25': + resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} '@types/folder-hash@4.0.4': resolution: {integrity: sha512-c+PwHm51Dw3fXM8SDK+93PO3oXdk4XNouCCvV67lj4aijRkZz5g67myk+9wqWWnyv3go6q96hT6ywcd3XtoZiQ==} @@ -3570,8 +3972,8 @@ packages: '@types/fs-extra@11.0.4': resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} - '@types/git-raw-commits@5.0.0': - resolution: {integrity: sha512-MQIzbZxgEnKpN1kCcw9JlQIu3Wdw5c4CCCP2cUli+DYgFjzsjtGLOeUe8oqPjjrKJudOoFnNuIZb/4sYHXEWZg==} + '@types/git-raw-commits@5.0.1': + resolution: {integrity: sha512-sd4kgxJbuZF0RDy6cX7KlKSGiwqB1mqn8nriUbxt5e1F+MO/N4hJlhaYn0Omw4g2biClFpT5Mre07x7OkGt8tg==} '@types/google.maps@3.58.1': resolution: {integrity: sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==} @@ -3579,17 +3981,14 @@ packages: '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} - '@types/http-proxy@1.17.16': - resolution: {integrity: sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==} - - '@types/jasmine@5.1.11': - resolution: {integrity: sha512-eAij9lMAsosuA8cvRcqw7p2vO+LUraktQDmOUFx2jAnya8NUchr3DryHksfhZbRzU83vzNUSZhlk1cFdoePxwA==} + '@types/http-proxy@1.17.17': + resolution: {integrity: sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==} '@types/jasmine@5.1.12': resolution: {integrity: sha512-1BzPxNsFDLDfj9InVR3IeY0ZVf4o9XV+4mDqoCfyPkbsA7dYyKAPAb2co6wLFlHcvxPlt1wShm7zQdV7uTfLGA==} - '@types/jasmine@5.1.9': - resolution: {integrity: sha512-8t4HtkW4wxiPVedMpeZ63n3vlWxEIquo/zc1Tm8ElU+SqVV7+D3Na2PWaJUp179AzTragMWVwkMv7mvty0NfyQ==} + '@types/jasmine@5.1.13': + resolution: {integrity: sha512-MYCcDkruFc92LeYZux5BC0dmqo2jk+M5UIZ4/oFnAPCXN9mCcQhLyj7F3/Za7rocVyt5YRr1MmqJqFlvQ9LVcg==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -3615,11 +4014,11 @@ packages: '@types/node-forge@1.3.14': resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==} - '@types/node@22.18.8': - resolution: {integrity: sha512-pAZSHMiagDR7cARo/cch1f3rXy0AEXwsVsVH09FcyeJVAzCnGgmYis7P3JidtTUjyadhTeSo8TgRPswstghDaw==} + '@types/node@22.19.2': + resolution: {integrity: sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==} - '@types/node@24.8.1': - resolution: {integrity: sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==} + '@types/node@24.10.4': + resolution: {integrity: sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -3633,8 +4032,8 @@ packages: '@types/pg@8.6.1': resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==} - '@types/pumpify@1.4.4': - resolution: {integrity: sha512-+cWbQUecD04MQYkjNBhPmcUIP368aloYmqm+ImdMKA8rMpxRNAhZAD6gIj+sAVTF1DliqrT/qUp6aGNi/9U3tw==} + '@types/pumpify@1.4.5': + resolution: {integrity: sha512-BGVAQyK5yJdfIII230fVYGY47V63hUNAhryuuS3b4lEN2LNwxUXFKsEf8QLDCjmZuimlj23BHppJgcrGvNtqKg==} '@types/q@0.0.32': resolution: {integrity: sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==} @@ -3660,17 +4059,17 @@ packages: '@types/semver@7.7.1': resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} - '@types/send@0.17.5': - resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==} + '@types/send@0.17.6': + resolution: {integrity: sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==} - '@types/send@1.2.0': - resolution: {integrity: sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ==} + '@types/send@1.2.1': + resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} '@types/serve-index@1.9.4': resolution: {integrity: sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==} - '@types/serve-static@1.15.9': - resolution: {integrity: sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA==} + '@types/serve-static@1.15.10': + resolution: {integrity: sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==} '@types/shelljs@0.8.17': resolution: {integrity: sha512-IDksKYmQA2W9MkQjiyptbMmcQx+8+Ol6b7h6dPU5S05JyiQDSb/nZKnrMrZqGwgV6VkVdl6/SPCKPDlMRvqECg==} @@ -3715,8 +4114,8 @@ packages: '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - '@types/yargs@17.0.33': - resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} '@types/yarnpkg__lockfile@1.1.9': resolution: {integrity: sha512-GD4Fk15UoP5NLCNor51YdfL9MSdldKCqOC9EssrRw3HVfar9wUZ5y8Lfnp+qVD6hIinLr8ygklDYnmlnlQo12Q==} @@ -3801,6 +4200,10 @@ packages: resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} engines: {node: ^18.17.0 || >=20.5.0} + abbrev@4.0.0: + resolution: {integrity: sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==} + engines: {node: ^20.17.0 || >=22.9.0} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -3885,8 +4288,8 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - algoliasearch@5.40.0: - resolution: {integrity: sha512-a9aIL2E3Z7uYUPMCmjMFFd5MWhn+ccTubEvnMy7rOTZCB62dXBJtz0R5BZ/TPuX3R9ocBsgWuAbGWQ+Ph4Fmlg==} + algoliasearch@5.40.1: + resolution: {integrity: sha512-iUNxcXUNg9085TJx0HJLjqtDE0r1RZ0GOGrt8KNQqQT5ugu8lZsHuMUYW/e0lHhq6xBvmktU9Bw4CXP9VQeKrg==} engines: {node: '>= 14.0.0'} amdefine@1.0.1: @@ -3900,8 +4303,8 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} - ansi-escapes@7.1.1: - resolution: {integrity: sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==} + ansi-escapes@7.2.0: + resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} engines: {node: '>=18'} ansi-html-community@0.0.8: @@ -3937,10 +4340,6 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - ansis@4.2.0: - resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} - engines: {node: '>=14'} - any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -4044,8 +4443,8 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - atomically@2.0.3: - resolution: {integrity: sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw==} + atomically@2.1.0: + resolution: {integrity: sha512-+gDffFXRW6sl/HCwbta7zK4uNqbPjv4YJEAdz7Vu+FLQHe77eZ4bvbJGi4hE0QPeJlMYMA3piXEr1UL3dAwx7Q==} autoprefixer@10.4.21: resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} @@ -4054,6 +4453,13 @@ packages: peerDependencies: postcss: ^8.1.0 + autoprefixer@10.4.22: + resolution: {integrity: sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -4064,10 +4470,6 @@ packages: aws4@1.13.2: resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} - axe-core@4.10.3: - resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} - engines: {node: '>=4'} - axe-core@4.11.0: resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} engines: {node: '>=4'} @@ -4111,11 +4513,16 @@ packages: balanced-match@2.0.0: resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} - bare-events@2.7.0: - resolution: {integrity: sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==} + bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true - bare-fs@4.4.5: - resolution: {integrity: sha512-TCtu93KGLu6/aiGWzMr12TmSRS6nKdfhAnzTQRbXoSWxkbb9eRd53jQ51jG7g1gYjjtto3hbBrrhzg6djcgiKg==} + bare-fs@4.5.2: + resolution: {integrity: sha512-veTnRzkb6aPHOvSKIOy60KzURfBdUflr5VReI+NSaPL6xf+XLdONQgZgpYvUuZLVQ8dCqxpBAudaOM1+KpAUxw==} engines: {bare: '>=1.16.0'} peerDependencies: bare-buffer: '*' @@ -4141,8 +4548,8 @@ packages: bare-events: optional: true - bare-url@2.2.2: - resolution: {integrity: sha512-g+ueNGKkrjMazDG3elZO1pNs3HY5+mMmOet1jtKyhOaCnkLzitxf26z7hoAEkDNgdNmnc1KIlt/dw6Po6xZMpA==} + bare-url@2.3.2: + resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -4151,8 +4558,8 @@ packages: resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} engines: {node: ^4.5.0 || >= 5.9} - baseline-browser-mapping@2.8.12: - resolution: {integrity: sha512-vAPMQdnyKCBtkmQA6FMCBvU9qFIppS3nzyXnEM+Lo2IAhG4Mpjv9cCxMudhgV3YdNNJv6TNqXy97dfRVL2LmaQ==} + baseline-browser-mapping@2.9.5: + resolution: {integrity: sha512-D5vIoztZOq1XM54LUdttJVc96ggEsIfju2JBvht06pSzpckp3C7HReun67Bghzrtdsq9XdMGbSSB3v3GhMNmAA==} hasBin: true basic-auth-connect@1.1.0: @@ -4203,12 +4610,12 @@ packages: engines: {node: '>=6.9.x'} hasBin: true - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + body-parser@1.20.4: + resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - body-parser@2.2.0: - resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + body-parser@2.2.1: + resolution: {integrity: sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==} engines: {node: '>=18'} bonjour-service@1.3.0: @@ -4231,8 +4638,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.26.3: - resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -4287,8 +4694,8 @@ packages: resolution: {integrity: sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==} engines: {node: ^18.17.0 || >=20.5.0} - cacache@20.0.1: - resolution: {integrity: sha512-+7LYcYGBYoNqTp1Rv7Ny1YjUo5E0/ftkQtraH3vkfAGgVHc+ouWdC8okAwQgQR7EVIdW6JTzTmhKFwzb+4okAQ==} + cacache@20.0.3: + resolution: {integrity: sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==} engines: {node: ^20.17.0 || >=22.9.0} call-bind-apply-helpers@1.0.2: @@ -4325,8 +4732,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001747: - resolution: {integrity: sha512-mzFa2DGIhuc5490Nd/G31xN1pnBnYMadtkyTjefPI7wzypqgCEpeWu9bJr0OnDsyKrW75zA9ZAt7pbQFmwLsQg==} + caniuse-lite@1.0.30001760: + resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} canonical-path@0.0.2: resolution: {integrity: sha512-y8EIEvL+IW81S4hRQWCRFtly+g1cc1G+wxHpjhYR9jI2+JJjWiaKnkH8mmvNHOMOAd9fzgARDO3AEzjuR51qaA==} @@ -4373,8 +4780,8 @@ packages: character-entities-legacy@1.1.4: resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} - chardet@2.1.0: - resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} checkpoint-stream@0.1.2: resolution: {integrity: sha512-eYXIcydL3mPjjEVLxHdi1ISgTwmxGJZ8vyJ3lYVvFTDRyTOZMTbKZdRJqiA7Gi1rPcwOyyzcrZmGLL8ff7e69w==} @@ -4404,8 +4811,8 @@ packages: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} - chromium-bidi@9.1.0: - resolution: {integrity: sha512-rlUzQ4WzIAWdIbY/viPShhZU2n21CxDUgazXVbw4Hu1MwaeUSEksSeM6DqPgpRjCLXRk702AVRxJxoOz0dw4OA==} + chromium-bidi@11.0.0: + resolution: {integrity: sha512-cM3DI+OOb89T3wO8cpPSro80Q9eKYJ7hGVXoGS3GkDPxnYSqiv+6xwpIf6XERyJ9Tdsl09hmNmY94BkgZdVekw==} peerDependencies: devtools-protocol: '*' @@ -4452,8 +4859,8 @@ packages: resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} engines: {node: 10.* || >= 12.*} - cli-truncate@5.1.0: - resolution: {integrity: sha512-7JDGG+4Zp0CsknDCedl0DYdaeOhc46QNpXi3NLQblkZpXXgA6LncLDUUyvrjSvZeF3VRQa+KiMGomazQrC1V8g==} + cli-truncate@5.1.1: + resolution: {integrity: sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==} engines: {node: '>=20'} cli-width@4.1.0: @@ -4492,8 +4899,8 @@ packages: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - color-convert@3.1.2: - resolution: {integrity: sha512-UNqkvCDXstVck3kdowtOTWROIJQwafjOfXSmddoDrXo4cewMKmusCeF22Q24zvjR8nwWib/3S/dfyzPItPEiJg==} + color-convert@3.1.3: + resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} engines: {node: '>=14.6'} color-name@1.1.3: @@ -4502,16 +4909,16 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-name@2.0.2: - resolution: {integrity: sha512-9vEt7gE16EW7Eu7pvZnR0abW9z6ufzhXxGXZEVU9IqPdlsUiMwJeJfRtq0zePUmnbHGT9zajca7mX8zgoayo4A==} + color-name@2.1.0: + resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} engines: {node: '>=12.20'} - color-string@2.1.2: - resolution: {integrity: sha512-RxmjYxbWemV9gKu4zPgiZagUxbH3RQpEIO77XoSSX0ivgABDZ+h8Zuash/EMFLTI4N9QgFPOJ6JQpPZKFxa+dA==} + color-string@2.1.4: + resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} engines: {node: '>=18'} - color@5.0.2: - resolution: {integrity: sha512-e2hz5BzbUPcYlIRHo8ieAhYgoajrJr+hWoceg6E345TPsATMUKqDgzt8fSXZJJbxfpiPzkWyphz8yn8At7q3fA==} + color@5.0.3: + resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} engines: {node: '>=18'} colord@2.9.3: @@ -4606,9 +5013,9 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} - content-disposition@1.0.0: - resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} - engines: {node: '>= 0.6'} + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} @@ -4618,8 +5025,8 @@ packages: resolution: {integrity: sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==} engines: {node: '>=18'} - conventional-commits-parser@6.2.0: - resolution: {integrity: sha512-uLnoLeIW4XaoFtH37qEcg/SXMJmKF4vi7V0H2rnPueg+VEtFGA/asSCNTcq4M/GQ6QmlzchAEtOoDTtKqWeHag==} + conventional-commits-parser@6.2.1: + resolution: {integrity: sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==} engines: {node: '>=18'} hasBin: true @@ -4629,17 +5036,13 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + cookie-signature@1.0.7: + resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} - engines: {node: '>= 0.6'} - cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} @@ -4653,8 +5056,8 @@ packages: peerDependencies: webpack: ^5.1.0 - core-js-compat@3.45.1: - resolution: {integrity: sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==} + core-js-compat@3.47.0: + resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -4864,12 +5267,12 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - default-browser-id@5.0.0: - resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} engines: {node: '>=18'} - default-browser@5.2.1: - resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} + default-browser@5.4.0: + resolution: {integrity: sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==} engines: {node: '>=18'} defaults@1.0.4: @@ -4927,19 +5330,19 @@ packages: engines: {node: '>=0.10'} hasBin: true - detect-libc@2.1.1: - resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} - devtools-protocol@0.0.1508733: - resolution: {integrity: sha512-QJ1R5gtck6nDcdM+nlsaJXcelPEI7ZxSMw1ujHpO1c4+9l+Nue5qlebi9xO1Z2MGr92bFOQTW7/rrheh5hHxDg==} - devtools-protocol@0.0.1527314: resolution: {integrity: sha512-UohCFOlzpPPD/IcsxM0k4lVZp/GfhPVJ6l2No5XX+LknpGisPWJe17oOHQhZTHf6ThUFIMwHO6bSEZUq/6oP7w==} + devtools-protocol@0.0.1534754: + resolution: {integrity: sha512-26T91cV5dbOYnXdJi5qQHoTtUoNEqwkHcAyu/IKtjIAxiEqPMrDiRkDOPWVsGfNZGmlQVHQbZRSjD8sxagWVsQ==} + dgeni-packages@0.30.0: resolution: {integrity: sha512-k5y9HSwJzWgc8S7bHxejojJfuo2heltY9lTa5UgfqoBv2vubCwqXhVxFBXr3nKfymc9YOALCnk10JYeOdVLLWQ==} engines: {node: '>=12.0.0', yarn: '>=0.17.9'} @@ -5037,11 +5440,11 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.230: - resolution: {integrity: sha512-A6A6Fd3+gMdaed9wX83CvHYJb4UuapPD5X5SLq72VZJzxHSY0/LUweGXRWmQlh2ln7KV7iw7jnwXK7dlPoOnHQ==} + electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} - emoji-regex@10.5.0: - resolution: {integrity: sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -5158,13 +5561,23 @@ packages: es6-promisify@5.0.0: resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} - esbuild-wasm@0.25.10: - resolution: {integrity: sha512-IyyfrTA2iiOh/uhlaJj0aUDgW42lFhr29ZeKouVNOz/8mLyuqWbEuVst+B4RBH18pb3AcOHnaOgyskAbsVOe3A==} + esbuild-wasm@0.26.0: + resolution: {integrity: sha512-9rZuermDo9ZbWvKBv/vDRaRciCpR4L3rEbZLDs5kDq3TrCHRQZaQipQeV9wK/btpLBzNUBujTrd1uorDxbL/GA==} engines: {node: '>=18'} hasBin: true - esbuild@0.25.10: - resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.26.0: + resolution: {integrity: sha512-3Hq7jri+tRrVWha+ZeIVhl4qJRha/XjRNSopvTsOaCvfPHrflTYTcUFcEjMKdxofsXXsdc4zjg5NOTnL4Gl57Q==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.27.1: + resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==} engines: {node: '>=18'} hasBin: true @@ -5300,8 +5713,8 @@ packages: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} - exponential-backoff@3.1.2: - resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} express-rate-limit@7.5.1: resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} @@ -5309,12 +5722,12 @@ packages: peerDependencies: express: '>= 4.11' - express@4.21.2: - resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} + express@4.22.1: + resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} engines: {node: '>= 0.10.0'} - express@5.1.0: - resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} extend@3.0.2: @@ -5404,13 +5817,13 @@ packages: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} engines: {node: '>= 0.8'} - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + finalhandler@1.3.2: + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} engines: {node: '>= 0.8'} - finalhandler@2.1.0: - resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} - engines: {node: '>= 0.8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} @@ -5420,18 +5833,13 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - firebase-tools@14.17.0: - resolution: {integrity: sha512-BWOfB9kokuRZbfRpr1AJrMiJHzyp8TjTNmYlgmHnGcBOAwtDinaeceqiKwLyZ6SucnOWj6Ca73DubqbAj+DmKw==} - engines: {node: '>=20.0.0 || >=22.0.0'} - hasBin: true - firebase-tools@14.20.0: resolution: {integrity: sha512-8zduD1/tpm8tEf4V6dOdveLHVttPUdnubZeZksdvRcetJuffNuU+Ugr4/JsObhxJP0n0Npb2MvPMHln6xKHMXw==} engines: {node: '>=20.0.0 || >=22.0.0'} hasBin: true - firebase@12.4.0: - resolution: {integrity: sha512-/chNgDQ6ppPPGOQO4jctxOa/5JeQxuhaxA7Y90K0I+n/wPfoO8mRveedhVUdo7ExLcWUivnnow/ouSLYSI5Icw==} + firebase@12.7.0: + resolution: {integrity: sha512-ZBZg9jFo8uH4Emd7caOqtalKJfDGHnHQSrCPiqRAdTFQd0wL3ERilUBfhnhBLnlernugkN/o7nJa0p+sE71Izg==} flat-cache@3.2.0: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} @@ -5480,8 +5888,8 @@ packages: resolution: {integrity: sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==} engines: {node: '>= 0.12'} - form-data@4.0.4: - resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} formdata-polyfill@4.0.10: @@ -5498,6 +5906,9 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -5555,8 +5966,8 @@ packages: resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==} engines: {node: '>=14'} - gaxios@7.1.2: - resolution: {integrity: sha512-/Szrn8nr+2TsQT1Gp8iIe/BEytJmbyfrbFh419DfGQSkEgNEhbPi7JRJuughjkTzPWgU9gBQf5AVu3DbHt0OXA==} + gaxios@7.1.3: + resolution: {integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==} engines: {node: '>=18'} gaze@1.1.3: @@ -5567,8 +5978,8 @@ packages: resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==} engines: {node: '>=14'} - gcp-metadata@7.0.1: - resolution: {integrity: sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==} + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} engines: {node: '>=18'} generator-function@2.0.1: @@ -5607,8 +6018,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} get-uri@6.0.5: resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} @@ -5645,15 +6056,19 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} hasBin: true - glob@11.0.3: - resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + glob@11.1.0: + resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} engines: {node: 20 || >=22} hasBin: true + glob@13.0.0: + resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} + engines: {node: 20 || >=22} + glob@5.0.15: resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} deprecated: Glob versions prior to v9 are no longer supported @@ -5697,8 +6112,8 @@ packages: resolution: {integrity: sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==} engines: {node: '>= 0.10'} - google-auth-library@10.4.0: - resolution: {integrity: sha512-CmIrSy1bqMQUsPmA9+hcSbAXL80cFhu40cGMUjCaLpNKVzzvi+0uAHq8GNZxkoGYIsTX4ZQ7e4aInAqWxgn4fg==} + google-auth-library@10.5.0: + resolution: {integrity: sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==} engines: {node: '>=18'} google-auth-library@9.15.1: @@ -5709,16 +6124,16 @@ packages: resolution: {integrity: sha512-V6eky/xz2mcKfAd1Ioxyd6nmA61gao3n01C+YeuIwu3vzM9EDR6wcVzMSIbLMDXWeoi9SHYctXuKYC5uJUT3eQ==} engines: {node: '>=14'} - google-gax@5.0.4: - resolution: {integrity: sha512-HmQ6zIYBs2EikTk+kjeHmtHprNTEpsnVaKONw9cwZZwUNCkUb+D5RYrJpCxyjdvIDvJp3wLbVReolJLRZRms1g==} + google-gax@5.0.6: + resolution: {integrity: sha512-1kGbqVQBZPAAu4+/R1XxPQKP0ydbNYoLAr4l0ZO2bMV0kLyLW4I1gAk++qBLWt7DPORTzmWRMsCZe86gDjShJA==} engines: {node: '>=18'} google-logging-utils@0.0.2: resolution: {integrity: sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==} engines: {node: '>=14'} - google-logging-utils@1.1.1: - resolution: {integrity: sha512-rcX58I7nqpu4mbKztFeOAObbomBbHU2oIb/d3tJfF3dizGSApqtSwYJigGCooHdnMyQBIw8BrWyK96w3YXgr6A==} + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} engines: {node: '>=14'} googleapis-common@8.0.2-rc.0: @@ -5741,8 +6156,8 @@ packages: peerDependencies: graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - graphql@16.11.0: - resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} + graphql@16.12.0: + resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} grpc-gcp@1.0.1: @@ -5864,8 +6279,8 @@ packages: resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} engines: {node: ^16.14.0 || >=18.0.0} - hosted-git-info@9.0.0: - resolution: {integrity: sha512-gEf705MZLrDPkbbhi8PnoO4ZwYgKoNL+ISZ3AjZMht2r3N5tuTwncyDi6Fv2/qDnMmZxgs0yI8WDOyR8q3G+SQ==} + hosted-git-info@9.0.2: + resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} engines: {node: ^20.17.0 || >=22.9.0} hpack.js@2.1.6: @@ -5911,6 +6326,10 @@ packages: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + http-link-header@1.1.3: resolution: {integrity: sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ==} engines: {node: '>=6.0.0'} @@ -6019,15 +6438,15 @@ packages: immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - immutable@5.1.3: - resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==} + immutable@5.1.4: + resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - import-in-the-middle@1.14.4: - resolution: {integrity: sha512-eWjxh735SJLFJJDs5X82JQ2405OdJeAHDBnaoFCfdr5GVc7AWc9xU7KbrF+3Xd5F2ccP1aQFKtY+65X6EfKZ7A==} + import-in-the-middle@1.15.0: + resolution: {integrity: sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==} import-lazy@2.1.0: resolution: {integrity: sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==} @@ -6069,6 +6488,10 @@ packages: resolution: {integrity: sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==} engines: {node: ^18.17.0 || >=20.5.0} + ini@6.0.0: + resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} + engines: {node: ^20.17.0 || >=22.9.0} + install-artifact-from-github@1.4.0: resolution: {integrity: sha512-+y6WywKZREw5rq7U2jvr2nmZpT7cbWbQQ0N/qfcseYnzHFz2cZz1Et52oY+XttYuYeTkI8Y+R2JNWj68MpQFSg==} hasBin: true @@ -6077,11 +6500,11 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} - intl-messageformat@10.7.17: - resolution: {integrity: sha512-0Ugaf65B2J76rb31drgNF1l6bGEDkbIiYc2Glx6jaZINHnwa5kDRGy8KXYuA+/8P4G0c9prAFhfVhQJJfzUuvQ==} + intl-messageformat@10.7.18: + resolution: {integrity: sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==} - ip-address@10.0.1: - resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} ip-regex@4.3.0: @@ -6092,8 +6515,8 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - ipaddr.js@2.2.0: - resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} + ipaddr.js@2.3.0: + resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} engines: {node: '>= 10'} is-alphabetical@1.0.4: @@ -6457,12 +6880,12 @@ packages: jasmine-core@4.6.1: resolution: {integrity: sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==} - jasmine-core@5.11.0: - resolution: {integrity: sha512-MPJ8L5yyNul0F2SuEsLASwESXQjJvBXnKu31JWFyRZSvuv2B79K4GDWN3pSqvLheUNh7Fyb6dXwd4rsz95O2Kg==} - jasmine-core@5.12.0: resolution: {integrity: sha512-QqO4pX33GEML5JoGQU6BM5NHKPgEsg+TXp3jCIDek9MbfEp2JUYEFBo9EF1+hegWy/bCHS1m5nP0BOp18G6rVA==} + jasmine-core@5.13.0: + resolution: {integrity: sha512-vsYjfh7lyqvZX5QgqKc4YH8phs7g96Z8bsdIFNEU3VqXhlHaq+vov/Fgn/sr6MiUczdZkyXRC3TX369Ll4Nzbw==} + jasmine-reporters@2.5.2: resolution: {integrity: sha512-qdewRUuFOSiWhiyWZX8Yx3YNQ9JG51ntBEO4ekLQRpktxFTwUHy24a86zD/Oi2BRTKksEdfWQZcQFqzjqIkPig==} @@ -6473,12 +6896,8 @@ packages: resolution: {integrity: sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==} hasBin: true - jasmine@5.11.0: - resolution: {integrity: sha512-MhIYY2pLfRA5hhIvY72ZLilwKeZEBuTyIUv9JDB+b+pEYehsJDW2obKF2dmMtWaFG6pDiFiAUNphpZ7SW7fFMA==} - hasBin: true - - jasmine@5.12.0: - resolution: {integrity: sha512-KmKeTNuH8rgAuPRL5AUsXWSdJVlDu+pgqi2dLXoZUSH/g3kR+7Ho8B7hEhwDu0fu1PLuiXZtfaxmQ/mB5wqihw==} + jasmine@5.13.0: + resolution: {integrity: sha512-oLCXIhEb5e0zzjn9GyuvcuisvLBwUjmgz7a0RNGWKwQtJCDld4m+vwKUpAIJVLB5vbmQFdtKhT86/tIZlJ5gYw==} hasBin: true jasminewd2@2.2.0: @@ -6499,6 +6918,9 @@ packages: join-path@1.1.1: resolution: {integrity: sha512-jnt9OC34sLXMLJ6YfPQ2ZEKrR9mB5ZbSnQb4LPaOx1c5rTzxpR33L18jjp0r75mGGTJmsil3qwN1B5IBeTnSSA==} + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + jpeg-js@0.4.4: resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} @@ -6509,12 +6931,12 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true jsbn@0.1.1: @@ -6537,9 +6959,9 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-parse-even-better-errors@4.0.0: - resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==} - engines: {node: ^18.17.0 || >=20.5.0} + json-parse-even-better-errors@5.0.0: + resolution: {integrity: sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==} + engines: {node: ^20.17.0 || >=22.9.0} json-parse-helpfulerror@1.0.3: resolution: {integrity: sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==} @@ -6577,8 +6999,8 @@ packages: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} - jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} jsprim@1.4.2: @@ -6588,17 +7010,11 @@ packages: jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} - jwa@1.4.2: - resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} - jwa@2.0.1: resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - jws@3.2.2: - resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} - - jws@4.0.0: - resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} kagekiri@2.0.0: resolution: {integrity: sha512-4AG25g5A6NTS7+9RRIyB6Yn5G8QHu+spy/pENI0zfNC4j4XBsaVueykK/yJAmE1x4MyD6NpcoXhVUmBB9nI9DA==} @@ -6669,8 +7085,8 @@ packages: kuler@2.0.0: resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} - launch-editor@2.11.1: - resolution: {integrity: sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==} + launch-editor@2.12.0: + resolution: {integrity: sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==} lazystream@1.0.1: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} @@ -6732,16 +7148,16 @@ packages: lighthouse-stack-packs@1.12.3: resolution: {integrity: sha512-d8IsOpE83kbANgnM+Tp8+x6HcMpX9o2ITBiUERssgzAIFdZCQzs/f4k6D0DLQTE59enml9mbAOU52Wu35exWtg==} - lighthouse@13.0.0: - resolution: {integrity: sha512-s9koINEnVGm4n4oej4G3NET4e8i1XjPYCxEqp+TDlwUUkS5jpeOiFbIRLvPol/kgaeYce7BBqg8m52V7MEW7Lw==} + lighthouse@13.0.1: + resolution: {integrity: sha512-SsxFXPE0DoUv6rH3hva0luh0pbpyIx9McBQ1WUpqCYFMtArODT6l9Zpu1K3XSdkeMQ2/zFcMN5o3pPVhfVwnCA==} engines: {node: '>=22.19'} hasBin: true lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - listr2@9.0.4: - resolution: {integrity: sha512-1wd/kpAdKRLwv7/3OKC8zZ5U8e/fajCfWMxacUvB79S5nLrYGPtUI/8chMQhn3LQjsRVErTb9i1ECAwW0ZIHnQ==} + listr2@9.0.5: + resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} engines: {node: '>=20.0.0'} lmdb@3.4.3: @@ -6752,8 +7168,8 @@ packages: resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} engines: {node: '>=4'} - loader-runner@4.3.0: - resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + loader-runner@4.3.1: + resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} loader-utils@2.0.4: @@ -6868,8 +7284,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.2: - resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} + lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -6912,8 +7328,8 @@ packages: resolution: {integrity: sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==} engines: {node: ^18.17.0 || >=20.5.0} - make-fetch-happen@15.0.2: - resolution: {integrity: sha512-sI1NY4lWlXBAfjmCtVWIIpBypbBdhHtcjnwnv+gtCnsaOffyFil3aidszGC8hgzJe+fT1qix05sWxmD/Bmf/oQ==} + make-fetch-happen@15.0.3: + resolution: {integrity: sha512-iyyEpDty1mwW3dGlYXAJqC/azFn5PPvgKVwXayOGBSmKLxhKZ9fg4qIan2ePpp1vJIwfFiO34LAPZgq9SZW9Aw==} engines: {node: ^20.17.0 || >=22.9.0} map-obj@1.0.1: @@ -6943,8 +7359,8 @@ packages: engines: {node: '>= 18'} hasBin: true - marked@16.3.0: - resolution: {integrity: sha512-K3UxuKu6l6bmA5FUwYho8CfJBlsUWAooKtdGgMcERSpF7gcBUrCGsLH7wDaaNOzwq18JzSUDyoEb/YsrqMac3w==} + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} engines: {node: '>= 20'} hasBin: true @@ -6966,8 +7382,8 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} - memfs@4.48.1: - resolution: {integrity: sha512-vWO+1ROkhOALF1UnT9aNOOflq5oFDlqwTXaPg6duo07fBLxSH0+bcF0TY1lbA1zTNKyGgDxgaDdKx5MaewLX5A==} + memfs@4.51.1: + resolution: {integrity: sha512-Eyt3XrufitN2ZL9c/uIRMyDwXanLI88h/L3MoWqNY747ha3dMR9dWqp8cRT5ntjZ0U1TNuq4U91ZXK0sMBjYOQ==} memorystream@0.3.1: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} @@ -7015,9 +7431,9 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - mime-types@3.0.1: - resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} - engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} @@ -7050,8 +7466,8 @@ packages: minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - minimatch@10.0.3: - resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} minimatch@3.0.8: @@ -7091,6 +7507,10 @@ packages: resolution: {integrity: sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==} engines: {node: ^18.17.0 || >=20.5.0} + minipass-fetch@5.0.0: + resolution: {integrity: sha512-fiCdUALipqgPWrOVTz9fw0XhcazULXOSU6ie40DDbX1F49p1dBrSRBuswndTx1x3vEb/g0FT7vC4c4C2u/mh3A==} + engines: {node: ^20.17.0 || >=22.9.0} + minipass-flush@1.0.5: resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} engines: {node: '>= 8'} @@ -7180,11 +7600,15 @@ packages: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} + mute-stream@3.0.0: + resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} + engines: {node: ^20.17.0 || >=22.9.0} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nan@2.23.0: - resolution: {integrity: sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==} + nan@2.24.0: + resolution: {integrity: sha512-Vpf9qnVW1RaDkoNKFUvfxqAbtI8ncb8OJlqZ9wwpXzWPEsvsB1nvdUi6oYrHIkQ1Y/tMDnr1h4nczS0VB9Xykg==} nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} @@ -7257,8 +7681,8 @@ packages: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - node-forge@1.3.1: - resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + node-forge@1.3.3: + resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} engines: {node: '>= 6.13.0'} node-gyp-build-optional-packages@5.2.2: @@ -7269,13 +7693,18 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true - node-gyp@11.4.2: - resolution: {integrity: sha512-3gD+6zsrLQH7DyYOUIutaauuXrcyxeTPyQuZQCQoNPZMHMMS5m4y0xclNpvYzoK3VNzuyxT6eF4mkIL4WSZ1eQ==} + node-gyp@11.5.0: + resolution: {integrity: sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==} engines: {node: ^18.17.0 || >=20.5.0} hasBin: true - node-releases@2.0.23: - resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} + node-gyp@12.1.0: + resolution: {integrity: sha512-W+RYA8jBnhSr2vrTtlPYPc1K+CSjGpVDRZxcqJcERZ8ND3A1ThWPHRwctTx3qC3oW99jt726jhdz3Y6ky87J4g==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} nopt@3.0.6: resolution: {integrity: sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==} @@ -7286,6 +7715,11 @@ packages: engines: {node: ^18.17.0 || >=20.5.0} hasBin: true + nopt@9.0.0: + resolution: {integrity: sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -7309,9 +7743,9 @@ packages: resolution: {integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - npm-install-checks@7.1.2: - resolution: {integrity: sha512-z9HJBCYw9Zr8BqXcllKIs5nI+QggAImbBdHphOzVYrz2CB4iQ6FzWyKmlqDZua+51nAu7FcemlbTc9VgQN5XDQ==} - engines: {node: ^18.17.0 || >=20.5.0} + npm-install-checks@8.0.0: + resolution: {integrity: sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==} + engines: {node: ^20.17.0 || >=22.9.0} npm-normalize-package-bin@3.0.1: resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==} @@ -7321,6 +7755,10 @@ packages: resolution: {integrity: sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==} engines: {node: ^18.17.0 || >=20.5.0} + npm-normalize-package-bin@5.0.0: + resolution: {integrity: sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==} + engines: {node: ^20.17.0 || >=22.9.0} + npm-package-arg@11.0.3: resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} engines: {node: ^16.14.0 || >=18.0.0} @@ -7329,20 +7767,20 @@ packages: resolution: {integrity: sha512-6zqls5xFvJbgFjB1B2U6yITtyGBjDBORB7suI4zA4T/sZ1OmkMFlaQSNB/4K0LtXNA1t4OprAFxPisadK5O2ag==} engines: {node: ^20.17.0 || >=22.9.0} - npm-packlist@10.0.2: - resolution: {integrity: sha512-DrIWNiWT0FTdDRjGOYfEEZUNe1IzaSZ+up7qBTKnrQDySpdmuOQvytrqQlpK5QrCA4IThMvL4wTumqaa1ZvVIQ==} + npm-packlist@10.0.3: + resolution: {integrity: sha512-zPukTwJMOu5X5uvm0fztwS5Zxyvmk38H/LfidkOMt3gbZVCyro2cD/ETzwzVPcWZA3JOyPznfUN/nkyFiyUbxg==} engines: {node: ^20.17.0 || >=22.9.0} - npm-pick-manifest@11.0.1: - resolution: {integrity: sha512-HnU7FYSWbo7dTVHtK0G+BXbZ0aIfxz/aUCVLN0979Ec6rGUX5cJ6RbgVx5fqb5G31ufz+BVFA7y1SkRTPVNoVQ==} + npm-pick-manifest@11.0.3: + resolution: {integrity: sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==} engines: {node: ^20.17.0 || >=22.9.0} npm-pick-manifest@9.1.0: resolution: {integrity: sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==} engines: {node: ^16.14.0 || >=18.0.0} - npm-registry-fetch@19.0.0: - resolution: {integrity: sha512-DFxSAemHUwT/POaXAOY4NJmEWBPB0oKbwD6FFDE9hnt1nORkt/FXvgjD4hQjoKoHw9u0Ezws9SPXwV7xE/Gyww==} + npm-registry-fetch@19.1.1: + resolution: {integrity: sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==} engines: {node: ^20.17.0 || >=22.9.0} npm-run-all@4.1.5: @@ -7492,8 +7930,8 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-map@7.0.3: - resolution: {integrity: sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==} + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} engines: {node: '>=18'} p-queue@6.6.2: @@ -7612,8 +8050,8 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.0: - resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + path-scurry@2.0.1: + resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} engines: {node: 20 || >=22} path-to-regexp@0.1.12: @@ -7719,8 +8157,8 @@ packages: resolution: {integrity: sha512-0u3N7H4+hbr40KjuVn2uNhOcthu/9usKhnw5vT3J7ply79v3D3M8naI00el9Klcy16x557VsEkkUQaHCWFXC/g==} engines: {node: '>=20.x'} - pkce-challenge@5.0.0: - resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} portfinder@1.0.38: @@ -7790,8 +8228,8 @@ packages: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} - postcss-selector-parser@7.1.0: - resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} postcss-value-parser@4.2.0: @@ -7821,8 +8259,8 @@ packages: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} engines: {node: '>=14'} hasBin: true @@ -7834,6 +8272,10 @@ packages: resolution: {integrity: sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==} engines: {node: ^18.17.0 || >=20.5.0} + proc-log@6.1.0: + resolution: {integrity: sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==} + engines: {node: ^20.17.0 || >=22.9.0} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -7870,8 +8312,8 @@ packages: resolution: {integrity: sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==} engines: {node: '>=14.0.0'} - proto3-json-serializer@3.0.2: - resolution: {integrity: sha512-AnMIfnoK2Ml3F/ZVl5PxcwIoefMxj4U/lomJ5/B2eIGdxw4UkbV1YamtsMQsEkZATdMCKMbnI1iG9RQaJbxBGw==} + proto3-json-serializer@3.0.4: + resolution: {integrity: sha512-E1sbAYg3aEbXrq0n1ojJkRHQJGE1kaE/O6GLA94y8rnJBfgvOPTOd1b9hOceQK1FFZI9qMh1vBERCyO2ifubcw==} engines: {node: '>=18'} protobufjs@7.4.0: @@ -7930,8 +8372,8 @@ packages: resolution: {integrity: sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==} engines: {node: '>=8'} - puppeteer-core@24.23.0: - resolution: {integrity: sha512-yl25C59gb14sOdIiSnJ08XiPP+O2RjuyZmEG+RjYmCXO7au0jcLf7fRiyii96dXGUBW7Zwei/mVKfxMx/POeFw==} + puppeteer-core@24.32.1: + resolution: {integrity: sha512-GdWTOgy3RqaW6Etgx93ydlVJ4FBJ6TmhMksG5W7v4uawKAzLHNj33k4kBQ1SFZ9NvoXNjhdQuIQ+uik2kWnarA==} engines: {node: '>=18'} q@1.4.1: @@ -7954,10 +8396,6 @@ packages: resolution: {integrity: sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==} engines: {node: '>=0.9'} - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} - engines: {node: '>=0.6'} - qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -7987,20 +8425,20 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} engines: {node: '>= 0.8'} - raw-body@3.0.1: - resolution: {integrity: sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==} + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - re2@1.22.1: - resolution: {integrity: sha512-E4J0EtgyNLdIr0wTg0dQPefuiqNY29KaLacytiUAYYRzxCG+zOkWoUygt1rI+TA1LrhN49/njrfSO1DHtVC5Vw==} + re2@1.22.3: + resolution: {integrity: sha512-002aE82U91DiaUA16U6vbiJusvPXn1OWiQukOxJkVUTXbzrSuQbFNHYKcGw8QK/uifRCfjl2Hd/vXYDanKkmaQ==} read-pkg-up@7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} @@ -8113,8 +8551,8 @@ packages: require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - requirejs@2.3.7: - resolution: {integrity: sha512-DouTG8T1WanGok6Qjg2SXuCMzszOo0eHeH9hDZ5Y4x8Je+9JB38HdTLT4/VA8OaUhBa0JPVHJ0pyBkM1z+pDsw==} + requirejs@2.3.8: + resolution: {integrity: sha512-7/cTSLOdYkNBNJcDMWf+luFvMriVm7eYxp4BcFCsAX0wF421Vyce5SXP17c+Jd5otXKGNehIonFlyQXSowL6Mw==} engines: {node: '>=0.4.0'} hasBin: true @@ -8139,8 +8577,8 @@ packages: resolve@1.1.7: resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} hasBin: true @@ -8194,12 +8632,16 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rimraf@5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + hasBin: true + robots-parser@3.0.1: resolution: {integrity: sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ==} engines: {node: '>=10.0.0'} - rolldown@1.0.0-beta.43: - resolution: {integrity: sha512-6RcqyRx0tY1MlRLnjXPp/849Rl/CPFhzpGGwNPEPjKwqBMqPq/Rbbkxasa8s0x+IkUk46ty4jazb5skZ/Vgdhw==} + rolldown@1.0.0-beta.47: + resolution: {integrity: sha512-Mid74GckX1OeFAOYz9KuXeWYhq3xkXbMziYIC+ULVdUzPTG9y70OBSBQDQn9hQP8u/AfhuYw1R0BSg15nBI4Dg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -8220,8 +8662,8 @@ packages: '@types/node': optional: true - rollup@4.52.4: - resolution: {integrity: sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==} + rollup@4.53.3: + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -8310,8 +8752,8 @@ packages: saucelabs@1.5.0: resolution: {integrity: sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==} - sax@1.4.1: - resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + sax@1.4.3: + resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} schema-utils@4.3.3: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} @@ -8340,11 +8782,6 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true - semver@7.7.3: resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} @@ -8358,6 +8795,10 @@ packages: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} + send@0.19.1: + resolution: {integrity: sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==} + engines: {node: '>= 0.8.0'} + send@1.2.0: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} @@ -8616,6 +9057,10 @@ packages: resolution: {integrity: sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==} engines: {node: ^18.17.0 || >=20.5.0} + ssri@13.0.0: + resolution: {integrity: sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==} + engines: {node: ^20.17.0 || >=22.9.0} + stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} @@ -8741,8 +9186,11 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - stubborn-fs@1.2.5: - resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==} + stubborn-fs@2.0.0: + resolution: {integrity: sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==} + + stubborn-utils@1.0.2: + resolution: {integrity: sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==} stubs@3.0.0: resolution: {integrity: sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==} @@ -8820,8 +9268,8 @@ packages: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} - tar@7.5.1: - resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} + tar@7.5.2: + resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} engines: {node: '>=18'} tcp-port-used@1.0.2: @@ -8839,8 +9287,8 @@ packages: resolution: {integrity: sha512-WfecDCR1xC9b0nsrzSaxPf3ZuWeWLUWblW4vlDQAa1biQaKHiImHnJfeQocQe/hXKMcolRzgkcVX/7kK4zoWbw==} engines: {node: '>=0.8.0'} - terser-webpack-plugin@5.3.14: - resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + terser-webpack-plugin@5.3.15: + resolution: {integrity: sha512-PGkOdpRFK+rb1TzVz+msVhw4YMRT9txLF4kRqvJhGhCM324xuR3REBSHALN+l+sAhKUmz0aotnjp5D+P83mLhQ==} engines: {node: '>= 10.13.0'} peerDependencies: '@swc/core': '*' @@ -8860,6 +9308,11 @@ packages: engines: {node: '>=10'} hasBin: true + terser@5.44.1: + resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} + engines: {node: '>=10'} + hasBin: true + text-decoder@1.2.3: resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} @@ -8882,6 +9335,9 @@ packages: third-party-web@0.27.0: resolution: {integrity: sha512-h0JYX+dO2Zr3abCQpS6/uFjujaOjA1DyDzGQ41+oFn9VW/ARiq9g5ln7qEP9+BTzDpOMyIfsfj4OvfgXAsMUSA==} + third-party-web@0.29.0: + resolution: {integrity: sha512-nBDSJw5B7Sl1YfsATG2XkW5qgUPODbJhXw++BKygi9w6O/NKS98/uY/nR/DxDq2axEjL6halHW1v+jhm/j1DBQ==} + through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} @@ -8905,11 +9361,11 @@ packages: title-case@2.1.1: resolution: {integrity: sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==} - tldts-core@7.0.17: - resolution: {integrity: sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==} + tldts-core@7.0.19: + resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} - tldts-icann@7.0.17: - resolution: {integrity: sha512-up4oFDoumyz2RscRxoYRxf+2OvIKUHjh7rUvuGWI0PZ/47k35sadoi2JyKR0AIfTw09qcfix8bUxXFQhY1QZIQ==} + tldts-icann@7.0.19: + resolution: {integrity: sha512-PZgda8E2cXMNa7QlBbiZh3vcS8UaPTDRIBmcGPDlujSMtQLrzjvikeJxzQSqWxn3muaMJ7BsC+aL464Yl2I6cA==} tmp@0.0.30: resolution: {integrity: sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==} @@ -9025,8 +9481,8 @@ packages: peerDependencies: typescript: 5.9.2 - tsx@4.20.6: - resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} hasBin: true @@ -9128,13 +9584,17 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.14.0: - resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} undici@5.29.0: resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} engines: {node: '>=14.0'} + undici@7.16.0: + resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} + engines: {node: '>=20.18.1'} + unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -9162,10 +9622,18 @@ packages: resolution: {integrity: sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==} engines: {node: ^18.17.0 || >=20.5.0} + unique-filename@5.0.0: + resolution: {integrity: sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==} + engines: {node: ^20.17.0 || >=22.9.0} + unique-slug@5.0.0: resolution: {integrity: sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==} engines: {node: ^18.17.0 || >=20.5.0} + unique-slug@6.0.0: + resolution: {integrity: sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==} + engines: {node: ^20.17.0 || >=22.9.0} + unique-string@2.0.0: resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} engines: {node: '>=8'} @@ -9201,8 +9669,8 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + update-browserslist-db@1.2.2: + resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -9293,8 +9761,8 @@ packages: vfile@3.0.1: resolution: {integrity: sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ==} - vite@7.1.10: - resolution: {integrity: sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==} + vite@7.2.2: + resolution: {integrity: sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -9366,8 +9834,8 @@ packages: web-vitals@4.2.4: resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} - webdriver-bidi-protocol@0.3.6: - resolution: {integrity: sha512-mlGndEOA9yK9YAbvtxaPTqdi/kaCWYYfwrZvGzcmkr/3lWM+tQj53BxtpVd6qbC6+E5OnHXgCcAhre6AkXzxjA==} + webdriver-bidi-protocol@0.3.9: + resolution: {integrity: sha512-uIYvlRQ0PwtZR1EzHlTMol1G0lAlmOe6wPykF9a77AK3bkpvZHzIVxRE2ThOx5vjy2zISe0zhwf5rzuUfbo1PQ==} webdriver-js-extender@2.1.0: resolution: {integrity: sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==} @@ -9445,8 +9913,8 @@ packages: whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - when-exit@2.1.4: - resolution: {integrity: sha512-4rnvd3A1t16PWzrBUcSDZqcAmsUIy4minDXT/CZ8F2mVDgd65i4Aalimgz1aQkRGU0iH5eT5+6Rx2TK8o443Pg==} + when-exit@2.1.5: + resolution: {integrity: sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==} which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} @@ -9486,6 +9954,11 @@ packages: engines: {node: ^18.17.0 || >=20.5.0} hasBin: true + which@6.0.0: + resolution: {integrity: sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + widest-line@3.1.0: resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} engines: {node: '>=8'} @@ -9501,8 +9974,8 @@ packages: resolution: {integrity: sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg==} engines: {node: '>= 0.10.0'} - winston@3.18.3: - resolution: {integrity: sha512-NoBZauFNNWENgsnC9YpgyYwOVrl2m58PpQ8lNHjV3kosGs7KJ7Npk9pCUE+WJlawVSe8mykWDKWFSVfs3QO9ww==} + winston@3.19.0: + resolution: {integrity: sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==} engines: {node: '>= 12.0.0'} word-wrap@1.2.5: @@ -9626,8 +10099,8 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - yaml@2.8.1: - resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} hasBin: true @@ -9686,144 +10159,147 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} - zod-to-json-schema@3.24.6: - resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} + zod-to-json-schema@3.25.0: + resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} peerDependencies: - zod: ^3.24.1 + zod: ^3.25 || ^4 zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.1.13: + resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} + zone.js@0.15.1: resolution: {integrity: sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==} - zx@8.8.4: - resolution: {integrity: sha512-44GcD+ZlM/v1OQtbwnSxLPcoE1ZEUICmR+RSbJZLAqfIixNLuMjLyh0DcS75OyfJ/sWYAwCWDmDvJ4hdnANAPQ==} + zx@8.8.5: + resolution: {integrity: sha512-SNgDF5L0gfN7FwVOdEFguY3orU5AkfFZm9B5YSHog/UDHv+lvmd82ZAsOenOkQixigwH2+yyH198AwNdKhj+RA==} engines: {node: '>= 12.17.0'} hasBin: true snapshots: - '@actions/core@1.11.1': + '@actions/core@2.0.1': dependencies: - '@actions/exec': 1.1.1 - '@actions/http-client': 2.2.3 + '@actions/exec': 2.0.0 + '@actions/http-client': 3.0.0 - '@actions/exec@1.1.1': + '@actions/exec@2.0.0': dependencies: - '@actions/io': 1.1.3 + '@actions/io': 2.0.0 - '@actions/http-client@2.2.3': + '@actions/http-client@3.0.0': dependencies: tunnel: 0.0.6 undici: 5.29.0 - '@actions/io@1.1.3': {} + '@actions/io@2.0.0': {} - '@algolia/abtesting@1.6.0': + '@algolia/abtesting@1.6.1': dependencies: - '@algolia/client-common': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + '@algolia/client-common': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 - '@algolia/client-abtesting@5.40.0': + '@algolia/client-abtesting@5.40.1': dependencies: - '@algolia/client-common': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + '@algolia/client-common': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 - '@algolia/client-analytics@5.40.0': + '@algolia/client-analytics@5.40.1': dependencies: - '@algolia/client-common': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + '@algolia/client-common': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 - '@algolia/client-common@5.40.0': {} + '@algolia/client-common@5.40.1': {} - '@algolia/client-insights@5.40.0': + '@algolia/client-insights@5.40.1': dependencies: - '@algolia/client-common': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + '@algolia/client-common': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 - '@algolia/client-personalization@5.40.0': + '@algolia/client-personalization@5.40.1': dependencies: - '@algolia/client-common': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + '@algolia/client-common': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 - '@algolia/client-query-suggestions@5.40.0': + '@algolia/client-query-suggestions@5.40.1': dependencies: - '@algolia/client-common': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + '@algolia/client-common': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 - '@algolia/client-search@5.40.0': + '@algolia/client-search@5.40.1': dependencies: - '@algolia/client-common': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + '@algolia/client-common': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 - '@algolia/ingestion@1.40.0': + '@algolia/ingestion@1.40.1': dependencies: - '@algolia/client-common': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + '@algolia/client-common': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 - '@algolia/monitoring@1.40.0': + '@algolia/monitoring@1.40.1': dependencies: - '@algolia/client-common': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + '@algolia/client-common': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 - '@algolia/recommend@5.40.0': + '@algolia/recommend@5.40.1': dependencies: - '@algolia/client-common': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + '@algolia/client-common': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 - '@algolia/requester-browser-xhr@5.40.0': + '@algolia/requester-browser-xhr@5.40.1': dependencies: - '@algolia/client-common': 5.40.0 + '@algolia/client-common': 5.40.1 - '@algolia/requester-fetch@5.40.0': + '@algolia/requester-fetch@5.40.1': dependencies: - '@algolia/client-common': 5.40.0 + '@algolia/client-common': 5.40.1 - '@algolia/requester-node-http@5.40.0': + '@algolia/requester-node-http@5.40.1': dependencies: - '@algolia/client-common': 5.40.0 + '@algolia/client-common': 5.40.1 '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@angular-devkit/architect@0.2100.0-next.8(chokidar@4.0.3)': + '@angular-devkit/architect@0.2100.3(chokidar@4.0.3)': dependencies: - '@angular-devkit/core': 21.0.0-next.8(chokidar@4.0.3) + '@angular-devkit/core': 21.0.3(chokidar@4.0.3) rxjs: 7.8.2 transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@21.0.0-next.8(cfe8a97e2176695474f8a07e88e10fe8)': + '@angular-devkit/build-angular@21.0.3(a4728fe13469fa501a2f42d499133d45)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2100.0-next.8(chokidar@4.0.3) - '@angular-devkit/build-webpack': 0.2100.0-next.8(chokidar@4.0.3)(webpack-dev-server@5.2.2(bufferutil@4.0.9)(webpack@5.102.1(esbuild@0.25.10)))(webpack@5.102.1(esbuild@0.25.10)) - '@angular-devkit/core': 21.0.0-next.8(chokidar@4.0.3) - '@angular/build': 21.0.0-next.8(b79efbffc17c55a8c1fe4809ca38affa) - '@angular/compiler-cli': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2) + '@angular-devkit/architect': 0.2100.3(chokidar@4.0.3) + '@angular-devkit/build-webpack': 0.2100.3(chokidar@4.0.3)(webpack-dev-server@5.2.2(bufferutil@4.0.9)(webpack@5.102.1(esbuild@0.26.0)))(webpack@5.102.1(esbuild@0.26.0)) + '@angular-devkit/core': 21.0.3(chokidar@4.0.3) + '@angular/build': 21.0.3(ae0eb9cd6117e067476db2d120b81ee6) + '@angular/compiler-cli': 21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2) '@babel/core': 7.28.4 '@babel/generator': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 @@ -9834,53 +10310,53 @@ snapshots: '@babel/preset-env': 7.28.3(@babel/core@7.28.4) '@babel/runtime': 7.28.4 '@discoveryjs/json-ext': 0.6.3 - '@ngtools/webpack': 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(typescript@5.9.2)(webpack@5.102.1(esbuild@0.25.10)) + '@ngtools/webpack': 21.0.3(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(typescript@5.9.2)(webpack@5.102.1(esbuild@0.26.0)) ansi-colors: 4.1.3 autoprefixer: 10.4.21(postcss@8.5.6) - babel-loader: 10.0.0(@babel/core@7.28.4)(webpack@5.102.1(esbuild@0.25.10)) - browserslist: 4.26.3 - copy-webpack-plugin: 13.0.1(webpack@5.102.1(esbuild@0.25.10)) - css-loader: 7.1.2(webpack@5.102.1(esbuild@0.25.10)) - esbuild-wasm: 0.25.10 + babel-loader: 10.0.0(@babel/core@7.28.4)(webpack@5.102.1(esbuild@0.26.0)) + browserslist: 4.28.1 + copy-webpack-plugin: 13.0.1(webpack@5.102.1(esbuild@0.26.0)) + css-loader: 7.1.2(webpack@5.102.1(esbuild@0.26.0)) + esbuild-wasm: 0.26.0 http-proxy-middleware: 3.0.5 istanbul-lib-instrument: 6.0.3 jsonc-parser: 3.3.1 karma-source-map-support: 1.4.0 less: 4.4.2 - less-loader: 12.3.0(less@4.4.2)(webpack@5.102.1(esbuild@0.25.10)) - license-webpack-plugin: 4.0.2(webpack@5.102.1(esbuild@0.25.10)) + less-loader: 12.3.0(less@4.4.2)(webpack@5.102.1(esbuild@0.26.0)) + license-webpack-plugin: 4.0.2(webpack@5.102.1(esbuild@0.26.0)) loader-utils: 3.3.1 - mini-css-extract-plugin: 2.9.4(webpack@5.102.1(esbuild@0.25.10)) + mini-css-extract-plugin: 2.9.4(webpack@5.102.1(esbuild@0.26.0)) open: 10.2.0 ora: 9.0.0 picomatch: 4.0.3 piscina: 5.1.3 postcss: 8.5.6 - postcss-loader: 8.2.0(postcss@8.5.6)(typescript@5.9.2)(webpack@5.102.1(esbuild@0.25.10)) + postcss-loader: 8.2.0(postcss@8.5.6)(typescript@5.9.2)(webpack@5.102.1(esbuild@0.26.0)) resolve-url-loader: 5.0.0 rxjs: 7.8.2 sass: 1.93.2 - sass-loader: 16.0.5(sass@1.93.2)(webpack@5.102.1(esbuild@0.25.10)) + sass-loader: 16.0.5(sass@1.93.2)(webpack@5.102.1(esbuild@0.26.0)) semver: 7.7.3 - source-map-loader: 5.0.0(webpack@5.102.1(esbuild@0.25.10)) + source-map-loader: 5.0.0(webpack@5.102.1(esbuild@0.26.0)) source-map-support: 0.5.21 terser: 5.44.0 tinyglobby: 0.2.15 tree-kill: 1.2.2 tslib: 2.8.1 typescript: 5.9.2 - webpack: 5.102.1(esbuild@0.25.10) - webpack-dev-middleware: 7.4.5(webpack@5.102.1(esbuild@0.25.10)) - webpack-dev-server: 5.2.2(bufferutil@4.0.9)(webpack@5.102.1(esbuild@0.25.10)) + webpack: 5.102.1(esbuild@0.26.0) + webpack-dev-middleware: 7.4.5(webpack@5.102.1(esbuild@0.26.0)) + webpack-dev-server: 5.2.2(bufferutil@4.0.9)(webpack@5.102.1(esbuild@0.26.0)) webpack-merge: 6.0.1 - webpack-subresource-integrity: 5.1.0(webpack@5.102.1(esbuild@0.25.10)) + webpack-subresource-integrity: 5.1.0(webpack@5.102.1(esbuild@0.26.0)) optionalDependencies: - '@angular/core': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) - '@angular/localize': 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/compiler@21.0.0-next.8) - '@angular/platform-browser': 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)) - '@angular/platform-server': 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/compiler@21.0.0-next.8)(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) - '@angular/ssr': 21.0.0-next.8(97a956334e4483b817e98b9a94c98525) - esbuild: 0.25.10 + '@angular/core': 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) + '@angular/localize': 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/compiler@21.0.5) + '@angular/platform-browser': 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)) + '@angular/platform-server': 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/compiler@21.0.5)(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) + '@angular/ssr': 21.0.3(29820ad2842b06a07ed5fa27341aa1ea) + esbuild: 0.26.0 karma: 6.4.4(bufferutil@4.0.9) protractor: 7.0.0 transitivePeerDependencies: @@ -9906,16 +10382,16 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-webpack@0.2100.0-next.8(chokidar@4.0.3)(webpack-dev-server@5.2.2(bufferutil@4.0.9)(webpack@5.102.1(esbuild@0.25.10)))(webpack@5.102.1(esbuild@0.25.10))': + '@angular-devkit/build-webpack@0.2100.3(chokidar@4.0.3)(webpack-dev-server@5.2.2(bufferutil@4.0.9)(webpack@5.102.1(esbuild@0.26.0)))(webpack@5.102.1(esbuild@0.26.0))': dependencies: - '@angular-devkit/architect': 0.2100.0-next.8(chokidar@4.0.3) + '@angular-devkit/architect': 0.2100.3(chokidar@4.0.3) rxjs: 7.8.2 - webpack: 5.102.1(esbuild@0.25.10) - webpack-dev-server: 5.2.2(bufferutil@4.0.9)(webpack@5.102.1(esbuild@0.25.10)) + webpack: 5.102.1(esbuild@0.26.0) + webpack-dev-server: 5.2.2(bufferutil@4.0.9)(webpack@5.102.1(esbuild@0.26.0)) transitivePeerDependencies: - chokidar - '@angular-devkit/core@21.0.0-next.8(chokidar@4.0.3)': + '@angular-devkit/core@21.0.3(chokidar@4.0.3)': dependencies: ajv: 8.17.1 ajv-formats: 3.0.1 @@ -9926,9 +10402,9 @@ snapshots: optionalDependencies: chokidar: 4.0.3 - '@angular-devkit/schematics@21.0.0-next.8(chokidar@4.0.3)': + '@angular-devkit/schematics@21.0.3(chokidar@4.0.3)': dependencies: - '@angular-devkit/core': 21.0.0-next.8(chokidar@4.0.3) + '@angular-devkit/core': 21.0.3(chokidar@4.0.3) jsonc-parser: 3.3.1 magic-string: 0.30.19 ora: 9.0.0 @@ -9936,44 +10412,45 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular/build@21.0.0-next.8(b79efbffc17c55a8c1fe4809ca38affa)': + '@angular/build@21.0.3(ae0eb9cd6117e067476db2d120b81ee6)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2100.0-next.8(chokidar@4.0.3) - '@angular/compiler': 21.0.0-next.8 - '@angular/compiler-cli': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2) + '@angular-devkit/architect': 0.2100.3(chokidar@4.0.3) + '@angular/compiler': 21.0.5 + '@angular/compiler-cli': 21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2) '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 5.1.19(@types/node@22.18.8) - '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.1.10(@types/node@22.18.8)(jiti@2.6.1)(less@4.4.2)(sass@1.93.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@inquirer/confirm': 5.1.19(@types/node@22.19.2) + '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.2.2(@types/node@22.19.2)(jiti@2.6.1)(less@4.4.2)(sass@1.93.2)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.2)) beasties: 0.3.5 - browserslist: 4.26.3 - esbuild: 0.25.10 + browserslist: 4.28.1 + esbuild: 0.26.0 https-proxy-agent: 7.0.6(supports-color@10.2.2) istanbul-lib-instrument: 6.0.3 jsonc-parser: 3.3.1 - listr2: 9.0.4 + listr2: 9.0.5 magic-string: 0.30.19 mrmime: 2.0.1 parse5-html-rewriting-stream: 8.0.0 picomatch: 4.0.3 piscina: 5.1.3 - rolldown: 1.0.0-beta.43 + rolldown: 1.0.0-beta.47 sass: 1.93.2 semver: 7.7.3 source-map-support: 0.5.21 tinyglobby: 0.2.15 tslib: 2.8.1 typescript: 5.9.2 - vite: 7.1.10(@types/node@22.18.8)(jiti@2.6.1)(less@4.4.2)(sass@1.93.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + undici: 7.16.0 + vite: 7.2.2(@types/node@22.19.2)(jiti@2.6.1)(less@4.4.2)(sass@1.93.2)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.2) watchpack: 2.4.4 optionalDependencies: - '@angular/core': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) - '@angular/localize': 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/compiler@21.0.0-next.8) - '@angular/platform-browser': 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)) - '@angular/platform-server': 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/compiler@21.0.0-next.8)(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) - '@angular/ssr': 21.0.0-next.8(97a956334e4483b817e98b9a94c98525) + '@angular/core': 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) + '@angular/localize': 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/compiler@21.0.5) + '@angular/platform-browser': 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)) + '@angular/platform-server': 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/compiler@21.0.5)(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) + '@angular/ssr': 21.0.3(29820ad2842b06a07ed5fa27341aa1ea) karma: 6.4.4(bufferutil@4.0.9) less: 4.4.2 lmdb: 3.4.3 @@ -9991,44 +10468,46 @@ snapshots: - tsx - yaml - '@angular/cli@21.0.0-next.8(@types/node@22.18.8)(chokidar@4.0.3)': + '@angular/cli@21.0.3(@types/node@22.19.2)(chokidar@4.0.3)': dependencies: - '@angular-devkit/architect': 0.2100.0-next.8(chokidar@4.0.3) - '@angular-devkit/core': 21.0.0-next.8(chokidar@4.0.3) - '@angular-devkit/schematics': 21.0.0-next.8(chokidar@4.0.3) - '@inquirer/prompts': 7.9.0(@types/node@22.18.8) - '@listr2/prompt-adapter-inquirer': 3.0.4(@inquirer/prompts@7.9.0(@types/node@22.18.8))(@types/node@22.18.8)(listr2@9.0.4) - '@modelcontextprotocol/sdk': 1.20.0 - '@schematics/angular': 21.0.0-next.8(chokidar@4.0.3) + '@angular-devkit/architect': 0.2100.3(chokidar@4.0.3) + '@angular-devkit/core': 21.0.3(chokidar@4.0.3) + '@angular-devkit/schematics': 21.0.3(chokidar@4.0.3) + '@inquirer/prompts': 7.9.0(@types/node@22.19.2) + '@listr2/prompt-adapter-inquirer': 3.0.5(@inquirer/prompts@7.9.0(@types/node@22.19.2))(@types/node@22.19.2)(listr2@9.0.5) + '@modelcontextprotocol/sdk': 1.24.0 + '@schematics/angular': 21.0.3(chokidar@4.0.3) '@yarnpkg/lockfile': 1.1.0 - algoliasearch: 5.40.0 + algoliasearch: 5.40.1 ini: 5.0.0 jsonc-parser: 3.3.1 - listr2: 9.0.4 + listr2: 9.0.5 npm-package-arg: 13.0.1 pacote: 21.0.3 - resolve: 1.22.10 + parse5-html-rewriting-stream: 8.0.0 + resolve: 1.22.11 semver: 7.7.3 yargs: 18.0.0 - zod: 3.25.76 + zod: 4.1.13 transitivePeerDependencies: + - '@cfworker/json-schema' - '@types/node' - chokidar - supports-color - '@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7)': + '@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7)': dependencies: - '@angular/core': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) - '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2)) + '@angular/core': 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) + '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2)) rxjs: 6.6.7 tslib: 2.8.1 transitivePeerDependencies: - '@angular/compiler-cli' - supports-color - '@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2)': + '@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2)': dependencies: - '@angular/compiler': 21.0.0-next.8 + '@angular/compiler': 21.0.5 '@babel/core': 7.28.4 '@jridgewell/sourcemap-codec': 1.5.5 chokidar: 4.0.3 @@ -10042,128 +10521,127 @@ snapshots: transitivePeerDependencies: - supports-color - '@angular/compiler@21.0.0-next.8': + '@angular/compiler@21.0.5': dependencies: tslib: 2.8.1 - '@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)': + '@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)': dependencies: rxjs: 6.6.7 tslib: 2.8.1 optionalDependencies: - '@angular/compiler': 21.0.0-next.8 + '@angular/compiler': 21.0.5 zone.js: 0.15.1 - '@angular/forms@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7)': + '@angular/forms@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7)': dependencies: - '@angular/common': 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) - '@angular/core': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) - '@angular/platform-browser': 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)) - '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2)) + '@angular/common': 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) + '@angular/core': 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) + '@angular/platform-browser': 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)) + '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2)) rxjs: 6.6.7 tslib: 2.8.1 transitivePeerDependencies: - '@angular/compiler-cli' - supports-color - '@angular/localize@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/compiler@21.0.0-next.8)': + '@angular/localize@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/compiler@21.0.5)': dependencies: - '@angular/compiler': 21.0.0-next.8 - '@angular/compiler-cli': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2) + '@angular/compiler': 21.0.5 + '@angular/compiler-cli': 21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2) '@babel/core': 7.28.4 - '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2)) + '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2)) '@types/babel__core': 7.20.5 tinyglobby: 0.2.15 yargs: 18.0.0 transitivePeerDependencies: - supports-color - '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/3c4fd6f54f2c67ce5b9f1a32ce90e36ba2fada4e(@modelcontextprotocol/sdk@1.20.0)': + '@angular/ng-dev@https://codeload.github.com/angular/dev-infra-private-ng-dev-builds/tar.gz/24c98502339594196a800db33dd4294e359ea952(@modelcontextprotocol/sdk@1.24.3)': dependencies: - '@actions/core': 1.11.1 + '@actions/core': 2.0.1 '@google-cloud/spanner': 8.0.0(supports-color@10.2.2) - '@google/genai': 1.25.0(@modelcontextprotocol/sdk@1.20.0)(bufferutil@4.0.9)(encoding@0.1.13)(supports-color@10.2.2)(utf-8-validate@6.0.5) - '@inquirer/prompts': 7.9.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) - '@octokit/auth-app': 8.1.1 - '@octokit/core': 7.0.5 - '@octokit/graphql': 9.0.2 - '@octokit/graphql-schema': 15.26.0 - '@octokit/openapi-types': 26.0.0 - '@octokit/plugin-paginate-rest': 13.2.0(@octokit/core@7.0.5) - '@octokit/plugin-rest-endpoint-methods': 16.1.0(@octokit/core@7.0.5) - '@octokit/request-error': 7.0.1 - '@octokit/rest': 22.0.0 - '@octokit/types': 15.0.0 - '@pnpm/dependency-path': 1001.1.2 + '@google/genai': 1.33.0(@modelcontextprotocol/sdk@1.24.3)(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5) + '@inquirer/prompts': 8.1.0(@types/node@24.10.4) + '@inquirer/type': 4.0.2(@types/node@24.10.4) + '@octokit/auth-app': 8.1.2 + '@octokit/core': 7.0.6 + '@octokit/graphql': 9.0.3 + '@octokit/graphql-schema': 15.26.1 + '@octokit/openapi-types': 27.0.0 + '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6) + '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6) + '@octokit/request-error': 7.1.0 + '@octokit/rest': 22.0.1 + '@octokit/types': 16.0.0 + '@pnpm/dependency-path': 1001.1.8 '@types/cli-progress': 3.11.6 '@types/ejs': 3.1.5 '@types/events': 3.0.3 '@types/folder-hash': 4.0.4 - '@types/git-raw-commits': 5.0.0 - '@types/jasmine': 5.1.12 - '@types/node': 24.8.1 + '@types/git-raw-commits': 5.0.1 + '@types/jasmine': 5.1.13 + '@types/node': 24.10.4 '@types/semver': 7.7.1 '@types/which': 3.0.4 - '@types/yargs': 17.0.33 + '@types/yargs': 17.0.35 '@types/yarnpkg__lockfile': 1.1.9 '@yarnpkg/lockfile': 1.1.0 bufferutil: 4.0.9 - chalk: 5.6.2 cli-progress: 3.12.0 conventional-commits-filter: 5.0.0 - conventional-commits-parser: 6.2.0 + conventional-commits-parser: 6.2.1 ejs: 3.1.10 encoding: 0.1.13 fast-glob: 3.3.3 - firebase: 12.4.0 + firebase: 12.7.0 folder-hash: 4.1.1(supports-color@10.2.2) - git-raw-commits: 5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0) - jasmine: 5.12.0 - jasmine-core: 5.12.0 + git-raw-commits: 5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.1) + jasmine: 5.13.0 + jasmine-core: 5.13.0 jasmine-reporters: 2.5.2 jsonc-parser: 3.3.1 - minimatch: 10.0.3 + minimatch: 10.1.1 multimatch: 7.0.0 nock: 14.0.10 semver: 7.7.3 supports-color: 10.2.2 - tsx: 4.20.6 + tsx: 4.21.0 typed-graphqlify: 3.1.6 typescript: 5.9.2 utf-8-validate: 6.0.5 - which: 5.0.0 - yaml: 2.8.1 + which: 6.0.0 + yaml: 2.8.2 yargs: 18.0.0 transitivePeerDependencies: - '@modelcontextprotocol/sdk' - '@react-native-async-storage/async-storage' - '@angular/platform-browser-dynamic@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler@21.0.0-next.8)(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))': + '@angular/platform-browser-dynamic@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler@21.0.5)(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))': dependencies: - '@angular/common': 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) - '@angular/compiler': 21.0.0-next.8 - '@angular/core': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) - '@angular/platform-browser': 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)) + '@angular/common': 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) + '@angular/compiler': 21.0.5 + '@angular/core': 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) + '@angular/platform-browser': 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)) tslib: 2.8.1 - '@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))': + '@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))': dependencies: - '@angular/common': 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) - '@angular/core': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) - '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2)) + '@angular/common': 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) + '@angular/core': 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) + '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2)) tslib: 2.8.1 transitivePeerDependencies: - '@angular/compiler-cli' - supports-color - '@angular/platform-server@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/compiler@21.0.0-next.8)(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7)': + '@angular/platform-server@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/compiler@21.0.5)(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7)': dependencies: - '@angular/common': 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) - '@angular/compiler': 21.0.0-next.8 - '@angular/core': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) - '@angular/platform-browser': 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)) - '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2)) + '@angular/common': 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) + '@angular/compiler': 21.0.5 + '@angular/core': 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) + '@angular/platform-browser': 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)) + '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2)) rxjs: 6.6.7 tslib: 2.8.1 xhr2: 0.2.1 @@ -10171,42 +10649,42 @@ snapshots: - '@angular/compiler-cli' - supports-color - '@angular/router@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7)': + '@angular/router@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7)': dependencies: - '@angular/common': 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) - '@angular/core': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) - '@angular/platform-browser': 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)) - '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2)) + '@angular/common': 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) + '@angular/core': 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) + '@angular/platform-browser': 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)) + '@nginfra/angular-linking': 1.0.9(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2)) rxjs: 6.6.7 tslib: 2.8.1 transitivePeerDependencies: - '@angular/compiler-cli' - supports-color - '@angular/ssr@21.0.0-next.8(97a956334e4483b817e98b9a94c98525)': + '@angular/ssr@21.0.3(29820ad2842b06a07ed5fa27341aa1ea)': dependencies: - '@angular/common': 21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) - '@angular/core': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1) - '@angular/router': 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) + '@angular/common': 21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7) + '@angular/core': 21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1) + '@angular/router': 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) tslib: 2.8.1 optionalDependencies: - '@angular/platform-server': 21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/compiler@21.0.0-next.8)(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.0-next.8(@angular/common@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(@angular/core@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) + '@angular/platform-server': 21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/compiler@21.0.5)(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(@angular/platform-browser@21.0.5(@angular/common@21.0.5(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1))(rxjs@6.6.7))(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(@angular/core@21.0.5(@angular/compiler@21.0.5)(rxjs@6.6.7)(zone.js@0.15.1)))(rxjs@6.6.7) '@apidevtools/json-schema-ref-parser@9.1.2': dependencies: '@jsdevtools/ono': 7.1.3 '@types/json-schema': 7.0.15 call-me-maybe: 1.0.2 - js-yaml: 4.1.0 + js-yaml: 4.1.1 - '@apphosting/build@0.1.6(@types/node@22.18.8)(typescript@5.9.2)': + '@apphosting/build@0.1.7(@types/node@22.19.2)(typescript@5.9.2)': dependencies: - '@apphosting/common': 0.0.8 + '@apphosting/common': 0.0.9 '@npmcli/promise-spawn': 3.0.0 colorette: 2.0.20 commander: 11.1.0 npm-pick-manifest: 9.1.0 - ts-node: 10.9.2(@types/node@22.18.8)(typescript@5.9.2) + ts-node: 10.9.2(@types/node@22.19.2)(typescript@5.9.2) transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -10215,26 +10693,28 @@ snapshots: '@apphosting/common@0.0.8': {} + '@apphosting/common@0.0.9': {} + '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.4': {} + '@babel/compat-data@7.28.5': {} '@babel/core@7.26.10': dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.26.10) '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 convert-source-map: 2.0.0 debug: 4.4.3(supports-color@10.2.2) gensync: 1.0.0-beta.2 @@ -10246,14 +10726,34 @@ snapshots: '@babel/core@7.28.4': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3(supports-color@10.2.2) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3(supports-color@10.2.2) @@ -10265,38 +10765,46 @@ snapshots: '@babel/generator@7.28.3': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.26.3 + browserslist: 4.28.1 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.4)': + '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.4)': + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 @@ -10310,23 +10818,23 @@ snapshots: '@babel/helper-plugin-utils': 7.27.1 debug: 4.4.3(supports-color@10.2.2) lodash.debounce: 4.0.8 - resolve: 1.22.10 + resolve: 1.22.11 transitivePeerDependencies: - supports-color '@babel/helper-globals@7.28.0': {} - '@babel/helper-member-expression-to-functions@7.27.1': + '@babel/helper-member-expression-to-functions@7.28.5': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color @@ -10334,8 +10842,8 @@ snapshots: dependencies: '@babel/core': 7.26.10 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10343,14 +10851,23 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-plugin-utils@7.27.1': {} @@ -10359,58 +10876,58 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-split-export-declaration@7.24.7': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-option@7.27.1': {} '@babel/helper-wrap-function@7.28.3': dependencies: '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helpers@7.28.4': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 - '@babel/parser@7.28.4': + '@babel/parser@7.28.5': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10429,7 +10946,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.4) transitivePeerDependencies: - supports-color @@ -10437,7 +10954,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10458,7 +10975,7 @@ snapshots: '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.4)': @@ -10471,7 +10988,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10489,7 +11006,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-block-scoping@7.28.4(@babel/core@7.28.4)': + '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -10497,7 +11014,7 @@ snapshots: '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -10505,7 +11022,7 @@ snapshots: '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -10518,7 +11035,7 @@ snapshots: '@babel/helper-globals': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10528,18 +11045,18 @@ snapshots: '@babel/helper-plugin-utils': 7.27.1 '@babel/template': 7.27.2 - '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.4)': + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.4)': @@ -10550,7 +11067,7 @@ snapshots: '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.4)': @@ -10562,11 +11079,11 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.4) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -10589,7 +11106,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10603,7 +11120,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -10629,13 +11146,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10650,7 +11167,7 @@ snapshots: '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.4)': @@ -10673,9 +11190,9 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10692,7 +11209,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -10708,7 +11225,7 @@ snapshots: '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -10717,7 +11234,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -10735,7 +11252,7 @@ snapshots: '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.4)': @@ -10791,29 +11308,29 @@ snapshots: '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/preset-env@7.28.3(@babel/core@7.28.4)': dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.4) '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.4) '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.4) '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.4) @@ -10826,28 +11343,28 @@ snapshots: '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.4) '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-block-scoping': 7.28.4(@babel/core@7.28.4) + '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.4) '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.4) '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.4) - '@babel/plugin-transform-exponentiation-operator': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-modules-systemjs': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.4) @@ -10856,7 +11373,7 @@ snapshots: '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.4) '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.4) @@ -10877,7 +11394,7 @@ snapshots: babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.4) babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.4) babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.4) - core-js-compat: 3.45.1 + core-js-compat: 3.47.0 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -10886,7 +11403,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 esutils: 2.0.3 '@babel/runtime@7.28.4': {} @@ -10894,25 +11411,25 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 - '@babel/traverse@7.28.4': + '@babel/traverse@7.28.5': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/types@7.28.4': + '@babel/types@7.28.5': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@bazel/bazelisk@1.26.0': {} @@ -10926,13 +11443,13 @@ snapshots: '@colors/colors@1.6.0': {} - '@conventional-changelog/git-client@1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0)': + '@conventional-changelog/git-client@1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.1)': dependencies: '@types/semver': 7.7.1 semver: 7.7.3 optionalDependencies: conventional-commits-filter: 5.0.0 - conventional-commits-parser: 6.2.0 + conventional-commits-parser: 6.2.1 '@cspotcode/source-map-support@0.8.1': dependencies: @@ -10950,21 +11467,21 @@ snapshots: '@discoveryjs/json-ext@0.6.3': {} - '@electric-sql/pglite-tools@0.2.15(@electric-sql/pglite@0.3.10)': + '@electric-sql/pglite-tools@0.2.19(@electric-sql/pglite@0.3.14)': dependencies: - '@electric-sql/pglite': 0.3.10 + '@electric-sql/pglite': 0.3.14 '@electric-sql/pglite@0.2.17': {} - '@electric-sql/pglite@0.3.10': {} + '@electric-sql/pglite@0.3.14': {} - '@emnapi/core@1.5.0': + '@emnapi/core@1.7.1': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.5.0': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -10974,89 +11491,245 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.10': + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/aix-ppc64@0.26.0': + optional: true + + '@esbuild/aix-ppc64@0.27.1': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.26.0': + optional: true + + '@esbuild/android-arm64@0.27.1': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-arm@0.26.0': + optional: true + + '@esbuild/android-arm@0.27.1': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/android-x64@0.26.0': + optional: true + + '@esbuild/android-x64@0.27.1': + optional: true + + '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/android-arm64@0.25.10': + '@esbuild/darwin-arm64@0.26.0': optional: true - '@esbuild/android-arm@0.25.10': + '@esbuild/darwin-arm64@0.27.1': optional: true - '@esbuild/android-x64@0.25.10': + '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.25.10': + '@esbuild/darwin-x64@0.26.0': optional: true - '@esbuild/darwin-x64@0.25.10': + '@esbuild/darwin-x64@0.27.1': optional: true - '@esbuild/freebsd-arm64@0.25.10': + '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.25.10': + '@esbuild/freebsd-arm64@0.26.0': optional: true - '@esbuild/linux-arm64@0.25.10': + '@esbuild/freebsd-arm64@0.27.1': optional: true - '@esbuild/linux-arm@0.25.10': + '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/linux-ia32@0.25.10': + '@esbuild/freebsd-x64@0.26.0': optional: true - '@esbuild/linux-loong64@0.25.10': + '@esbuild/freebsd-x64@0.27.1': optional: true - '@esbuild/linux-mips64el@0.25.10': + '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.25.10': + '@esbuild/linux-arm64@0.26.0': optional: true - '@esbuild/linux-riscv64@0.25.10': + '@esbuild/linux-arm64@0.27.1': optional: true - '@esbuild/linux-s390x@0.25.10': + '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-x64@0.25.10': + '@esbuild/linux-arm@0.26.0': optional: true - '@esbuild/netbsd-arm64@0.25.10': + '@esbuild/linux-arm@0.27.1': optional: true - '@esbuild/netbsd-x64@0.25.10': + '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.25.10': + '@esbuild/linux-ia32@0.26.0': optional: true - '@esbuild/openbsd-x64@0.25.10': + '@esbuild/linux-ia32@0.27.1': optional: true - '@esbuild/openharmony-arm64@0.25.10': + '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/sunos-x64@0.25.10': + '@esbuild/linux-loong64@0.26.0': optional: true - '@esbuild/win32-arm64@0.25.10': + '@esbuild/linux-loong64@0.27.1': optional: true - '@esbuild/win32-ia32@0.25.10': + '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/win32-x64@0.25.10': + '@esbuild/linux-mips64el@0.26.0': + optional: true + + '@esbuild/linux-mips64el@0.27.1': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.26.0': + optional: true + + '@esbuild/linux-ppc64@0.27.1': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.26.0': + optional: true + + '@esbuild/linux-riscv64@0.27.1': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.26.0': + optional: true + + '@esbuild/linux-s390x@0.27.1': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/linux-x64@0.26.0': + optional: true + + '@esbuild/linux-x64@0.27.1': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.26.0': + optional: true + + '@esbuild/netbsd-arm64@0.27.1': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.26.0': + optional: true + + '@esbuild/netbsd-x64@0.27.1': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.26.0': + optional: true + + '@esbuild/openbsd-arm64@0.27.1': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.26.0': + optional: true + + '@esbuild/openbsd-x64@0.27.1': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.26.0': + optional: true + + '@esbuild/openharmony-arm64@0.27.1': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.26.0': + optional: true + + '@esbuild/sunos-x64@0.27.1': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.26.0': + optional: true + + '@esbuild/win32-arm64@0.27.1': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.26.0': + optional: true + + '@esbuild/win32-ia32@0.27.1': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@esbuild/win32-x64@0.26.0': + optional: true + + '@esbuild/win32-x64@0.27.1': optional: true '@fastify/busboy@2.1.1': {} - '@firebase/ai@2.4.0(@firebase/app-types@0.9.3)(@firebase/app@0.14.4)': + '@firebase/ai@2.6.1(@firebase/app-types@0.9.3)(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/app-check-interop-types': 0.3.3 '@firebase/app-types': 0.9.3 '@firebase/component': 0.7.0 @@ -11064,11 +11737,11 @@ snapshots: '@firebase/util': 1.13.0 tslib: 2.8.1 - '@firebase/analytics-compat@0.2.25(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4)': + '@firebase/analytics-compat@0.2.25(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6)': dependencies: - '@firebase/analytics': 0.10.19(@firebase/app@0.14.4) + '@firebase/analytics': 0.10.19(@firebase/app@0.14.6) '@firebase/analytics-types': 0.8.3 - '@firebase/app-compat': 0.5.4 + '@firebase/app-compat': 0.5.6 '@firebase/component': 0.7.0 '@firebase/util': 1.13.0 tslib: 2.8.1 @@ -11077,20 +11750,20 @@ snapshots: '@firebase/analytics-types@0.8.3': {} - '@firebase/analytics@0.10.19(@firebase/app@0.14.4)': + '@firebase/analytics@0.10.19(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/component': 0.7.0 - '@firebase/installations': 0.6.19(@firebase/app@0.14.4) + '@firebase/installations': 0.6.19(@firebase/app@0.14.6) '@firebase/logger': 0.5.0 '@firebase/util': 1.13.0 tslib: 2.8.1 - '@firebase/app-check-compat@0.4.0(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4)': + '@firebase/app-check-compat@0.4.0(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6)': dependencies: - '@firebase/app-check': 0.11.0(@firebase/app@0.14.4) + '@firebase/app-check': 0.11.0(@firebase/app@0.14.6) '@firebase/app-check-types': 0.5.3 - '@firebase/app-compat': 0.5.4 + '@firebase/app-compat': 0.5.6 '@firebase/component': 0.7.0 '@firebase/logger': 0.5.0 '@firebase/util': 1.13.0 @@ -11102,17 +11775,17 @@ snapshots: '@firebase/app-check-types@0.5.3': {} - '@firebase/app-check@0.11.0(@firebase/app@0.14.4)': + '@firebase/app-check@0.11.0(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/component': 0.7.0 '@firebase/logger': 0.5.0 '@firebase/util': 1.13.0 tslib: 2.8.1 - '@firebase/app-compat@0.5.4': + '@firebase/app-compat@0.5.6': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/component': 0.7.0 '@firebase/logger': 0.5.0 '@firebase/util': 1.13.0 @@ -11120,7 +11793,7 @@ snapshots: '@firebase/app-types@0.9.3': {} - '@firebase/app@0.14.4': + '@firebase/app@0.14.6': dependencies: '@firebase/component': 0.7.0 '@firebase/logger': 0.5.0 @@ -11128,10 +11801,10 @@ snapshots: idb: 7.1.1 tslib: 2.8.1 - '@firebase/auth-compat@0.6.0(@firebase/app-compat@0.5.4)(@firebase/app-types@0.9.3)(@firebase/app@0.14.4)': + '@firebase/auth-compat@0.6.2(@firebase/app-compat@0.5.6)(@firebase/app-types@0.9.3)(@firebase/app@0.14.6)': dependencies: - '@firebase/app-compat': 0.5.4 - '@firebase/auth': 1.11.0(@firebase/app@0.14.4) + '@firebase/app-compat': 0.5.6 + '@firebase/auth': 1.12.0(@firebase/app@0.14.6) '@firebase/auth-types': 0.13.0(@firebase/app-types@0.9.3)(@firebase/util@1.13.0) '@firebase/component': 0.7.0 '@firebase/util': 1.13.0 @@ -11148,9 +11821,9 @@ snapshots: '@firebase/app-types': 0.9.3 '@firebase/util': 1.13.0 - '@firebase/auth@1.11.0(@firebase/app@0.14.4)': + '@firebase/auth@1.12.0(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/component': 0.7.0 '@firebase/logger': 0.5.0 '@firebase/util': 1.13.0 @@ -11161,9 +11834,9 @@ snapshots: '@firebase/util': 1.13.0 tslib: 2.8.1 - '@firebase/data-connect@0.3.11(@firebase/app@0.14.4)': + '@firebase/data-connect@0.3.12(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/auth-interop-types': 0.2.4 '@firebase/component': 0.7.0 '@firebase/logger': 0.5.0 @@ -11194,11 +11867,11 @@ snapshots: faye-websocket: 0.11.4 tslib: 2.8.1 - '@firebase/firestore-compat@0.4.2(@firebase/app-compat@0.5.4)(@firebase/app-types@0.9.3)(@firebase/app@0.14.4)': + '@firebase/firestore-compat@0.4.3(@firebase/app-compat@0.5.6)(@firebase/app-types@0.9.3)(@firebase/app@0.14.6)': dependencies: - '@firebase/app-compat': 0.5.4 + '@firebase/app-compat': 0.5.6 '@firebase/component': 0.7.0 - '@firebase/firestore': 4.9.2(@firebase/app@0.14.4) + '@firebase/firestore': 4.9.3(@firebase/app@0.14.6) '@firebase/firestore-types': 3.0.3(@firebase/app-types@0.9.3)(@firebase/util@1.13.0) '@firebase/util': 1.13.0 tslib: 2.8.1 @@ -11211,9 +11884,9 @@ snapshots: '@firebase/app-types': 0.9.3 '@firebase/util': 1.13.0 - '@firebase/firestore@4.9.2(@firebase/app@0.14.4)': + '@firebase/firestore@4.9.3(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/component': 0.7.0 '@firebase/logger': 0.5.0 '@firebase/util': 1.13.0 @@ -11222,11 +11895,11 @@ snapshots: '@grpc/proto-loader': 0.7.15 tslib: 2.8.1 - '@firebase/functions-compat@0.4.1(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4)': + '@firebase/functions-compat@0.4.1(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6)': dependencies: - '@firebase/app-compat': 0.5.4 + '@firebase/app-compat': 0.5.6 '@firebase/component': 0.7.0 - '@firebase/functions': 0.13.1(@firebase/app@0.14.4) + '@firebase/functions': 0.13.1(@firebase/app@0.14.6) '@firebase/functions-types': 0.6.3 '@firebase/util': 1.13.0 tslib: 2.8.1 @@ -11235,9 +11908,9 @@ snapshots: '@firebase/functions-types@0.6.3': {} - '@firebase/functions@0.13.1(@firebase/app@0.14.4)': + '@firebase/functions@0.13.1(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/app-check-interop-types': 0.3.3 '@firebase/auth-interop-types': 0.2.4 '@firebase/component': 0.7.0 @@ -11245,11 +11918,11 @@ snapshots: '@firebase/util': 1.13.0 tslib: 2.8.1 - '@firebase/installations-compat@0.2.19(@firebase/app-compat@0.5.4)(@firebase/app-types@0.9.3)(@firebase/app@0.14.4)': + '@firebase/installations-compat@0.2.19(@firebase/app-compat@0.5.6)(@firebase/app-types@0.9.3)(@firebase/app@0.14.6)': dependencies: - '@firebase/app-compat': 0.5.4 + '@firebase/app-compat': 0.5.6 '@firebase/component': 0.7.0 - '@firebase/installations': 0.6.19(@firebase/app@0.14.4) + '@firebase/installations': 0.6.19(@firebase/app@0.14.6) '@firebase/installations-types': 0.5.3(@firebase/app-types@0.9.3) '@firebase/util': 1.13.0 tslib: 2.8.1 @@ -11261,9 +11934,9 @@ snapshots: dependencies: '@firebase/app-types': 0.9.3 - '@firebase/installations@0.6.19(@firebase/app@0.14.4)': + '@firebase/installations@0.6.19(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/component': 0.7.0 '@firebase/util': 1.13.0 idb: 7.1.1 @@ -11273,11 +11946,11 @@ snapshots: dependencies: tslib: 2.8.1 - '@firebase/messaging-compat@0.2.23(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4)': + '@firebase/messaging-compat@0.2.23(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6)': dependencies: - '@firebase/app-compat': 0.5.4 + '@firebase/app-compat': 0.5.6 '@firebase/component': 0.7.0 - '@firebase/messaging': 0.12.23(@firebase/app@0.14.4) + '@firebase/messaging': 0.12.23(@firebase/app@0.14.6) '@firebase/util': 1.13.0 tslib: 2.8.1 transitivePeerDependencies: @@ -11285,22 +11958,22 @@ snapshots: '@firebase/messaging-interop-types@0.2.3': {} - '@firebase/messaging@0.12.23(@firebase/app@0.14.4)': + '@firebase/messaging@0.12.23(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/component': 0.7.0 - '@firebase/installations': 0.6.19(@firebase/app@0.14.4) + '@firebase/installations': 0.6.19(@firebase/app@0.14.6) '@firebase/messaging-interop-types': 0.2.3 '@firebase/util': 1.13.0 idb: 7.1.1 tslib: 2.8.1 - '@firebase/performance-compat@0.2.22(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4)': + '@firebase/performance-compat@0.2.22(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6)': dependencies: - '@firebase/app-compat': 0.5.4 + '@firebase/app-compat': 0.5.6 '@firebase/component': 0.7.0 '@firebase/logger': 0.5.0 - '@firebase/performance': 0.7.9(@firebase/app@0.14.4) + '@firebase/performance': 0.7.9(@firebase/app@0.14.6) '@firebase/performance-types': 0.2.3 '@firebase/util': 1.13.0 tslib: 2.8.1 @@ -11309,22 +11982,22 @@ snapshots: '@firebase/performance-types@0.2.3': {} - '@firebase/performance@0.7.9(@firebase/app@0.14.4)': + '@firebase/performance@0.7.9(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/component': 0.7.0 - '@firebase/installations': 0.6.19(@firebase/app@0.14.4) + '@firebase/installations': 0.6.19(@firebase/app@0.14.6) '@firebase/logger': 0.5.0 '@firebase/util': 1.13.0 tslib: 2.8.1 web-vitals: 4.2.4 - '@firebase/remote-config-compat@0.2.20(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4)': + '@firebase/remote-config-compat@0.2.20(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6)': dependencies: - '@firebase/app-compat': 0.5.4 + '@firebase/app-compat': 0.5.6 '@firebase/component': 0.7.0 '@firebase/logger': 0.5.0 - '@firebase/remote-config': 0.7.0(@firebase/app@0.14.4) + '@firebase/remote-config': 0.7.0(@firebase/app@0.14.6) '@firebase/remote-config-types': 0.5.0 '@firebase/util': 1.13.0 tslib: 2.8.1 @@ -11333,20 +12006,20 @@ snapshots: '@firebase/remote-config-types@0.5.0': {} - '@firebase/remote-config@0.7.0(@firebase/app@0.14.4)': + '@firebase/remote-config@0.7.0(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/component': 0.7.0 - '@firebase/installations': 0.6.19(@firebase/app@0.14.4) + '@firebase/installations': 0.6.19(@firebase/app@0.14.6) '@firebase/logger': 0.5.0 '@firebase/util': 1.13.0 tslib: 2.8.1 - '@firebase/storage-compat@0.4.0(@firebase/app-compat@0.5.4)(@firebase/app-types@0.9.3)(@firebase/app@0.14.4)': + '@firebase/storage-compat@0.4.0(@firebase/app-compat@0.5.6)(@firebase/app-types@0.9.3)(@firebase/app@0.14.6)': dependencies: - '@firebase/app-compat': 0.5.4 + '@firebase/app-compat': 0.5.6 '@firebase/component': 0.7.0 - '@firebase/storage': 0.14.0(@firebase/app@0.14.4) + '@firebase/storage': 0.14.0(@firebase/app@0.14.6) '@firebase/storage-types': 0.8.3(@firebase/app-types@0.9.3)(@firebase/util@1.13.0) '@firebase/util': 1.13.0 tslib: 2.8.1 @@ -11359,9 +12032,9 @@ snapshots: '@firebase/app-types': 0.9.3 '@firebase/util': 1.13.0 - '@firebase/storage@0.14.0(@firebase/app@0.14.4)': + '@firebase/storage@0.14.0(@firebase/app@0.14.6)': dependencies: - '@firebase/app': 0.14.4 + '@firebase/app': 0.14.6 '@firebase/component': 0.7.0 '@firebase/util': 1.13.0 tslib: 2.8.1 @@ -11372,7 +12045,7 @@ snapshots: '@firebase/webchannel-wrapper@1.0.5': {} - '@formatjs/ecma402-abstract@2.3.5': + '@formatjs/ecma402-abstract@2.3.6': dependencies: '@formatjs/fast-memoize': 2.2.7 '@formatjs/intl-localematcher': 0.6.2 @@ -11383,26 +12056,26 @@ snapshots: dependencies: tslib: 2.8.1 - '@formatjs/icu-messageformat-parser@2.11.3': + '@formatjs/icu-messageformat-parser@2.11.4': dependencies: - '@formatjs/ecma402-abstract': 2.3.5 - '@formatjs/icu-skeleton-parser': 1.8.15 + '@formatjs/ecma402-abstract': 2.3.6 + '@formatjs/icu-skeleton-parser': 1.8.16 tslib: 2.8.1 - '@formatjs/icu-skeleton-parser@1.8.15': + '@formatjs/icu-skeleton-parser@1.8.16': dependencies: - '@formatjs/ecma402-abstract': 2.3.5 + '@formatjs/ecma402-abstract': 2.3.6 tslib: 2.8.1 '@formatjs/intl-localematcher@0.6.2': dependencies: tslib: 2.8.1 - '@google-cloud/cloud-sql-connector@1.8.3': + '@google-cloud/cloud-sql-connector@1.8.4': dependencies: '@googleapis/sqladmin': 31.1.0 - gaxios: 7.1.2(supports-color@10.2.2) - google-auth-library: 10.4.0(supports-color@10.2.2) + gaxios: 7.1.3(supports-color@10.2.2) + google-auth-library: 10.5.0(supports-color@10.2.2) p-throttle: 7.0.0 transitivePeerDependencies: - supports-color @@ -11414,7 +12087,7 @@ snapshots: arrify: 2.0.1 duplexify: 4.1.3 extend: 3.0.2 - google-auth-library: 10.4.0(supports-color@10.2.2) + google-auth-library: 10.5.0(supports-color@10.2.2) html-entities: 2.6.0 retry-request: 8.0.2(supports-color@10.2.2) teeny-request: 10.1.0(supports-color@10.2.2) @@ -11450,7 +12123,7 @@ snapshots: '@opentelemetry/semantic-conventions': 1.30.0 arrify: 2.0.1 extend: 3.0.2 - google-auth-library: 9.15.1(encoding@0.1.13)(supports-color@10.2.2) + google-auth-library: 9.15.1(encoding@0.1.13) google-gax: 4.6.1(encoding@0.1.13) heap-js: 2.7.1 is-stream-ended: 0.1.4 @@ -11468,9 +12141,9 @@ snapshots: '@google-cloud/promisify': 5.0.0 '@grpc/proto-loader': 0.7.15 '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 2.1.0(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/context-async-hooks': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.38.0 '@types/big.js': 6.2.2 '@types/stack-trace': 0.0.33 big.js: 7.0.1 @@ -11478,8 +12151,8 @@ snapshots: duplexify: 4.1.3 events-intercept: 2.0.0 extend: 3.0.2 - google-auth-library: 10.4.0(supports-color@10.2.2) - google-gax: 5.0.4(supports-color@10.2.2) + google-auth-library: 10.5.0(supports-color@10.2.2) + google-gax: 5.0.6(supports-color@10.2.2) grpc-gcp: 1.0.1 is: 3.3.2 lodash.snakecase: 4.1.1 @@ -11495,15 +12168,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@google/genai@1.25.0(@modelcontextprotocol/sdk@1.20.0)(bufferutil@4.0.9)(encoding@0.1.13)(supports-color@10.2.2)(utf-8-validate@6.0.5)': + '@google/genai@1.33.0(@modelcontextprotocol/sdk@1.24.3)(bufferutil@4.0.9)(supports-color@10.2.2)(utf-8-validate@6.0.5)': dependencies: - google-auth-library: 9.15.1(encoding@0.1.13)(supports-color@10.2.2) + google-auth-library: 10.5.0(supports-color@10.2.2) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) optionalDependencies: - '@modelcontextprotocol/sdk': 1.20.0 + '@modelcontextprotocol/sdk': 1.24.3 transitivePeerDependencies: - bufferutil - - encoding - supports-color - utf-8-validate @@ -11513,7 +12185,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@grpc/grpc-js@1.14.0': + '@grpc/grpc-js@1.14.2': dependencies: '@grpc/proto-loader': 0.8.0 '@js-sdsl/ordered-map': 4.4.2 @@ -11521,7 +12193,7 @@ snapshots: '@grpc/grpc-js@1.9.15': dependencies: '@grpc/proto-loader': 0.7.15 - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@grpc/proto-loader@0.7.15': dependencies: @@ -11537,365 +12209,271 @@ snapshots: protobufjs: 7.5.4 yargs: 17.7.2 - '@inquirer/ansi@1.0.0': {} - - '@inquirer/ansi@1.0.1': {} - - '@inquirer/checkbox@4.2.4(@types/node@22.18.8)': - dependencies: - '@inquirer/ansi': 1.0.0 - '@inquirer/core': 10.2.2(@types/node@22.18.8) - '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.9(@types/node@22.18.8) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.18.8 + '@inquirer/ansi@1.0.2': {} - '@inquirer/checkbox@4.3.0(@types/node@22.18.8)': - dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0(@types/node@22.18.8) - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@22.18.8) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.18.8 + '@inquirer/ansi@2.0.2': {} - '@inquirer/checkbox@4.3.0(@types/node@24.8.1)': + '@inquirer/checkbox@4.3.2(@types/node@22.19.2)': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 22.19.2 - '@inquirer/confirm@5.1.18(@types/node@22.18.8)': + '@inquirer/checkbox@5.0.3(@types/node@24.10.4)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) + '@inquirer/ansi': 2.0.2 + '@inquirer/core': 11.1.0(@types/node@24.10.4) + '@inquirer/figures': 2.0.2 + '@inquirer/type': 4.0.2(@types/node@24.10.4) optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 24.10.4 - '@inquirer/confirm@5.1.19(@types/node@22.18.8)': + '@inquirer/confirm@5.1.19(@types/node@22.19.2)': dependencies: - '@inquirer/core': 10.3.0(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@inquirer/confirm@5.1.19(@types/node@24.8.1)': + '@inquirer/confirm@5.1.21(@types/node@22.19.2)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 22.19.2 - '@inquirer/core@10.2.2(@types/node@22.18.8)': + '@inquirer/confirm@6.0.3(@types/node@24.10.4)': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@22.18.8) - cli-width: 4.1.0 - mute-stream: 2.0.0 - signal-exit: 4.1.0 - wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 11.1.0(@types/node@24.10.4) + '@inquirer/type': 4.0.2(@types/node@24.10.4) optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 24.10.4 - '@inquirer/core@10.3.0(@types/node@22.18.8)': + '@inquirer/core@10.3.2(@types/node@22.19.2)': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@22.18.8) + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@inquirer/core@10.3.0(@types/node@24.8.1)': + '@inquirer/core@11.1.0(@types/node@24.10.4)': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/ansi': 2.0.2 + '@inquirer/figures': 2.0.2 + '@inquirer/type': 4.0.2(@types/node@24.10.4) cli-width: 4.1.0 - mute-stream: 2.0.0 + mute-stream: 3.0.0 signal-exit: 4.1.0 - wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 24.8.1 - - '@inquirer/editor@4.2.20(@types/node@22.18.8)': - dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.8) - '@inquirer/external-editor': 1.0.2(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) - optionalDependencies: - '@types/node': 22.18.8 - - '@inquirer/editor@4.2.21(@types/node@22.18.8)': - dependencies: - '@inquirer/core': 10.3.0(@types/node@22.18.8) - '@inquirer/external-editor': 1.0.2(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) + wrap-ansi: 9.0.2 optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 24.10.4 - '@inquirer/editor@4.2.21(@types/node@24.8.1)': + '@inquirer/editor@4.2.23(@types/node@22.19.2)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/external-editor': 1.0.2(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/external-editor': 1.0.3(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 22.19.2 - '@inquirer/expand@4.0.20(@types/node@22.18.8)': + '@inquirer/editor@5.0.3(@types/node@24.10.4)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 11.1.0(@types/node@24.10.4) + '@inquirer/external-editor': 2.0.2(@types/node@24.10.4) + '@inquirer/type': 4.0.2(@types/node@24.10.4) optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 24.10.4 - '@inquirer/expand@4.0.21(@types/node@22.18.8)': + '@inquirer/expand@4.0.23(@types/node@22.19.2)': dependencies: - '@inquirer/core': 10.3.0(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@inquirer/expand@4.0.21(@types/node@24.8.1)': + '@inquirer/expand@5.0.3(@types/node@24.10.4)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 11.1.0(@types/node@24.10.4) + '@inquirer/type': 4.0.2(@types/node@24.10.4) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.10.4 - '@inquirer/external-editor@1.0.2(@types/node@22.18.8)': + '@inquirer/external-editor@1.0.3(@types/node@22.19.2)': dependencies: - chardet: 2.1.0 + chardet: 2.1.1 iconv-lite: 0.7.0 optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@inquirer/external-editor@1.0.2(@types/node@24.8.1)': + '@inquirer/external-editor@2.0.2(@types/node@24.10.4)': dependencies: - chardet: 2.1.0 + chardet: 2.1.1 iconv-lite: 0.7.0 optionalDependencies: - '@types/node': 24.8.1 - - '@inquirer/figures@1.0.13': {} - - '@inquirer/figures@1.0.14': {} - - '@inquirer/input@4.2.4(@types/node@22.18.8)': - dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) - optionalDependencies: - '@types/node': 22.18.8 - - '@inquirer/input@4.2.5(@types/node@22.18.8)': - dependencies: - '@inquirer/core': 10.3.0(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) - optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 24.10.4 - '@inquirer/input@4.2.5(@types/node@24.8.1)': - dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) - optionalDependencies: - '@types/node': 24.8.1 + '@inquirer/figures@1.0.15': {} - '@inquirer/number@3.0.20(@types/node@22.18.8)': - dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) - optionalDependencies: - '@types/node': 22.18.8 + '@inquirer/figures@2.0.2': {} - '@inquirer/number@3.0.21(@types/node@22.18.8)': + '@inquirer/input@4.3.1(@types/node@22.19.2)': dependencies: - '@inquirer/core': 10.3.0(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@inquirer/number@3.0.21(@types/node@24.8.1)': + '@inquirer/input@5.0.3(@types/node@24.10.4)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 11.1.0(@types/node@24.10.4) + '@inquirer/type': 4.0.2(@types/node@24.10.4) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.10.4 - '@inquirer/password@4.0.20(@types/node@22.18.8)': + '@inquirer/number@3.0.23(@types/node@22.19.2)': dependencies: - '@inquirer/ansi': 1.0.0 - '@inquirer/core': 10.2.2(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@inquirer/password@4.0.21(@types/node@22.18.8)': + '@inquirer/number@4.0.3(@types/node@24.10.4)': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) + '@inquirer/core': 11.1.0(@types/node@24.10.4) + '@inquirer/type': 4.0.2(@types/node@24.10.4) optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 24.10.4 - '@inquirer/password@4.0.21(@types/node@24.8.1)': + '@inquirer/password@4.0.23(@types/node@22.19.2)': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) - optionalDependencies: - '@types/node': 24.8.1 - - '@inquirer/prompts@7.8.6(@types/node@22.18.8)': - dependencies: - '@inquirer/checkbox': 4.2.4(@types/node@22.18.8) - '@inquirer/confirm': 5.1.18(@types/node@22.18.8) - '@inquirer/editor': 4.2.20(@types/node@22.18.8) - '@inquirer/expand': 4.0.20(@types/node@22.18.8) - '@inquirer/input': 4.2.4(@types/node@22.18.8) - '@inquirer/number': 3.0.20(@types/node@22.18.8) - '@inquirer/password': 4.0.20(@types/node@22.18.8) - '@inquirer/rawlist': 4.1.8(@types/node@22.18.8) - '@inquirer/search': 3.1.3(@types/node@22.18.8) - '@inquirer/select': 4.3.4(@types/node@22.18.8) - optionalDependencies: - '@types/node': 22.18.8 - - '@inquirer/prompts@7.9.0(@types/node@22.18.8)': - dependencies: - '@inquirer/checkbox': 4.3.0(@types/node@22.18.8) - '@inquirer/confirm': 5.1.19(@types/node@22.18.8) - '@inquirer/editor': 4.2.21(@types/node@22.18.8) - '@inquirer/expand': 4.0.21(@types/node@22.18.8) - '@inquirer/input': 4.2.5(@types/node@22.18.8) - '@inquirer/number': 3.0.21(@types/node@22.18.8) - '@inquirer/password': 4.0.21(@types/node@22.18.8) - '@inquirer/rawlist': 4.1.9(@types/node@22.18.8) - '@inquirer/search': 3.2.0(@types/node@22.18.8) - '@inquirer/select': 4.4.0(@types/node@22.18.8) + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) optionalDependencies: - '@types/node': 22.18.8 - - '@inquirer/prompts@7.9.0(@types/node@24.8.1)': - dependencies: - '@inquirer/checkbox': 4.3.0(@types/node@24.8.1) - '@inquirer/confirm': 5.1.19(@types/node@24.8.1) - '@inquirer/editor': 4.2.21(@types/node@24.8.1) - '@inquirer/expand': 4.0.21(@types/node@24.8.1) - '@inquirer/input': 4.2.5(@types/node@24.8.1) - '@inquirer/number': 3.0.21(@types/node@24.8.1) - '@inquirer/password': 4.0.21(@types/node@24.8.1) - '@inquirer/rawlist': 4.1.9(@types/node@24.8.1) - '@inquirer/search': 3.2.0(@types/node@24.8.1) - '@inquirer/select': 4.4.0(@types/node@24.8.1) - optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 22.19.2 - '@inquirer/rawlist@4.1.8(@types/node@22.18.8)': + '@inquirer/password@5.0.3(@types/node@24.10.4)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) - yoctocolors-cjs: 2.1.3 + '@inquirer/ansi': 2.0.2 + '@inquirer/core': 11.1.0(@types/node@24.10.4) + '@inquirer/type': 4.0.2(@types/node@24.10.4) optionalDependencies: - '@types/node': 22.18.8 - - '@inquirer/rawlist@4.1.9(@types/node@22.18.8)': - dependencies: - '@inquirer/core': 10.3.0(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) - yoctocolors-cjs: 2.1.3 + '@types/node': 24.10.4 + + '@inquirer/prompts@7.10.1(@types/node@22.19.2)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@22.19.2) + '@inquirer/confirm': 5.1.21(@types/node@22.19.2) + '@inquirer/editor': 4.2.23(@types/node@22.19.2) + '@inquirer/expand': 4.0.23(@types/node@22.19.2) + '@inquirer/input': 4.3.1(@types/node@22.19.2) + '@inquirer/number': 3.0.23(@types/node@22.19.2) + '@inquirer/password': 4.0.23(@types/node@22.19.2) + '@inquirer/rawlist': 4.1.11(@types/node@22.19.2) + '@inquirer/search': 3.2.2(@types/node@22.19.2) + '@inquirer/select': 4.4.2(@types/node@22.19.2) optionalDependencies: - '@types/node': 22.18.8 - - '@inquirer/rawlist@4.1.9(@types/node@24.8.1)': - dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/type': 3.0.9(@types/node@24.8.1) - yoctocolors-cjs: 2.1.3 + '@types/node': 22.19.2 + + '@inquirer/prompts@7.9.0(@types/node@22.19.2)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@22.19.2) + '@inquirer/confirm': 5.1.21(@types/node@22.19.2) + '@inquirer/editor': 4.2.23(@types/node@22.19.2) + '@inquirer/expand': 4.0.23(@types/node@22.19.2) + '@inquirer/input': 4.3.1(@types/node@22.19.2) + '@inquirer/number': 3.0.23(@types/node@22.19.2) + '@inquirer/password': 4.0.23(@types/node@22.19.2) + '@inquirer/rawlist': 4.1.11(@types/node@22.19.2) + '@inquirer/search': 3.2.2(@types/node@22.19.2) + '@inquirer/select': 4.4.2(@types/node@22.19.2) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 22.19.2 + + '@inquirer/prompts@8.1.0(@types/node@24.10.4)': + dependencies: + '@inquirer/checkbox': 5.0.3(@types/node@24.10.4) + '@inquirer/confirm': 6.0.3(@types/node@24.10.4) + '@inquirer/editor': 5.0.3(@types/node@24.10.4) + '@inquirer/expand': 5.0.3(@types/node@24.10.4) + '@inquirer/input': 5.0.3(@types/node@24.10.4) + '@inquirer/number': 4.0.3(@types/node@24.10.4) + '@inquirer/password': 5.0.3(@types/node@24.10.4) + '@inquirer/rawlist': 5.1.0(@types/node@24.10.4) + '@inquirer/search': 4.0.3(@types/node@24.10.4) + '@inquirer/select': 5.0.3(@types/node@24.10.4) + optionalDependencies: + '@types/node': 24.10.4 - '@inquirer/search@3.1.3(@types/node@22.18.8)': + '@inquirer/rawlist@4.1.11(@types/node@22.19.2)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.8) - '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.9(@types/node@22.18.8) + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@inquirer/search@3.2.0(@types/node@22.18.8)': + '@inquirer/rawlist@5.1.0(@types/node@24.10.4)': dependencies: - '@inquirer/core': 10.3.0(@types/node@22.18.8) - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@22.18.8) - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 11.1.0(@types/node@24.10.4) + '@inquirer/type': 4.0.2(@types/node@24.10.4) optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 24.10.4 - '@inquirer/search@3.2.0(@types/node@24.8.1)': + '@inquirer/search@3.2.2(@types/node@22.19.2)': dependencies: - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@24.8.1) + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 22.19.2 - '@inquirer/select@4.3.4(@types/node@22.18.8)': + '@inquirer/search@4.0.3(@types/node@24.10.4)': dependencies: - '@inquirer/ansi': 1.0.0 - '@inquirer/core': 10.2.2(@types/node@22.18.8) - '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.9(@types/node@22.18.8) - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 11.1.0(@types/node@24.10.4) + '@inquirer/figures': 2.0.2 + '@inquirer/type': 4.0.2(@types/node@24.10.4) optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 24.10.4 - '@inquirer/select@4.4.0(@types/node@22.18.8)': + '@inquirer/select@4.4.2(@types/node@22.19.2)': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0(@types/node@22.18.8) - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@22.18.8) + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@22.19.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@inquirer/select@4.4.0(@types/node@24.8.1)': + '@inquirer/select@5.0.3(@types/node@24.10.4)': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0(@types/node@24.8.1) - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@24.8.1) - yoctocolors-cjs: 2.1.3 + '@inquirer/ansi': 2.0.2 + '@inquirer/core': 11.1.0(@types/node@24.10.4) + '@inquirer/figures': 2.0.2 + '@inquirer/type': 4.0.2(@types/node@24.10.4) optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.10.4 - '@inquirer/type@3.0.9(@types/node@22.18.8)': + '@inquirer/type@3.0.10(@types/node@22.19.2)': optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@inquirer/type@3.0.9(@types/node@24.8.1)': + '@inquirer/type@4.0.2(@types/node@24.10.4)': optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.10.4 '@isaacs/balanced-match@4.0.1': {} @@ -11955,7 +12533,7 @@ snapshots: dependencies: tslib: 2.8.1 - '@jsonjoy.com/buffers@1.0.0(tslib@2.8.1)': + '@jsonjoy.com/buffers@1.2.1(tslib@2.8.1)': dependencies: tslib: 2.8.1 @@ -11963,15 +12541,16 @@ snapshots: dependencies: tslib: 2.8.1 - '@jsonjoy.com/json-pack@1.14.0(tslib@2.8.1)': + '@jsonjoy.com/json-pack@1.21.0(tslib@2.8.1)': dependencies: '@jsonjoy.com/base64': 1.1.2(tslib@2.8.1) - '@jsonjoy.com/buffers': 1.0.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) '@jsonjoy.com/json-pointer': 1.0.2(tslib@2.8.1) '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) hyperdyperid: 1.2.0 thingies: 2.5.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) tslib: 2.8.1 '@jsonjoy.com/json-pointer@1.0.2(tslib@2.8.1)': @@ -11982,17 +12561,17 @@ snapshots: '@jsonjoy.com/util@1.9.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/buffers': 1.0.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) tslib: 2.8.1 '@leichtgewicht/ip-codec@2.0.5': {} - '@listr2/prompt-adapter-inquirer@3.0.4(@inquirer/prompts@7.9.0(@types/node@22.18.8))(@types/node@22.18.8)(listr2@9.0.4)': + '@listr2/prompt-adapter-inquirer@3.0.5(@inquirer/prompts@7.9.0(@types/node@22.19.2))(@types/node@22.19.2)(listr2@9.0.5)': dependencies: - '@inquirer/prompts': 7.9.0(@types/node@22.18.8) - '@inquirer/type': 3.0.9(@types/node@22.18.8) - listr2: 9.0.4 + '@inquirer/prompts': 7.9.0(@types/node@22.19.2) + '@inquirer/type': 3.0.10(@types/node@22.19.2) + listr2: 9.0.5 transitivePeerDependencies: - '@types/node' @@ -12019,37 +12598,41 @@ snapshots: '@material/material-color-utilities@0.3.0': {} - '@modelcontextprotocol/sdk@1.19.1': + '@modelcontextprotocol/sdk@1.24.0': dependencies: - ajv: 6.12.6 + ajv: 8.17.1 + ajv-formats: 3.0.1 content-type: 1.0.5 cors: 2.8.5 cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.0.6 - express: 5.1.0 - express-rate-limit: 7.5.1(express@5.1.0) - pkce-challenge: 5.0.0 - raw-body: 3.0.1 - zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) + express: 5.2.1 + express-rate-limit: 7.5.1(express@5.2.1) + jose: 6.1.3 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.1.13 + zod-to-json-schema: 3.25.0(zod@4.1.13) transitivePeerDependencies: - supports-color - '@modelcontextprotocol/sdk@1.20.0': + '@modelcontextprotocol/sdk@1.24.3': dependencies: - ajv: 6.12.6 + ajv: 8.17.1 + ajv-formats: 3.0.1 content-type: 1.0.5 cors: 2.8.5 cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.0.6 - express: 5.1.0 - express-rate-limit: 7.5.1(express@5.1.0) - pkce-challenge: 5.0.0 - raw-body: 3.0.1 + express: 5.2.1 + express-rate-limit: 7.5.1(express@5.2.1) + jose: 6.1.3 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) + zod-to-json-schema: 3.25.0(zod@3.25.76) transitivePeerDependencies: - supports-color @@ -12071,7 +12654,7 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': optional: true - '@mswjs/interceptors@0.39.7': + '@mswjs/interceptors@0.39.8': dependencies: '@open-draft/deferred-promise': 2.2.0 '@open-draft/logger': 0.3.0 @@ -12152,29 +12735,29 @@ snapshots: '@napi-rs/nice-win32-x64-msvc': 1.1.1 optional: true - '@napi-rs/wasm-runtime@1.0.7': + '@napi-rs/wasm-runtime@1.1.0': dependencies: - '@emnapi/core': 1.5.0 - '@emnapi/runtime': 1.5.0 + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 '@tybys/wasm-util': 0.10.1 optional: true - '@nginfra/angular-linking@1.0.9(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))': + '@nginfra/angular-linking@1.0.9(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))': dependencies: - '@angular/compiler-cli': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2) + '@angular/compiler-cli': 21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2) '@babel/core': 7.26.10 '@types/babel__core': 7.20.5 - '@types/node': 22.18.8 + '@types/node': 22.19.2 tinyglobby: 0.2.12 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@ngtools/webpack@21.0.0-next.8(@angular/compiler-cli@21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2))(typescript@5.9.2)(webpack@5.102.1(esbuild@0.25.10))': + '@ngtools/webpack@21.0.3(@angular/compiler-cli@21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2))(typescript@5.9.2)(webpack@5.102.1(esbuild@0.26.0))': dependencies: - '@angular/compiler-cli': 21.0.0-next.8(@angular/compiler@21.0.0-next.8)(typescript@5.9.2) + '@angular/compiler-cli': 21.0.5(@angular/compiler@21.0.5)(typescript@5.9.2) typescript: 5.9.2 - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) '@nodelib/fs.scandir@2.1.5': dependencies: @@ -12197,13 +12780,14 @@ snapshots: socks-proxy-agent: 8.0.5 transitivePeerDependencies: - supports-color + optional: true '@npmcli/agent@4.0.0': dependencies: agent-base: 7.1.4 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6(supports-color@10.2.2) - lru-cache: 11.2.2 + lru-cache: 11.2.4 socks-proxy-agent: 8.0.5 transitivePeerDependencies: - supports-color @@ -12211,32 +12795,37 @@ snapshots: '@npmcli/fs@4.0.0': dependencies: semver: 7.7.3 + optional: true - '@npmcli/git@7.0.0': + '@npmcli/fs@5.0.0': dependencies: - '@npmcli/promise-spawn': 8.0.3 - ini: 5.0.0 - lru-cache: 11.2.2 - npm-pick-manifest: 11.0.1 - proc-log: 5.0.0 + semver: 7.7.3 + + '@npmcli/git@7.0.1': + dependencies: + '@npmcli/promise-spawn': 9.0.1 + ini: 6.0.0 + lru-cache: 11.2.4 + npm-pick-manifest: 11.0.3 + proc-log: 6.1.0 promise-retry: 2.0.1 semver: 7.7.3 - which: 5.0.0 + which: 6.0.0 '@npmcli/installed-package-contents@3.0.0': dependencies: npm-bundled: 4.0.0 npm-normalize-package-bin: 4.0.0 - '@npmcli/node-gyp@4.0.0': {} + '@npmcli/node-gyp@5.0.0': {} - '@npmcli/package-json@7.0.1': + '@npmcli/package-json@7.0.4': dependencies: - '@npmcli/git': 7.0.0 - glob: 11.0.3 - hosted-git-info: 9.0.0 - json-parse-even-better-errors: 4.0.0 - proc-log: 5.0.0 + '@npmcli/git': 7.0.1 + glob: 13.0.0 + hosted-git-info: 9.0.2 + json-parse-even-better-errors: 5.0.0 + proc-log: 6.1.0 semver: 7.7.3 validate-npm-package-license: 3.0.4 @@ -12248,129 +12837,156 @@ snapshots: dependencies: which: 5.0.0 - '@npmcli/redact@3.2.2': {} + '@npmcli/promise-spawn@9.0.1': + dependencies: + which: 6.0.0 + + '@npmcli/redact@4.0.0': {} - '@npmcli/run-script@10.0.0': + '@npmcli/run-script@10.0.3': dependencies: - '@npmcli/node-gyp': 4.0.0 - '@npmcli/package-json': 7.0.1 - '@npmcli/promise-spawn': 8.0.3 - node-gyp: 11.4.2 - proc-log: 5.0.0 - which: 5.0.0 + '@npmcli/node-gyp': 5.0.0 + '@npmcli/package-json': 7.0.4 + '@npmcli/promise-spawn': 9.0.1 + node-gyp: 12.1.0 + proc-log: 6.1.0 + which: 6.0.0 transitivePeerDependencies: - supports-color - '@octokit/auth-app@8.1.1': + '@octokit/auth-app@8.1.2': dependencies: - '@octokit/auth-oauth-app': 9.0.2 - '@octokit/auth-oauth-user': 6.0.1 - '@octokit/request': 10.0.5 - '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/auth-oauth-app': 9.0.3 + '@octokit/auth-oauth-user': 6.0.2 + '@octokit/request': 10.0.7 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 toad-cache: 3.7.0 universal-github-app-jwt: 2.2.2 universal-user-agent: 7.0.3 - '@octokit/auth-oauth-app@9.0.2': + '@octokit/auth-oauth-app@9.0.3': dependencies: - '@octokit/auth-oauth-device': 8.0.2 - '@octokit/auth-oauth-user': 6.0.1 - '@octokit/request': 10.0.5 - '@octokit/types': 15.0.0 + '@octokit/auth-oauth-device': 8.0.3 + '@octokit/auth-oauth-user': 6.0.2 + '@octokit/request': 10.0.7 + '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 - '@octokit/auth-oauth-device@8.0.2': + '@octokit/auth-oauth-device@8.0.3': dependencies: - '@octokit/oauth-methods': 6.0.1 - '@octokit/request': 10.0.5 - '@octokit/types': 15.0.0 + '@octokit/oauth-methods': 6.0.2 + '@octokit/request': 10.0.7 + '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 - '@octokit/auth-oauth-user@6.0.1': + '@octokit/auth-oauth-user@6.0.2': dependencies: - '@octokit/auth-oauth-device': 8.0.2 - '@octokit/oauth-methods': 6.0.1 - '@octokit/request': 10.0.5 - '@octokit/types': 15.0.0 + '@octokit/auth-oauth-device': 8.0.3 + '@octokit/oauth-methods': 6.0.2 + '@octokit/request': 10.0.7 + '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 '@octokit/auth-token@6.0.0': {} - '@octokit/core@7.0.5': + '@octokit/core@7.0.6': dependencies: '@octokit/auth-token': 6.0.0 - '@octokit/graphql': 9.0.2 - '@octokit/request': 10.0.5 - '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/graphql': 9.0.3 + '@octokit/request': 10.0.7 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 before-after-hook: 4.0.0 universal-user-agent: 7.0.3 - '@octokit/endpoint@11.0.1': + '@octokit/endpoint@11.0.2': dependencies: - '@octokit/types': 15.0.0 + '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 - '@octokit/graphql-schema@15.26.0': + '@octokit/graphql-schema@15.26.1': dependencies: - graphql: 16.11.0 - graphql-tag: 2.12.6(graphql@16.11.0) + graphql: 16.12.0 + graphql-tag: 2.12.6(graphql@16.12.0) - '@octokit/graphql@9.0.2': + '@octokit/graphql@9.0.3': dependencies: - '@octokit/request': 10.0.5 - '@octokit/types': 15.0.0 + '@octokit/request': 10.0.7 + '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 '@octokit/oauth-authorization-url@8.0.0': {} - '@octokit/oauth-methods@6.0.1': + '@octokit/oauth-methods@6.0.2': dependencies: '@octokit/oauth-authorization-url': 8.0.0 - '@octokit/request': 10.0.5 - '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/request': 10.0.7 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 '@octokit/openapi-types@26.0.0': {} - '@octokit/plugin-paginate-rest@13.2.0(@octokit/core@7.0.5)': + '@octokit/openapi-types@27.0.0': {} + + '@octokit/plugin-paginate-rest@13.2.1(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/types': 15.0.2 + + '@octokit/plugin-paginate-rest@14.0.0(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/types': 16.0.0 + + '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.6)': dependencies: - '@octokit/core': 7.0.5 - '@octokit/types': 15.0.0 + '@octokit/core': 7.0.6 - '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.5)': + '@octokit/plugin-rest-endpoint-methods@16.1.1(@octokit/core@7.0.6)': dependencies: - '@octokit/core': 7.0.5 + '@octokit/core': 7.0.6 + '@octokit/types': 15.0.2 - '@octokit/plugin-rest-endpoint-methods@16.1.0(@octokit/core@7.0.5)': + '@octokit/plugin-rest-endpoint-methods@17.0.0(@octokit/core@7.0.6)': dependencies: - '@octokit/core': 7.0.5 - '@octokit/types': 15.0.0 + '@octokit/core': 7.0.6 + '@octokit/types': 16.0.0 - '@octokit/request-error@7.0.1': + '@octokit/request-error@7.1.0': dependencies: - '@octokit/types': 15.0.0 + '@octokit/types': 16.0.0 - '@octokit/request@10.0.5': + '@octokit/request@10.0.7': dependencies: - '@octokit/endpoint': 11.0.1 - '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/endpoint': 11.0.2 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 fast-content-type-parse: 3.0.0 universal-user-agent: 7.0.3 '@octokit/rest@22.0.0': dependencies: - '@octokit/core': 7.0.5 - '@octokit/plugin-paginate-rest': 13.2.0(@octokit/core@7.0.5) - '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.5) - '@octokit/plugin-rest-endpoint-methods': 16.1.0(@octokit/core@7.0.5) + '@octokit/core': 7.0.6 + '@octokit/plugin-paginate-rest': 13.2.1(@octokit/core@7.0.6) + '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.6) + '@octokit/plugin-rest-endpoint-methods': 16.1.1(@octokit/core@7.0.6) - '@octokit/types@15.0.0': + '@octokit/rest@22.0.1': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6) + '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.6) + '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6) + + '@octokit/types@15.0.2': dependencies: '@octokit/openapi-types': 26.0.0 + '@octokit/types@16.0.0': + dependencies: + '@octokit/openapi-types': 27.0.0 + '@open-draft/deferred-promise@2.2.0': {} '@open-draft/logger@0.3.0': @@ -12390,7 +13006,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks@2.1.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -12399,17 +13015,17 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.28.0 - '@opentelemetry/core@2.1.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/instrumentation-amqplib@0.46.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -12418,7 +13034,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@types/connect': 3.4.38 transitivePeerDependencies: - supports-color @@ -12435,7 +13051,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -12466,7 +13082,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -12486,7 +13102,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) '@opentelemetry/redis-common': 0.36.2 - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -12494,7 +13110,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -12502,7 +13118,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -12511,7 +13127,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -12526,7 +13142,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -12535,7 +13151,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -12543,7 +13159,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color @@ -12552,7 +13168,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@types/mysql': 2.15.26 transitivePeerDependencies: - supports-color @@ -12562,7 +13178,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.0) '@types/pg': 8.6.1 '@types/pg-pool': 2.0.6 @@ -12574,7 +13190,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) '@opentelemetry/redis-common': 0.36.2 - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 transitivePeerDependencies: - supports-color @@ -12582,7 +13198,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@types/tedious': 4.0.14 transitivePeerDependencies: - supports-color @@ -12600,7 +13216,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/api-logs': 0.57.2 '@types/shimmer': 1.2.0 - import-in-the-middle: 1.14.4 + import-in-the-middle: 1.15.0 require-in-the-middle: 7.5.2 semver: 7.7.3 shimmer: 1.2.1 @@ -12626,14 +13242,14 @@ snapshots: '@opentelemetry/semantic-conventions@1.30.0': {} - '@opentelemetry/semantic-conventions@1.37.0': {} + '@opentelemetry/semantic-conventions@1.38.0': {} '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@oxc-project/types@0.94.0': {} + '@oxc-project/types@0.96.0': {} '@parcel/watcher-android-arm64@2.5.1': optional: true @@ -12699,7 +13315,7 @@ snapshots: '@paulirish/trace_engine@0.0.61': dependencies: legacy-javascript: 0.0.1 - third-party-web: 0.27.0 + third-party-web: 0.29.0 '@phenomnomnominal/tsquery@4.2.0(typescript@5.9.2)': dependencies: @@ -12719,10 +13335,10 @@ snapshots: '@pnpm/crypto.polyfill@1000.1.0': {} - '@pnpm/dependency-path@1001.1.2': + '@pnpm/dependency-path@1001.1.8': dependencies: '@pnpm/crypto.hash': 1000.2.1 - '@pnpm/types': 1000.8.0 + '@pnpm/types': 1001.2.0 semver: 7.7.3 '@pnpm/graceful-fs@1000.0.1': @@ -12739,7 +13355,7 @@ snapshots: '@pnpm/network.ca-file': 1.0.2 config-chain: 1.1.13 - '@pnpm/types@1000.8.0': {} + '@pnpm/types@1001.2.0': {} '@prisma/instrumentation@6.11.1(@opentelemetry/api@1.9.0)': dependencies: @@ -12771,7 +13387,7 @@ snapshots: '@protobufjs/utf8@1.1.0': {} - '@puppeteer/browsers@2.10.10': + '@puppeteer/browsers@2.11.0': dependencies: debug: 4.4.3(supports-color@10.2.2) extract-zip: 2.0.1 @@ -12781,59 +13397,60 @@ snapshots: tar-fs: 3.1.1 yargs: 17.7.2 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a - supports-color - '@rolldown/binding-android-arm64@1.0.0-beta.43': + '@rolldown/binding-android-arm64@1.0.0-beta.47': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-beta.43': + '@rolldown/binding-darwin-arm64@1.0.0-beta.47': optional: true - '@rolldown/binding-darwin-x64@1.0.0-beta.43': + '@rolldown/binding-darwin-x64@1.0.0-beta.47': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-beta.43': + '@rolldown/binding-freebsd-x64@1.0.0-beta.47': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.43': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.47': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.43': + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.47': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.43': + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.47': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.43': + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.47': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.43': + '@rolldown/binding-linux-x64-musl@1.0.0-beta.47': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.43': + '@rolldown/binding-openharmony-arm64@1.0.0-beta.47': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.43': + '@rolldown/binding-wasm32-wasi@1.0.0-beta.47': dependencies: - '@napi-rs/wasm-runtime': 1.0.7 + '@napi-rs/wasm-runtime': 1.1.0 optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.43': + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.47': optional: true - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.43': + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.47': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.43': + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.47': optional: true - '@rolldown/pluginutils@1.0.0-beta.43': {} + '@rolldown/pluginutils@1.0.0-beta.47': {} - '@rollup/plugin-commonjs@28.0.6(rollup@4.52.4)': + '@rollup/plugin-commonjs@28.0.9(rollup@4.53.3)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) + '@rollup/pluginutils': 5.3.0(rollup@4.53.3) commondir: 1.0.1 estree-walker: 2.0.2 fdir: 6.5.0(picomatch@4.0.3) @@ -12841,111 +13458,111 @@ snapshots: magic-string: 0.30.19 picomatch: 4.0.3 optionalDependencies: - rollup: 4.52.4 + rollup: 4.53.3 - '@rollup/plugin-node-resolve@16.0.2(rollup@4.52.4)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.53.3)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) + '@rollup/pluginutils': 5.3.0(rollup@4.53.3) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 - resolve: 1.22.10 + resolve: 1.22.11 optionalDependencies: - rollup: 4.52.4 + rollup: 4.53.3 - '@rollup/pluginutils@5.2.0(rollup@4.52.4)': + '@rollup/pluginutils@5.2.0(rollup@4.53.3)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.52.4 + rollup: 4.53.3 - '@rollup/pluginutils@5.3.0(rollup@4.52.4)': + '@rollup/pluginutils@5.3.0(rollup@4.53.3)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.52.4 + rollup: 4.53.3 - '@rollup/rollup-android-arm-eabi@4.52.4': + '@rollup/rollup-android-arm-eabi@4.53.3': optional: true - '@rollup/rollup-android-arm64@4.52.4': + '@rollup/rollup-android-arm64@4.53.3': optional: true - '@rollup/rollup-darwin-arm64@4.52.4': + '@rollup/rollup-darwin-arm64@4.53.3': optional: true - '@rollup/rollup-darwin-x64@4.52.4': + '@rollup/rollup-darwin-x64@4.53.3': optional: true - '@rollup/rollup-freebsd-arm64@4.52.4': + '@rollup/rollup-freebsd-arm64@4.53.3': optional: true - '@rollup/rollup-freebsd-x64@4.52.4': + '@rollup/rollup-freebsd-x64@4.53.3': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.4': + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.4': + '@rollup/rollup-linux-arm-musleabihf@4.53.3': optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.4': + '@rollup/rollup-linux-arm64-gnu@4.53.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.52.4': + '@rollup/rollup-linux-arm64-musl@4.53.3': optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.4': + '@rollup/rollup-linux-loong64-gnu@4.53.3': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.4': + '@rollup/rollup-linux-ppc64-gnu@4.53.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.4': + '@rollup/rollup-linux-riscv64-gnu@4.53.3': optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.4': + '@rollup/rollup-linux-riscv64-musl@4.53.3': optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.4': + '@rollup/rollup-linux-s390x-gnu@4.53.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.52.4': + '@rollup/rollup-linux-x64-gnu@4.53.3': optional: true - '@rollup/rollup-linux-x64-musl@4.52.4': + '@rollup/rollup-linux-x64-musl@4.53.3': optional: true - '@rollup/rollup-openharmony-arm64@4.52.4': + '@rollup/rollup-openharmony-arm64@4.53.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.4': + '@rollup/rollup-win32-arm64-msvc@4.53.3': optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.4': + '@rollup/rollup-win32-ia32-msvc@4.53.3': optional: true - '@rollup/rollup-win32-x64-gnu@4.52.4': + '@rollup/rollup-win32-x64-gnu@4.53.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.52.4': + '@rollup/rollup-win32-x64-msvc@4.53.3': optional: true - '@schematics/angular@21.0.0-next.8(chokidar@4.0.3)': + '@schematics/angular@21.0.3(chokidar@4.0.3)': dependencies: - '@angular-devkit/core': 21.0.0-next.8(chokidar@4.0.3) - '@angular-devkit/schematics': 21.0.0-next.8(chokidar@4.0.3) + '@angular-devkit/core': 21.0.3(chokidar@4.0.3) + '@angular-devkit/schematics': 21.0.3(chokidar@4.0.3) jsonc-parser: 3.3.1 transitivePeerDependencies: - chokidar - '@sentry/core@9.46.0': {} + '@sentry/core@9.47.1': {} - '@sentry/node-core@9.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0)': + '@sentry/node-core@9.47.1(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.0) @@ -12953,12 +13570,12 @@ snapshots: '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 - '@sentry/core': 9.46.0 - '@sentry/opentelemetry': 9.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0) - import-in-the-middle: 1.14.4 + '@opentelemetry/semantic-conventions': 1.38.0 + '@sentry/core': 9.47.1 + '@sentry/opentelemetry': 9.47.1(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) + import-in-the-middle: 1.15.0 - '@sentry/node@9.46.0': + '@sentry/node@9.47.1': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.0) @@ -12988,24 +13605,24 @@ snapshots: '@opentelemetry/instrumentation-undici': 0.10.1(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 + '@opentelemetry/semantic-conventions': 1.38.0 '@prisma/instrumentation': 6.11.1(@opentelemetry/api@1.9.0) - '@sentry/core': 9.46.0 - '@sentry/node-core': 9.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0) - '@sentry/opentelemetry': 9.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0) - import-in-the-middle: 1.14.4 + '@sentry/core': 9.47.1 + '@sentry/node-core': 9.47.1(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) + '@sentry/opentelemetry': 9.47.1(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) + import-in-the-middle: 1.15.0 minimatch: 9.0.5 transitivePeerDependencies: - supports-color - '@sentry/opentelemetry@9.46.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.37.0)': + '@sentry/opentelemetry@9.47.1(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.37.0 - '@sentry/core': 9.46.0 + '@opentelemetry/semantic-conventions': 1.38.0 + '@sentry/core': 9.47.1 '@sigstore/bundle@4.0.0': dependencies: @@ -13020,7 +13637,7 @@ snapshots: '@sigstore/bundle': 4.0.0 '@sigstore/core': 3.0.0 '@sigstore/protobuf-specs': 0.5.0 - make-fetch-happen: 15.0.2 + make-fetch-happen: 15.0.3 proc-log: 5.0.0 promise-retry: 2.0.1 transitivePeerDependencies: @@ -13043,7 +13660,7 @@ snapshots: '@so-ric/colorspace@1.1.6': dependencies: - color: 5.0.2 + color: 5.0.3 text-hex: 1.0.0 '@socket.io/component-emitter@3.1.2': {} @@ -13054,7 +13671,7 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} - '@tsconfig/node10@1.0.11': {} + '@tsconfig/node10@1.0.12': {} '@tsconfig/node12@1.0.11': {} @@ -13076,58 +13693,58 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/big.js@6.2.2': {} '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/bonjour@3.5.13': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/caseless@0.12.5': {} '@types/cli-progress@3.11.6': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/connect-history-api-fallback@1.5.4': dependencies: - '@types/express-serve-static-core': 4.19.6 - '@types/node': 22.18.8 + '@types/express-serve-static-core': 4.19.7 + '@types/node': 22.19.2 '@types/connect@3.4.38': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/cors@2.8.19': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@types/duplexify@3.6.4': + '@types/duplexify@3.6.5': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/ejs@3.1.5': {} @@ -13145,50 +13762,48 @@ snapshots: '@types/events@3.0.3': {} - '@types/express-serve-static-core@4.19.6': + '@types/express-serve-static-core@4.19.7': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 - '@types/send': 1.2.0 + '@types/send': 1.2.1 - '@types/express@4.17.23': + '@types/express@4.17.25': dependencies: '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 4.19.6 + '@types/express-serve-static-core': 4.19.7 '@types/qs': 6.14.0 - '@types/serve-static': 1.15.9 + '@types/serve-static': 1.15.10 '@types/folder-hash@4.0.4': {} '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@types/git-raw-commits@5.0.0': + '@types/git-raw-commits@5.0.1': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/google.maps@3.58.1': {} '@types/http-errors@2.0.5': {} - '@types/http-proxy@1.17.16': + '@types/http-proxy@1.17.17': dependencies: - '@types/node': 22.18.8 - - '@types/jasmine@5.1.11': {} + '@types/node': 22.19.2 '@types/jasmine@5.1.12': {} - '@types/jasmine@5.1.9': {} + '@types/jasmine@5.1.13': {} '@types/json-schema@7.0.15': {} '@types/jsonfile@6.1.4': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/long@4.0.2': {} @@ -13200,19 +13815,19 @@ snapshots: '@types/mysql@2.15.26': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/node-forge@1.3.14': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@types/node@22.18.8': + '@types/node@22.19.2': dependencies: undici-types: 6.21.0 - '@types/node@24.8.1': + '@types/node@24.10.4': dependencies: - undici-types: 7.14.0 + undici-types: 7.16.0 '@types/normalize-package-data@2.4.4': {} @@ -13224,14 +13839,14 @@ snapshots: '@types/pg@8.6.1': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 pg-protocol: 1.10.3 pg-types: 2.2.0 - '@types/pumpify@1.4.4': + '@types/pumpify@1.4.5': dependencies: - '@types/duplexify': 3.6.4 - '@types/node': 22.18.8 + '@types/duplexify': 3.6.5 + '@types/node': 22.19.2 '@types/q@0.0.32': {} @@ -13242,7 +13857,7 @@ snapshots: '@types/request@2.48.13': dependencies: '@types/caseless': 0.12.5 - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/tough-cookie': 4.0.5 form-data: 2.5.5 @@ -13254,41 +13869,41 @@ snapshots: '@types/semver@7.7.1': {} - '@types/send@0.17.5': + '@types/send@0.17.6': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.18.8 + '@types/node': 22.19.2 - '@types/send@1.2.0': + '@types/send@1.2.1': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/serve-index@1.9.4': dependencies: - '@types/express': 4.17.23 + '@types/express': 4.17.25 - '@types/serve-static@1.15.9': + '@types/serve-static@1.15.10': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 22.18.8 - '@types/send': 0.17.5 + '@types/node': 22.19.2 + '@types/send': 0.17.6 '@types/shelljs@0.8.17': dependencies: - '@types/node': 22.18.8 - glob: 11.0.3 + '@types/node': 22.19.2 + glob: 11.1.0 '@types/shimmer@1.2.0': {} '@types/sockjs@0.3.36': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/stack-trace@0.0.33': {} '@types/tedious@4.0.14': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/tough-cookie@4.0.5': {} @@ -13304,7 +13919,7 @@ snapshots: '@types/vfile@3.0.2': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/unist': 2.0.11 '@types/vfile-message': 2.0.0 @@ -13312,11 +13927,11 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 '@types/yargs-parser@21.0.3': {} - '@types/yargs@17.0.33': + '@types/yargs@17.0.35': dependencies: '@types/yargs-parser': 21.0.3 @@ -13324,14 +13939,14 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 optional: true '@types/youtube@0.1.2': {} - '@vitejs/plugin-basic-ssl@2.1.0(vite@7.1.10(@types/node@22.18.8)(jiti@2.6.1)(less@4.4.2)(sass@1.93.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@vitejs/plugin-basic-ssl@2.1.0(vite@7.2.2(@types/node@22.19.2)(jiti@2.6.1)(less@4.4.2)(sass@1.93.2)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - vite: 7.1.10(@types/node@22.18.8)(jiti@2.6.1)(less@4.4.2)(sass@1.93.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.2.2(@types/node@22.19.2)(jiti@2.6.1)(less@4.4.2)(sass@1.93.2)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.2) '@webassemblyjs/ast@1.14.1': dependencies: @@ -13421,7 +14036,10 @@ snapshots: abbrev@1.0.9: {} - abbrev@3.0.1: {} + abbrev@3.0.1: + optional: true + + abbrev@4.0.0: {} abort-controller@3.0.0: dependencies: @@ -13434,7 +14052,7 @@ snapshots: accepts@2.0.0: dependencies: - mime-types: 3.0.1 + mime-types: 3.0.2 negotiator: 1.0.0 acorn-import-attributes@1.9.5(acorn@8.15.0): @@ -13503,22 +14121,22 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - algoliasearch@5.40.0: - dependencies: - '@algolia/abtesting': 1.6.0 - '@algolia/client-abtesting': 5.40.0 - '@algolia/client-analytics': 5.40.0 - '@algolia/client-common': 5.40.0 - '@algolia/client-insights': 5.40.0 - '@algolia/client-personalization': 5.40.0 - '@algolia/client-query-suggestions': 5.40.0 - '@algolia/client-search': 5.40.0 - '@algolia/ingestion': 1.40.0 - '@algolia/monitoring': 1.40.0 - '@algolia/recommend': 5.40.0 - '@algolia/requester-browser-xhr': 5.40.0 - '@algolia/requester-fetch': 5.40.0 - '@algolia/requester-node-http': 5.40.0 + algoliasearch@5.40.1: + dependencies: + '@algolia/abtesting': 1.6.1 + '@algolia/client-abtesting': 5.40.1 + '@algolia/client-analytics': 5.40.1 + '@algolia/client-common': 5.40.1 + '@algolia/client-insights': 5.40.1 + '@algolia/client-personalization': 5.40.1 + '@algolia/client-query-suggestions': 5.40.1 + '@algolia/client-search': 5.40.1 + '@algolia/ingestion': 1.40.1 + '@algolia/monitoring': 1.40.1 + '@algolia/recommend': 5.40.1 + '@algolia/requester-browser-xhr': 5.40.1 + '@algolia/requester-fetch': 5.40.1 + '@algolia/requester-node-http': 5.40.1 amdefine@1.0.1: optional: true @@ -13529,7 +14147,7 @@ snapshots: ansi-colors@4.1.3: {} - ansi-escapes@7.1.1: + ansi-escapes@7.2.0: dependencies: environment: 1.1.0 @@ -13553,8 +14171,6 @@ snapshots: ansi-styles@6.2.3: {} - ansis@4.2.0: {} - any-promise@1.3.0: {} anymatch@3.1.3: @@ -13564,7 +14180,7 @@ snapshots: archiver-utils@5.0.2: dependencies: - glob: 10.4.5 + glob: 10.5.0 graceful-fs: 4.2.11 is-stream: 2.0.1 lazystream: 1.0.1 @@ -13582,6 +14198,7 @@ snapshots: tar-stream: 3.1.7 zip-stream: 6.0.1 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a arg@4.1.3: {} @@ -13655,21 +14272,31 @@ snapshots: asynckit@0.4.0: {} - atomically@2.0.3: + atomically@2.1.0: dependencies: - stubborn-fs: 1.2.5 - when-exit: 2.1.4 + stubborn-fs: 2.0.0 + when-exit: 2.1.5 autoprefixer@10.4.21(postcss@8.5.6): dependencies: - browserslist: 4.26.3 - caniuse-lite: 1.0.30001747 + browserslist: 4.28.1 + caniuse-lite: 1.0.30001760 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 postcss: 8.5.6 postcss-value-parser: 4.2.0 + autoprefixer@10.4.22(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001760 + fraction.js: 5.3.4 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 @@ -13678,21 +14305,19 @@ snapshots: aws4@1.13.2: {} - axe-core@4.10.3: {} - axe-core@4.11.0: {} b4a@1.7.3: {} - babel-loader@10.0.0(@babel/core@7.28.4)(webpack@5.102.1(esbuild@0.25.10)): + babel-loader@10.0.0(@babel/core@7.28.4)(webpack@5.102.1(esbuild@0.26.0)): dependencies: '@babel/core': 7.28.4 find-up: 5.0.0 - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.4): dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/core': 7.28.4 '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) semver: 6.3.1 @@ -13703,7 +14328,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) - core-js-compat: 3.45.1 + core-js-compat: 3.47.0 transitivePeerDependencies: - supports-color @@ -13720,16 +14345,17 @@ snapshots: balanced-match@2.0.0: {} - bare-events@2.7.0: {} + bare-events@2.8.2: {} - bare-fs@4.4.5: + bare-fs@4.5.2: dependencies: - bare-events: 2.7.0 + bare-events: 2.8.2 bare-path: 3.0.0 - bare-stream: 2.7.0(bare-events@2.7.0) - bare-url: 2.2.2 + bare-stream: 2.7.0(bare-events@2.8.2) + bare-url: 2.3.2 fast-fifo: 1.3.2 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a optional: true @@ -13741,16 +14367,17 @@ snapshots: bare-os: 3.6.2 optional: true - bare-stream@2.7.0(bare-events@2.7.0): + bare-stream@2.7.0(bare-events@2.8.2): dependencies: streamx: 2.23.0 optionalDependencies: - bare-events: 2.7.0 + bare-events: 2.8.2 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a optional: true - bare-url@2.2.2: + bare-url@2.3.2: dependencies: bare-path: 3.0.0 optional: true @@ -13759,7 +14386,7 @@ snapshots: base64id@2.0.0: {} - baseline-browser-mapping@2.8.12: {} + baseline-browser-mapping@2.9.5: {} basic-auth-connect@1.1.0: dependencies: @@ -13814,33 +14441,33 @@ snapshots: dependencies: minimist: 1.2.8 - body-parser@1.20.3: + body-parser@1.20.4: dependencies: bytes: 3.1.2 content-type: 1.0.5 debug: 2.6.9 depd: 2.0.0 destroy: 1.2.0 - http-errors: 2.0.0 + http-errors: 2.0.1 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 + qs: 6.14.0 + raw-body: 2.5.3 type-is: 1.6.18 unpipe: 1.0.0 transitivePeerDependencies: - supports-color - body-parser@2.2.0: + body-parser@2.2.1: dependencies: bytes: 3.1.2 content-type: 1.0.5 debug: 4.4.3(supports-color@10.2.2) - http-errors: 2.0.0 - iconv-lite: 0.6.3 + http-errors: 2.0.1 + iconv-lite: 0.7.0 on-finished: 2.4.1 qs: 6.14.0 - raw-body: 3.0.1 + raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: - supports-color @@ -13876,13 +14503,13 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.26.3: + browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.8.12 - caniuse-lite: 1.0.30001747 - electron-to-chromium: 1.5.230 - node-releases: 2.0.23 - update-browserslist-db: 1.1.3(browserslist@4.26.3) + baseline-browser-mapping: 2.9.5 + caniuse-lite: 1.0.30001760 + electron-to-chromium: 1.5.267 + node-releases: 2.0.27 + update-browserslist-db: 1.2.2(browserslist@4.28.1) browserstack-local@1.5.8: dependencies: @@ -13942,30 +14569,31 @@ snapshots: dependencies: '@npmcli/fs': 4.0.0 fs-minipass: 3.0.3 - glob: 10.4.5 + glob: 10.5.0 lru-cache: 10.4.3 minipass: 7.1.2 minipass-collect: 2.0.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 - p-map: 7.0.3 + p-map: 7.0.4 ssri: 12.0.0 - tar: 7.5.1 + tar: 7.5.2 unique-filename: 4.0.0 + optional: true - cacache@20.0.1: + cacache@20.0.3: dependencies: - '@npmcli/fs': 4.0.0 + '@npmcli/fs': 5.0.0 fs-minipass: 3.0.3 - glob: 11.0.3 - lru-cache: 11.2.2 + glob: 13.0.0 + lru-cache: 11.2.4 minipass: 7.1.2 minipass-collect: 2.0.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 - p-map: 7.0.3 - ssri: 12.0.0 - unique-filename: 4.0.0 + p-map: 7.0.4 + ssri: 13.0.0 + unique-filename: 5.0.0 call-bind-apply-helpers@1.0.2: dependencies: @@ -14003,7 +14631,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001747: {} + caniuse-lite@1.0.30001760: {} canonical-path@0.0.2: {} @@ -14065,11 +14693,11 @@ snapshots: character-entities-legacy@1.1.4: {} - chardet@2.1.0: {} + chardet@2.1.1: {} checkpoint-stream@0.1.2: dependencies: - '@types/pumpify': 1.4.4 + '@types/pumpify': 1.4.5 events-intercept: 2.0.0 pumpify: 1.5.1 split-array-stream: 1.0.3 @@ -14097,7 +14725,7 @@ snapshots: chrome-launcher@1.2.1: dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 2.0.2 @@ -14106,9 +14734,9 @@ snapshots: chrome-trace-event@1.0.4: {} - chromium-bidi@9.1.0(devtools-protocol@0.0.1508733): + chromium-bidi@11.0.0(devtools-protocol@0.0.1534754): dependencies: - devtools-protocol: 0.0.1508733 + devtools-protocol: 0.0.1534754 mitt: 3.0.1 zod: 3.25.76 @@ -14153,7 +14781,7 @@ snapshots: optionalDependencies: '@colors/colors': 1.5.0 - cli-truncate@5.1.0: + cli-truncate@5.1.1: dependencies: slice-ansi: 7.1.2 string-width: 8.1.0 @@ -14202,24 +14830,24 @@ snapshots: dependencies: color-name: 1.1.4 - color-convert@3.1.2: + color-convert@3.1.3: dependencies: - color-name: 2.0.2 + color-name: 2.1.0 color-name@1.1.3: {} color-name@1.1.4: {} - color-name@2.0.2: {} + color-name@2.1.0: {} - color-string@2.1.2: + color-string@2.1.4: dependencies: - color-name: 2.0.2 + color-name: 2.1.0 - color@5.0.2: + color@5.0.3: dependencies: - color-convert: 3.1.2 - color-string: 2.1.2 + color-convert: 3.1.3 + color-string: 2.1.4 colord@2.9.3: {} @@ -14289,7 +14917,7 @@ snapshots: configstore@7.1.0: dependencies: - atomically: 2.0.3 + atomically: 2.1.0 dot-prop: 9.0.0 graceful-fs: 4.2.11 xdg-basedir: 5.1.0 @@ -14325,15 +14953,13 @@ snapshots: dependencies: safe-buffer: 5.2.1 - content-disposition@1.0.0: - dependencies: - safe-buffer: 5.2.1 + content-disposition@1.0.1: {} content-type@1.0.5: {} conventional-commits-filter@5.0.0: {} - conventional-commits-parser@6.2.0: + conventional-commits-parser@6.2.1: dependencies: meow: 13.2.0 @@ -14341,30 +14967,28 @@ snapshots: convert-source-map@2.0.0: {} - cookie-signature@1.0.6: {} + cookie-signature@1.0.7: {} cookie-signature@1.2.2: {} - cookie@0.7.1: {} - cookie@0.7.2: {} copy-anything@2.0.6: dependencies: is-what: 3.14.1 - copy-webpack-plugin@13.0.1(webpack@5.102.1(esbuild@0.25.10)): + copy-webpack-plugin@13.0.1(webpack@5.102.1(esbuild@0.26.0)): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 schema-utils: 4.3.3 serialize-javascript: 6.0.2 tinyglobby: 0.2.15 - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) - core-js-compat@3.45.1: + core-js-compat@3.47.0: dependencies: - browserslist: 4.26.3 + browserslist: 4.28.1 core-util-is@1.0.2: {} @@ -14387,7 +15011,7 @@ snapshots: dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 - js-yaml: 4.1.0 + js-yaml: 4.1.1 parse-json: 5.2.0 optionalDependencies: typescript: 5.9.2 @@ -14425,7 +15049,7 @@ snapshots: css-functions-list@3.2.3: {} - css-loader@7.1.2(webpack@5.102.1(esbuild@0.25.10)): + css-loader@7.1.2(webpack@5.102.1(esbuild@0.26.0)): dependencies: icss-utils: 5.1.0(postcss@8.5.6) postcss: 8.5.6 @@ -14436,7 +15060,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.3 optionalDependencies: - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) css-select@6.0.0: dependencies: @@ -14538,12 +15162,12 @@ snapshots: deepmerge@4.3.1: {} - default-browser-id@5.0.0: {} + default-browser-id@5.0.1: {} - default-browser@5.2.1: + default-browser@5.4.0: dependencies: bundle-name: 4.1.0 - default-browser-id: 5.0.0 + default-browser-id: 5.0.1 defaults@1.0.4: dependencies: @@ -14596,15 +15220,15 @@ snapshots: detect-libc@1.0.3: optional: true - detect-libc@2.1.1: + detect-libc@2.1.2: optional: true detect-node@2.1.0: {} - devtools-protocol@0.0.1508733: {} - devtools-protocol@0.0.1527314: {} + devtools-protocol@0.0.1534754: {} + dgeni-packages@0.30.0(dgeni@0.4.14): dependencies: canonical-path: 1.0.0 @@ -14748,9 +15372,9 @@ snapshots: dependencies: jake: 10.9.4 - electron-to-chromium@1.5.230: {} + electron-to-chromium@1.5.267: {} - emoji-regex@10.5.0: {} + emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} @@ -14779,7 +15403,7 @@ snapshots: engine.io@6.6.4(bufferutil@4.0.9): dependencies: '@types/cors': 2.8.19 - '@types/node': 22.18.8 + '@types/node': 22.19.2 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.7.2 @@ -14918,36 +15542,94 @@ snapshots: dependencies: es6-promise: 4.2.8 - esbuild-wasm@0.25.10: {} + esbuild-wasm@0.26.0: {} - esbuild@0.25.10: + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + esbuild@0.26.0: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.10 - '@esbuild/android-arm': 0.25.10 - '@esbuild/android-arm64': 0.25.10 - '@esbuild/android-x64': 0.25.10 - '@esbuild/darwin-arm64': 0.25.10 - '@esbuild/darwin-x64': 0.25.10 - '@esbuild/freebsd-arm64': 0.25.10 - '@esbuild/freebsd-x64': 0.25.10 - '@esbuild/linux-arm': 0.25.10 - '@esbuild/linux-arm64': 0.25.10 - '@esbuild/linux-ia32': 0.25.10 - '@esbuild/linux-loong64': 0.25.10 - '@esbuild/linux-mips64el': 0.25.10 - '@esbuild/linux-ppc64': 0.25.10 - '@esbuild/linux-riscv64': 0.25.10 - '@esbuild/linux-s390x': 0.25.10 - '@esbuild/linux-x64': 0.25.10 - '@esbuild/netbsd-arm64': 0.25.10 - '@esbuild/netbsd-x64': 0.25.10 - '@esbuild/openbsd-arm64': 0.25.10 - '@esbuild/openbsd-x64': 0.25.10 - '@esbuild/openharmony-arm64': 0.25.10 - '@esbuild/sunos-x64': 0.25.10 - '@esbuild/win32-arm64': 0.25.10 - '@esbuild/win32-ia32': 0.25.10 - '@esbuild/win32-x64': 0.25.10 + '@esbuild/aix-ppc64': 0.26.0 + '@esbuild/android-arm': 0.26.0 + '@esbuild/android-arm64': 0.26.0 + '@esbuild/android-x64': 0.26.0 + '@esbuild/darwin-arm64': 0.26.0 + '@esbuild/darwin-x64': 0.26.0 + '@esbuild/freebsd-arm64': 0.26.0 + '@esbuild/freebsd-x64': 0.26.0 + '@esbuild/linux-arm': 0.26.0 + '@esbuild/linux-arm64': 0.26.0 + '@esbuild/linux-ia32': 0.26.0 + '@esbuild/linux-loong64': 0.26.0 + '@esbuild/linux-mips64el': 0.26.0 + '@esbuild/linux-ppc64': 0.26.0 + '@esbuild/linux-riscv64': 0.26.0 + '@esbuild/linux-s390x': 0.26.0 + '@esbuild/linux-x64': 0.26.0 + '@esbuild/netbsd-arm64': 0.26.0 + '@esbuild/netbsd-x64': 0.26.0 + '@esbuild/openbsd-arm64': 0.26.0 + '@esbuild/openbsd-x64': 0.26.0 + '@esbuild/openharmony-arm64': 0.26.0 + '@esbuild/sunos-x64': 0.26.0 + '@esbuild/win32-arm64': 0.26.0 + '@esbuild/win32-ia32': 0.26.0 + '@esbuild/win32-x64': 0.26.0 + + esbuild@0.27.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.1 + '@esbuild/android-arm': 0.27.1 + '@esbuild/android-arm64': 0.27.1 + '@esbuild/android-x64': 0.27.1 + '@esbuild/darwin-arm64': 0.27.1 + '@esbuild/darwin-x64': 0.27.1 + '@esbuild/freebsd-arm64': 0.27.1 + '@esbuild/freebsd-x64': 0.27.1 + '@esbuild/linux-arm': 0.27.1 + '@esbuild/linux-arm64': 0.27.1 + '@esbuild/linux-ia32': 0.27.1 + '@esbuild/linux-loong64': 0.27.1 + '@esbuild/linux-mips64el': 0.27.1 + '@esbuild/linux-ppc64': 0.27.1 + '@esbuild/linux-riscv64': 0.27.1 + '@esbuild/linux-s390x': 0.27.1 + '@esbuild/linux-x64': 0.27.1 + '@esbuild/netbsd-arm64': 0.27.1 + '@esbuild/netbsd-x64': 0.27.1 + '@esbuild/openbsd-arm64': 0.27.1 + '@esbuild/openbsd-x64': 0.27.1 + '@esbuild/openharmony-arm64': 0.27.1 + '@esbuild/sunos-x64': 0.27.1 + '@esbuild/win32-arm64': 0.27.1 + '@esbuild/win32-ia32': 0.27.1 + '@esbuild/win32-x64': 0.27.1 escalade@3.2.0: {} @@ -15035,7 +15717,9 @@ snapshots: events-universal@1.0.1: dependencies: - bare-events: 2.7.0 + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller events@3.3.0: {} @@ -15068,83 +15752,84 @@ snapshots: '@apidevtools/json-schema-ref-parser': 9.1.2 ajv: 8.17.1 ajv-formats: 2.1.1(ajv@8.17.1) - body-parser: 1.20.3 + body-parser: 1.20.4 content-type: 1.0.5 deep-freeze: 0.0.1 events-listener: 1.1.0 - glob: 10.4.5 + glob: 10.5.0 json-ptr: 3.1.1 json-schema-traverse: 1.0.0 lodash: 4.17.21 openapi3-ts: 3.2.0 promise-breaker: 6.0.0 qs: 6.14.0 - raw-body: 2.5.2 + raw-body: 2.5.3 semver: 7.7.3 transitivePeerDependencies: - supports-color exit@0.1.2: {} - exponential-backoff@3.1.2: {} + exponential-backoff@3.1.3: {} - express-rate-limit@7.5.1(express@5.1.0): + express-rate-limit@7.5.1(express@5.2.1): dependencies: - express: 5.1.0 + express: 5.2.1 - express@4.21.2: + express@4.22.1: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.3 + body-parser: 1.20.4 content-disposition: 0.5.4 content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.0.6 + cookie: 0.7.2 + cookie-signature: 1.0.7 debug: 2.6.9 depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.3.1 + finalhandler: 1.3.2 fresh: 0.5.2 - http-errors: 2.0.0 + http-errors: 2.0.1 merge-descriptors: 1.0.3 methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 path-to-regexp: 0.1.12 proxy-addr: 2.0.7 - qs: 6.13.0 + qs: 6.14.0 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.19.0 + send: 0.19.1 serve-static: 1.16.2 setprototypeof: 1.2.0 - statuses: 2.0.1 + statuses: 2.0.2 type-is: 1.6.18 utils-merge: 1.0.1 vary: 1.1.2 transitivePeerDependencies: - supports-color - express@5.1.0: + express@5.2.1: dependencies: accepts: 2.0.0 - body-parser: 2.2.0 - content-disposition: 1.0.0 + body-parser: 2.2.1 + content-disposition: 1.0.1 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 debug: 4.4.3(supports-color@10.2.2) + depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 2.1.0 + finalhandler: 2.1.1 fresh: 2.0.0 - http-errors: 2.0.0 + http-errors: 2.0.1 merge-descriptors: 2.0.0 - mime-types: 3.0.1 + mime-types: 3.0.2 on-finished: 2.4.1 once: 1.4.0 parseurl: 1.3.3 @@ -15247,19 +15932,19 @@ snapshots: transitivePeerDependencies: - supports-color - finalhandler@1.3.1: + finalhandler@1.3.2: dependencies: debug: 2.6.9 encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 - statuses: 2.0.1 + statuses: 2.0.2 unpipe: 1.0.0 transitivePeerDependencies: - supports-color - finalhandler@2.1.0: + finalhandler@2.1.1: dependencies: debug: 4.4.3(supports-color@10.2.2) encodeurl: 2.0.0 @@ -15280,107 +15965,22 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - firebase-tools@14.17.0(@types/node@22.18.8)(bufferutil@4.0.9)(encoding@0.1.13): - dependencies: - '@electric-sql/pglite': 0.3.10 - '@electric-sql/pglite-tools': 0.2.15(@electric-sql/pglite@0.3.10) - '@google-cloud/cloud-sql-connector': 1.8.3 - '@google-cloud/pubsub': 4.11.0(encoding@0.1.13) - '@inquirer/prompts': 7.8.6(@types/node@22.18.8) - '@modelcontextprotocol/sdk': 1.19.1 - abort-controller: 3.0.0 - ajv: 8.17.1 - ajv-formats: 3.0.1 - archiver: 7.0.1 - async-lock: 1.4.1 - body-parser: 1.20.3 - chokidar: 3.6.0 - cjson: 0.3.3 - cli-table3: 0.6.5 - colorette: 2.0.20 - commander: 5.1.0 - configstore: 5.0.1 - cors: 2.8.5 - cross-env: 7.0.3 - cross-spawn: 7.0.6 - csv-parse: 5.6.0 - deep-equal-in-any-order: 2.1.0 - exegesis: 4.3.0 - exegesis-express: 4.0.0 - express: 4.21.2 - filesize: 6.4.0 - form-data: 4.0.4 - fs-extra: 10.1.0 - fuzzy: 0.1.3 - gaxios: 6.7.1(encoding@0.1.13)(supports-color@10.2.2) - glob: 10.4.5 - google-auth-library: 9.15.1(encoding@0.1.13)(supports-color@10.2.2) - ignore: 7.0.5 - js-yaml: 3.14.1 - jsonwebtoken: 9.0.2 - leven: 3.1.0 - libsodium-wrappers: 0.7.15 - lodash: 4.17.21 - lsofi: 1.0.0 - marked: 13.0.3 - marked-terminal: 7.3.0(marked@13.0.3) - mime: 2.6.0 - minimatch: 3.1.2 - morgan: 1.10.1 - node-fetch: 2.7.0(encoding@0.1.13) - open: 6.4.0 - ora: 5.4.1 - p-limit: 3.1.0 - pg: 8.16.3 - pg-gateway: 0.3.0-beta.4 - pglite-2: '@electric-sql/pglite@0.2.17' - portfinder: 1.0.38 - progress: 2.0.3 - proxy-agent: 6.5.0 - retry: 0.13.1 - semver: 7.7.2 - sql-formatter: 15.6.10 - stream-chain: 2.2.5 - stream-json: 1.9.1 - superstatic: 9.2.0(encoding@0.1.13) - tar: 6.2.1 - tcp-port-used: 1.0.2 - tmp: 0.2.5 - triple-beam: 1.4.1 - universal-analytics: 0.5.3 - update-notifier-cjs: 5.1.7(encoding@0.1.13) - uuid: 8.3.2 - winston: 3.18.3 - winston-transport: 4.9.0 - ws: 7.5.10(bufferutil@4.0.9) - yaml: 2.8.1 - zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) - transitivePeerDependencies: - - '@types/node' - - bufferutil - - encoding - - pg-native - - react-native-b4a - - supports-color - - utf-8-validate - - firebase-tools@14.20.0(@types/node@22.18.8)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2): + firebase-tools@14.20.0(@types/node@22.19.2)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2): dependencies: - '@apphosting/build': 0.1.6(@types/node@22.18.8)(typescript@5.9.2) + '@apphosting/build': 0.1.7(@types/node@22.19.2)(typescript@5.9.2) '@apphosting/common': 0.0.8 - '@electric-sql/pglite': 0.3.10 - '@electric-sql/pglite-tools': 0.2.15(@electric-sql/pglite@0.3.10) - '@google-cloud/cloud-sql-connector': 1.8.3 + '@electric-sql/pglite': 0.3.14 + '@electric-sql/pglite-tools': 0.2.19(@electric-sql/pglite@0.3.14) + '@google-cloud/cloud-sql-connector': 1.8.4 '@google-cloud/pubsub': 4.11.0(encoding@0.1.13) - '@inquirer/prompts': 7.9.0(@types/node@22.18.8) - '@modelcontextprotocol/sdk': 1.20.0 + '@inquirer/prompts': 7.10.1(@types/node@22.19.2) + '@modelcontextprotocol/sdk': 1.24.3 abort-controller: 3.0.0 ajv: 8.17.1 ajv-formats: 3.0.1 archiver: 7.0.1 async-lock: 1.4.1 - body-parser: 1.20.3 + body-parser: 1.20.4 chokidar: 3.6.0 cjson: 0.3.3 cli-table3: 0.6.5 @@ -15394,17 +15994,17 @@ snapshots: deep-equal-in-any-order: 2.1.0 exegesis: 4.3.0 exegesis-express: 4.0.0 - express: 4.21.2 + express: 4.22.1 filesize: 6.4.0 - form-data: 4.0.4 + form-data: 4.0.5 fs-extra: 10.1.0 fuzzy: 0.1.3 - gaxios: 6.7.1(encoding@0.1.13)(supports-color@10.2.2) - glob: 10.4.5 - google-auth-library: 9.15.1(encoding@0.1.13)(supports-color@10.2.2) + gaxios: 6.7.1(encoding@0.1.13) + glob: 10.5.0 + google-auth-library: 9.15.1(encoding@0.1.13) ignore: 7.0.5 - js-yaml: 3.14.1 - jsonwebtoken: 9.0.2 + js-yaml: 3.14.2 + jsonwebtoken: 9.0.3 leven: 3.1.0 libsodium-wrappers: 0.7.15 lodash: 4.17.21 @@ -15437,16 +16037,18 @@ snapshots: universal-analytics: 0.5.3 update-notifier-cjs: 5.1.7(encoding@0.1.13) uuid: 8.3.2 - winston: 3.18.3 + winston: 3.19.0 winston-transport: 4.9.0 ws: 7.5.10(bufferutil@4.0.9) - yaml: 2.8.1 + yaml: 2.8.2 zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) + zod-to-json-schema: 3.25.0(zod@3.25.76) transitivePeerDependencies: + - '@cfworker/json-schema' - '@swc/core' - '@swc/wasm' - '@types/node' + - bare-abort-controller - bufferutil - encoding - pg-native @@ -15455,35 +16057,35 @@ snapshots: - typescript - utf-8-validate - firebase@12.4.0: + firebase@12.7.0: dependencies: - '@firebase/ai': 2.4.0(@firebase/app-types@0.9.3)(@firebase/app@0.14.4) - '@firebase/analytics': 0.10.19(@firebase/app@0.14.4) - '@firebase/analytics-compat': 0.2.25(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4) - '@firebase/app': 0.14.4 - '@firebase/app-check': 0.11.0(@firebase/app@0.14.4) - '@firebase/app-check-compat': 0.4.0(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4) - '@firebase/app-compat': 0.5.4 + '@firebase/ai': 2.6.1(@firebase/app-types@0.9.3)(@firebase/app@0.14.6) + '@firebase/analytics': 0.10.19(@firebase/app@0.14.6) + '@firebase/analytics-compat': 0.2.25(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6) + '@firebase/app': 0.14.6 + '@firebase/app-check': 0.11.0(@firebase/app@0.14.6) + '@firebase/app-check-compat': 0.4.0(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6) + '@firebase/app-compat': 0.5.6 '@firebase/app-types': 0.9.3 - '@firebase/auth': 1.11.0(@firebase/app@0.14.4) - '@firebase/auth-compat': 0.6.0(@firebase/app-compat@0.5.4)(@firebase/app-types@0.9.3)(@firebase/app@0.14.4) - '@firebase/data-connect': 0.3.11(@firebase/app@0.14.4) + '@firebase/auth': 1.12.0(@firebase/app@0.14.6) + '@firebase/auth-compat': 0.6.2(@firebase/app-compat@0.5.6)(@firebase/app-types@0.9.3)(@firebase/app@0.14.6) + '@firebase/data-connect': 0.3.12(@firebase/app@0.14.6) '@firebase/database': 1.1.0 '@firebase/database-compat': 2.1.0 - '@firebase/firestore': 4.9.2(@firebase/app@0.14.4) - '@firebase/firestore-compat': 0.4.2(@firebase/app-compat@0.5.4)(@firebase/app-types@0.9.3)(@firebase/app@0.14.4) - '@firebase/functions': 0.13.1(@firebase/app@0.14.4) - '@firebase/functions-compat': 0.4.1(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4) - '@firebase/installations': 0.6.19(@firebase/app@0.14.4) - '@firebase/installations-compat': 0.2.19(@firebase/app-compat@0.5.4)(@firebase/app-types@0.9.3)(@firebase/app@0.14.4) - '@firebase/messaging': 0.12.23(@firebase/app@0.14.4) - '@firebase/messaging-compat': 0.2.23(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4) - '@firebase/performance': 0.7.9(@firebase/app@0.14.4) - '@firebase/performance-compat': 0.2.22(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4) - '@firebase/remote-config': 0.7.0(@firebase/app@0.14.4) - '@firebase/remote-config-compat': 0.2.20(@firebase/app-compat@0.5.4)(@firebase/app@0.14.4) - '@firebase/storage': 0.14.0(@firebase/app@0.14.4) - '@firebase/storage-compat': 0.4.0(@firebase/app-compat@0.5.4)(@firebase/app-types@0.9.3)(@firebase/app@0.14.4) + '@firebase/firestore': 4.9.3(@firebase/app@0.14.6) + '@firebase/firestore-compat': 0.4.3(@firebase/app-compat@0.5.6)(@firebase/app-types@0.9.3)(@firebase/app@0.14.6) + '@firebase/functions': 0.13.1(@firebase/app@0.14.6) + '@firebase/functions-compat': 0.4.1(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6) + '@firebase/installations': 0.6.19(@firebase/app@0.14.6) + '@firebase/installations-compat': 0.2.19(@firebase/app-compat@0.5.6)(@firebase/app-types@0.9.3)(@firebase/app@0.14.6) + '@firebase/messaging': 0.12.23(@firebase/app@0.14.6) + '@firebase/messaging-compat': 0.2.23(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6) + '@firebase/performance': 0.7.9(@firebase/app@0.14.6) + '@firebase/performance-compat': 0.2.22(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6) + '@firebase/remote-config': 0.7.0(@firebase/app@0.14.6) + '@firebase/remote-config-compat': 0.2.20(@firebase/app-compat@0.5.6)(@firebase/app@0.14.6) + '@firebase/storage': 0.14.0(@firebase/app@0.14.6) + '@firebase/storage-compat': 0.4.0(@firebase/app-compat@0.5.6)(@firebase/app-types@0.9.3)(@firebase/app@0.14.6) '@firebase/util': 1.13.0 transitivePeerDependencies: - '@react-native-async-storage/async-storage' @@ -15537,7 +16139,7 @@ snapshots: mime-types: 2.1.35 safe-buffer: 5.2.1 - form-data@4.0.4: + form-data@4.0.5: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 @@ -15555,6 +16157,8 @@ snapshots: fraction.js@4.3.7: {} + fraction.js@5.3.4: {} + fresh@0.5.2: {} fresh@2.0.0: {} @@ -15607,7 +16211,7 @@ snapshots: fuzzy@0.1.3: {} - gaxios@6.7.1(encoding@0.1.13)(supports-color@10.2.2): + gaxios@6.7.1(encoding@0.1.13): dependencies: extend: 3.0.2 https-proxy-agent: 7.0.6(supports-color@10.2.2) @@ -15618,11 +16222,12 @@ snapshots: - encoding - supports-color - gaxios@7.1.2(supports-color@10.2.2): + gaxios@7.1.3(supports-color@10.2.2): dependencies: extend: 3.0.2 https-proxy-agent: 7.0.6(supports-color@10.2.2) node-fetch: 3.3.2 + rimraf: 5.0.10 transitivePeerDependencies: - supports-color @@ -15630,19 +16235,19 @@ snapshots: dependencies: globule: 1.3.4 - gcp-metadata@6.1.1(encoding@0.1.13)(supports-color@10.2.2): + gcp-metadata@6.1.1(encoding@0.1.13): dependencies: - gaxios: 6.7.1(encoding@0.1.13)(supports-color@10.2.2) + gaxios: 6.7.1(encoding@0.1.13) google-logging-utils: 0.0.2 json-bigint: 1.0.0 transitivePeerDependencies: - encoding - supports-color - gcp-metadata@7.0.1(supports-color@10.2.2): + gcp-metadata@8.1.2(supports-color@10.2.2): dependencies: - gaxios: 7.1.2(supports-color@10.2.2) - google-logging-utils: 1.1.1 + gaxios: 7.1.3(supports-color@10.2.2) + google-logging-utils: 1.1.3 json-bigint: 1.0.0 transitivePeerDependencies: - supports-color @@ -15685,7 +16290,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-tsconfig@4.10.1: + get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -15701,9 +16306,9 @@ snapshots: dependencies: assert-plus: 1.0.0 - git-raw-commits@5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0): + git-raw-commits@5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.1): dependencies: - '@conventional-changelog/git-client': 1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0) + '@conventional-changelog/git-client': 1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.1) meow: 13.2.0 transitivePeerDependencies: - conventional-commits-filter @@ -15731,7 +16336,7 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@10.4.5: + glob@10.5.0: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 @@ -15740,14 +16345,20 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@11.0.3: + glob@11.1.0: dependencies: foreground-child: 3.3.1 jackspeak: 4.1.1 - minimatch: 10.0.3 + minimatch: 10.1.1 minipass: 7.1.2 package-json-from-dist: 1.0.1 - path-scurry: 2.0.0 + path-scurry: 2.0.1 + + glob@13.0.0: + dependencies: + minimatch: 10.1.1 + minipass: 7.1.2 + path-scurry: 2.0.1 glob@5.0.15: dependencies: @@ -15820,38 +16431,38 @@ snapshots: lodash: 4.17.21 minimatch: 3.0.8 - google-auth-library@10.4.0(supports-color@10.2.2): + google-auth-library@10.5.0(supports-color@10.2.2): dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 7.1.2(supports-color@10.2.2) - gcp-metadata: 7.0.1(supports-color@10.2.2) - google-logging-utils: 1.1.1 + gaxios: 7.1.3(supports-color@10.2.2) + gcp-metadata: 8.1.2(supports-color@10.2.2) + google-logging-utils: 1.1.3 gtoken: 8.0.0(supports-color@10.2.2) - jws: 4.0.0 + jws: 4.0.1 transitivePeerDependencies: - supports-color - google-auth-library@9.15.1(encoding@0.1.13)(supports-color@10.2.2): + google-auth-library@9.15.1(encoding@0.1.13): dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 6.7.1(encoding@0.1.13)(supports-color@10.2.2) - gcp-metadata: 6.1.1(encoding@0.1.13)(supports-color@10.2.2) - gtoken: 7.1.0(encoding@0.1.13)(supports-color@10.2.2) - jws: 4.0.0 + gaxios: 6.7.1(encoding@0.1.13) + gcp-metadata: 6.1.1(encoding@0.1.13) + gtoken: 7.1.0(encoding@0.1.13) + jws: 4.0.1 transitivePeerDependencies: - encoding - supports-color google-gax@4.6.1(encoding@0.1.13): dependencies: - '@grpc/grpc-js': 1.14.0 + '@grpc/grpc-js': 1.14.2 '@grpc/proto-loader': 0.7.15 '@types/long': 4.0.2 abort-controller: 3.0.0 duplexify: 4.1.3 - google-auth-library: 9.15.1(encoding@0.1.13)(supports-color@10.2.2) + google-auth-library: 9.15.1(encoding@0.1.13) node-fetch: 2.7.0(encoding@0.1.13) object-hash: 3.0.0 proto3-json-serializer: 2.0.2 @@ -15862,30 +16473,31 @@ snapshots: - encoding - supports-color - google-gax@5.0.4(supports-color@10.2.2): + google-gax@5.0.6(supports-color@10.2.2): dependencies: - '@grpc/grpc-js': 1.14.0 + '@grpc/grpc-js': 1.14.2 '@grpc/proto-loader': 0.8.0 duplexify: 4.1.3 - google-auth-library: 10.4.0(supports-color@10.2.2) - google-logging-utils: 1.1.1 + google-auth-library: 10.5.0(supports-color@10.2.2) + google-logging-utils: 1.1.3 node-fetch: 3.3.2 object-hash: 3.0.0 - proto3-json-serializer: 3.0.2 + proto3-json-serializer: 3.0.4 protobufjs: 7.5.4 retry-request: 8.0.2(supports-color@10.2.2) + rimraf: 5.0.10 transitivePeerDependencies: - supports-color google-logging-utils@0.0.2: {} - google-logging-utils@1.1.1: {} + google-logging-utils@1.1.3: {} googleapis-common@8.0.2-rc.0: dependencies: extend: 3.0.2 - gaxios: 7.1.2(supports-color@10.2.2) - google-auth-library: 10.4.0(supports-color@10.2.2) + gaxios: 7.1.3(supports-color@10.2.2) + google-auth-library: 10.5.0(supports-color@10.2.2) qs: 6.14.0 url-template: 2.0.8 transitivePeerDependencies: @@ -15897,30 +16509,30 @@ snapshots: graceful-fs@4.2.11: {} - graphql-tag@2.12.6(graphql@16.11.0): + graphql-tag@2.12.6(graphql@16.12.0): dependencies: - graphql: 16.11.0 + graphql: 16.12.0 tslib: 2.8.1 - graphql@16.11.0: {} + graphql@16.12.0: {} grpc-gcp@1.0.1: dependencies: - '@grpc/grpc-js': 1.14.0 + '@grpc/grpc-js': 1.14.2 protobufjs: 7.4.0 - gtoken@7.1.0(encoding@0.1.13)(supports-color@10.2.2): + gtoken@7.1.0(encoding@0.1.13): dependencies: - gaxios: 6.7.1(encoding@0.1.13)(supports-color@10.2.2) - jws: 4.0.0 + gaxios: 6.7.1(encoding@0.1.13) + jws: 4.0.1 transitivePeerDependencies: - encoding - supports-color gtoken@8.0.0(supports-color@10.2.2): dependencies: - gaxios: 7.1.2(supports-color@10.2.2) - jws: 4.0.0 + gaxios: 7.1.3(supports-color@10.2.2) + jws: 4.0.1 transitivePeerDependencies: - supports-color @@ -16031,9 +16643,9 @@ snapshots: dependencies: lru-cache: 10.4.3 - hosted-git-info@9.0.0: + hosted-git-info@9.0.2: dependencies: - lru-cache: 11.2.2 + lru-cache: 11.2.4 hpack.js@2.1.6: dependencies: @@ -16095,6 +16707,14 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + http-link-header@1.1.3: {} http-parser-js@0.5.10: {} @@ -16114,21 +16734,21 @@ snapshots: transitivePeerDependencies: - supports-color - http-proxy-middleware@2.0.9(@types/express@4.17.23): + http-proxy-middleware@2.0.9(@types/express@4.17.25): dependencies: - '@types/http-proxy': 1.17.16 + '@types/http-proxy': 1.17.17 http-proxy: 1.18.1(debug@4.4.3) is-glob: 4.0.3 is-plain-obj: 3.0.0 micromatch: 4.0.8 optionalDependencies: - '@types/express': 4.17.23 + '@types/express': 4.17.25 transitivePeerDependencies: - debug http-proxy-middleware@3.0.5: dependencies: - '@types/http-proxy': 1.17.16 + '@types/http-proxy': 1.17.17 debug: 4.4.3(supports-color@10.2.2) http-proxy: 1.18.1(debug@4.4.3) is-glob: 4.0.3 @@ -16200,7 +16820,7 @@ snapshots: ignore-walk@8.0.0: dependencies: - minimatch: 10.0.3 + minimatch: 10.1.1 ignore@5.3.2: {} @@ -16213,14 +16833,14 @@ snapshots: immediate@3.0.6: {} - immutable@5.1.3: {} + immutable@5.1.4: {} import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - import-in-the-middle@1.14.4: + import-in-the-middle@1.15.0: dependencies: acorn: 8.15.0 acorn-import-attributes: 1.9.5(acorn@8.15.0) @@ -16252,6 +16872,8 @@ snapshots: ini@5.0.0: {} + ini@6.0.0: {} + install-artifact-from-github@1.4.0: optional: true @@ -16261,20 +16883,20 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 - intl-messageformat@10.7.17: + intl-messageformat@10.7.18: dependencies: - '@formatjs/ecma402-abstract': 2.3.5 + '@formatjs/ecma402-abstract': 2.3.6 '@formatjs/fast-memoize': 2.2.7 - '@formatjs/icu-messageformat-parser': 2.11.3 + '@formatjs/icu-messageformat-parser': 2.11.4 tslib: 2.8.1 - ip-address@10.0.1: {} + ip-address@10.1.0: {} ip-regex@4.3.0: {} ipaddr.js@1.9.1: {} - ipaddr.js@2.2.0: {} + ipaddr.js@2.3.0: {} is-alphabetical@1.0.4: {} @@ -16545,8 +17167,8 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: - '@babel/core': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -16555,8 +17177,8 @@ snapshots: istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 7.7.3 @@ -16590,7 +17212,7 @@ snapshots: esprima: 2.7.3 glob: 5.0.15 handlebars: 4.7.8 - js-yaml: 3.14.1 + js-yaml: 3.14.2 mkdirp: 0.5.6 nopt: 3.0.6 once: 1.4.0 @@ -16619,10 +17241,10 @@ snapshots: jasmine-core@4.6.1: {} - jasmine-core@5.11.0: {} - jasmine-core@5.12.0: {} + jasmine-core@5.13.0: {} + jasmine-reporters@2.5.2: dependencies: '@xmldom/xmldom': 0.8.11 @@ -16638,21 +17260,16 @@ snapshots: glob: 7.2.3 jasmine-core: 2.8.0 - jasmine@5.11.0: - dependencies: - glob: 10.4.5 - jasmine-core: 5.11.0 - - jasmine@5.12.0: + jasmine@5.13.0: dependencies: - glob: 10.4.5 - jasmine-core: 5.12.0 + glob: 10.5.0 + jasmine-core: 5.13.0 jasminewd2@2.2.0: {} jest-worker@27.5.1: dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -16666,18 +17283,20 @@ snapshots: url-join: 0.0.1 valid-url: 1.0.9 + jose@6.1.3: {} + jpeg-js@0.4.4: {} js-library-detector@6.7.0: {} js-tokens@4.0.0: {} - js-yaml@3.14.1: + js-yaml@3.14.2: dependencies: argparse: 1.0.10 esprima: 4.0.1 - js-yaml@4.1.0: + js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -16695,7 +17314,7 @@ snapshots: json-parse-even-better-errors@2.3.1: {} - json-parse-even-better-errors@4.0.0: {} + json-parse-even-better-errors@5.0.0: {} json-parse-helpfulerror@1.0.3: dependencies: @@ -16727,9 +17346,9 @@ snapshots: jsonparse@1.3.1: {} - jsonwebtoken@9.0.2: + jsonwebtoken@9.0.3: dependencies: - jws: 3.2.2 + jws: 4.0.1 lodash.includes: 4.3.0 lodash.isboolean: 3.0.3 lodash.isinteger: 4.0.4 @@ -16754,24 +17373,13 @@ snapshots: readable-stream: 2.3.8 setimmediate: 1.0.5 - jwa@1.4.2: - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - jws@3.2.2: - dependencies: - jwa: 1.4.2 - safe-buffer: 5.2.1 - - jws@4.0.0: + jws@4.0.1: dependencies: jwa: 2.0.1 safe-buffer: 5.2.1 @@ -16835,7 +17443,7 @@ snapshots: karma@6.4.4(bufferutil@4.0.9): dependencies: '@colors/colors': 1.5.0 - body-parser: 1.20.3 + body-parser: 1.20.4 braces: 3.0.3 chokidar: 3.6.0 connect: 3.7.0 @@ -16880,7 +17488,7 @@ snapshots: kuler@2.0.0: {} - launch-editor@2.11.1: + launch-editor@2.12.0: dependencies: picocolors: 1.1.1 shell-quote: 1.8.3 @@ -16891,11 +17499,11 @@ snapshots: legacy-javascript@0.0.1: {} - less-loader@12.3.0(less@4.4.2)(webpack@5.102.1(esbuild@0.25.10)): + less-loader@12.3.0(less@4.4.2)(webpack@5.102.1(esbuild@0.26.0)): dependencies: less: 4.4.2 optionalDependencies: - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) less@4.4.2: dependencies: @@ -16924,11 +17532,11 @@ snapshots: libsodium@0.7.15: {} - license-webpack-plugin@4.0.2(webpack@5.102.1(esbuild@0.25.10)): + license-webpack-plugin@4.0.2(webpack@5.102.1(esbuild@0.26.0)): dependencies: webpack-sources: 3.3.3 optionalDependencies: - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) lie@3.3.0: dependencies: @@ -16965,10 +17573,10 @@ snapshots: lighthouse-stack-packs@1.12.3: {} - lighthouse@13.0.0(bufferutil@4.0.9): + lighthouse@13.0.1(bufferutil@4.0.9): dependencies: '@paulirish/trace_engine': 0.0.61 - '@sentry/node': 9.46.0 + '@sentry/node': 9.47.1 axe-core: 4.11.0 chrome-launcher: 1.2.1 configstore: 7.1.0 @@ -16976,7 +17584,7 @@ snapshots: devtools-protocol: 0.0.1527314 enquirer: 2.4.1 http-link-header: 1.1.3 - intl-messageformat: 10.7.17 + intl-messageformat: 10.7.18 jpeg-js: 0.4.4 js-library-detector: 6.7.0 lighthouse-logger: 2.0.2 @@ -16984,15 +17592,16 @@ snapshots: lodash-es: 4.17.21 lookup-closest-locale: 6.2.0 open: 8.4.2 - puppeteer-core: 24.23.0(bufferutil@4.0.9) + puppeteer-core: 24.32.1(bufferutil@4.0.9) robots-parser: 3.0.1 speedline-core: 1.4.3 third-party-web: 0.27.0 - tldts-icann: 7.0.17 + tldts-icann: 7.0.19 ws: 7.5.10(bufferutil@4.0.9) yargs: 17.7.2 yargs-parser: 21.1.1 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - react-native-b4a @@ -17001,9 +17610,9 @@ snapshots: lines-and-columns@1.2.4: {} - listr2@9.0.4: + listr2@9.0.5: dependencies: - cli-truncate: 5.1.0 + cli-truncate: 5.1.1 colorette: 2.0.20 eventemitter3: 5.0.1 log-update: 6.1.0 @@ -17034,7 +17643,7 @@ snapshots: pify: 3.0.0 strip-bom: 3.0.0 - loader-runner@4.3.0: {} + loader-runner@4.3.1: {} loader-utils@2.0.4: dependencies: @@ -17111,7 +17720,7 @@ snapshots: log-update@6.1.0: dependencies: - ansi-escapes: 7.1.1 + ansi-escapes: 7.2.0 cli-cursor: 5.0.0 slice-ansi: 7.1.2 strip-ansi: 7.1.2 @@ -17148,7 +17757,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.2: {} + lru-cache@11.2.4: {} lru-cache@5.1.1: dependencies: @@ -17202,20 +17811,21 @@ snapshots: ssri: 12.0.0 transitivePeerDependencies: - supports-color + optional: true - make-fetch-happen@15.0.2: + make-fetch-happen@15.0.3: dependencies: '@npmcli/agent': 4.0.0 - cacache: 20.0.1 + cacache: 20.0.3 http-cache-semantics: 4.2.0 minipass: 7.1.2 - minipass-fetch: 4.0.1 + minipass-fetch: 5.0.0 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 negotiator: 1.0.0 - proc-log: 5.0.0 + proc-log: 6.1.0 promise-retry: 2.0.1 - ssri: 12.0.0 + ssri: 13.0.0 transitivePeerDependencies: - supports-color @@ -17227,7 +17837,7 @@ snapshots: marked-terminal@7.3.0(marked@13.0.3): dependencies: - ansi-escapes: 7.1.1 + ansi-escapes: 7.2.0 ansi-regex: 6.2.2 chalk: 5.6.2 cli-highlight: 2.1.11 @@ -17240,7 +17850,7 @@ snapshots: marked@13.0.3: {} - marked@16.3.0: {} + marked@16.4.2: {} marky@1.3.0: {} @@ -17252,9 +17862,9 @@ snapshots: media-typer@1.1.0: {} - memfs@4.48.1: + memfs@4.51.1: dependencies: - '@jsonjoy.com/json-pack': 1.14.0(tslib@2.8.1) + '@jsonjoy.com/json-pack': 1.21.0(tslib@2.8.1) '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) glob-to-regex.js: 1.2.0(tslib@2.8.1) thingies: 2.5.0(tslib@2.8.1) @@ -17303,7 +17913,7 @@ snapshots: dependencies: mime-db: 1.52.0 - mime-types@3.0.1: + mime-types@3.0.2: dependencies: mime-db: 1.54.0 @@ -17317,15 +17927,15 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.9.4(webpack@5.102.1(esbuild@0.25.10)): + mini-css-extract-plugin@2.9.4(webpack@5.102.1(esbuild@0.26.0)): dependencies: schema-utils: 4.3.3 tapable: 2.3.0 - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) minimalistic-assert@1.0.1: {} - minimatch@10.0.3: + minimatch@10.1.1: dependencies: '@isaacs/brace-expansion': 5.0.0 @@ -17372,6 +17982,15 @@ snapshots: minizlib: 3.1.0 optionalDependencies: encoding: 0.1.13 + optional: true + + minipass-fetch@5.0.0: + dependencies: + minipass: 7.1.2 + minipass-sized: 1.0.3 + minizlib: 3.1.0 + optionalDependencies: + encoding: 0.1.13 minipass-flush@1.0.5: dependencies: @@ -17464,13 +18083,15 @@ snapshots: mute-stream@2.0.0: {} + mute-stream@3.0.0: {} + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - nan@2.23.0: + nan@2.24.0: optional: true nanoid@3.3.11: {} @@ -17485,7 +18106,7 @@ snapshots: needle@3.3.1: dependencies: iconv-lite: 0.6.3 - sax: 1.4.1 + sax: 1.4.3 optional: true negotiator@0.6.3: {} @@ -17506,7 +18127,7 @@ snapshots: nock@14.0.10: dependencies: - '@mswjs/interceptors': 0.39.7 + '@mswjs/interceptors': 0.39.8 json-stringify-safe: 5.0.1 propagate: 2.0.1 @@ -17537,31 +18158,47 @@ snapshots: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 - node-forge@1.3.1: {} + node-forge@1.3.3: {} node-gyp-build-optional-packages@5.2.2: dependencies: - detect-libc: 2.1.1 + detect-libc: 2.1.2 optional: true node-gyp-build@4.8.4: {} - node-gyp@11.4.2: + node-gyp@11.5.0: dependencies: env-paths: 2.2.1 - exponential-backoff: 3.1.2 + exponential-backoff: 3.1.3 graceful-fs: 4.2.11 make-fetch-happen: 14.0.3 nopt: 8.1.0 proc-log: 5.0.0 semver: 7.7.3 - tar: 7.5.1 + tar: 7.5.2 tinyglobby: 0.2.15 which: 5.0.0 transitivePeerDependencies: - supports-color + optional: true + + node-gyp@12.1.0: + dependencies: + env-paths: 2.2.1 + exponential-backoff: 3.1.3 + graceful-fs: 4.2.11 + make-fetch-happen: 15.0.3 + nopt: 9.0.0 + proc-log: 6.1.0 + semver: 7.7.3 + tar: 7.5.2 + tinyglobby: 0.2.15 + which: 6.0.0 + transitivePeerDependencies: + - supports-color - node-releases@2.0.23: {} + node-releases@2.0.27: {} nopt@3.0.6: dependencies: @@ -17570,11 +18207,16 @@ snapshots: nopt@8.1.0: dependencies: abbrev: 3.0.1 + optional: true + + nopt@9.0.0: + dependencies: + abbrev: 4.0.0 normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.10 + resolve: 1.22.11 semver: 5.7.2 validate-npm-package-license: 3.0.4 @@ -17597,7 +18239,7 @@ snapshots: dependencies: semver: 7.7.3 - npm-install-checks@7.1.2: + npm-install-checks@8.0.0: dependencies: semver: 7.7.3 @@ -17605,6 +18247,8 @@ snapshots: npm-normalize-package-bin@4.0.0: {} + npm-normalize-package-bin@5.0.0: {} + npm-package-arg@11.0.3: dependencies: hosted-git-info: 7.0.2 @@ -17614,20 +18258,20 @@ snapshots: npm-package-arg@13.0.1: dependencies: - hosted-git-info: 9.0.0 + hosted-git-info: 9.0.2 proc-log: 5.0.0 semver: 7.7.3 validate-npm-package-name: 6.0.2 - npm-packlist@10.0.2: + npm-packlist@10.0.3: dependencies: ignore-walk: 8.0.0 - proc-log: 5.0.0 + proc-log: 6.1.0 - npm-pick-manifest@11.0.1: + npm-pick-manifest@11.0.3: dependencies: - npm-install-checks: 7.1.2 - npm-normalize-package-bin: 4.0.0 + npm-install-checks: 8.0.0 + npm-normalize-package-bin: 5.0.0 npm-package-arg: 13.0.1 semver: 7.7.3 @@ -17638,16 +18282,16 @@ snapshots: npm-package-arg: 11.0.3 semver: 7.7.3 - npm-registry-fetch@19.0.0: + npm-registry-fetch@19.1.1: dependencies: - '@npmcli/redact': 3.2.2 + '@npmcli/redact': 4.0.0 jsonparse: 1.3.1 - make-fetch-happen: 15.0.2 + make-fetch-happen: 15.0.3 minipass: 7.1.2 - minipass-fetch: 4.0.1 + minipass-fetch: 5.0.0 minizlib: 3.1.0 npm-package-arg: 13.0.1 - proc-log: 5.0.0 + proc-log: 6.1.0 transitivePeerDependencies: - supports-color @@ -17728,7 +18372,7 @@ snapshots: open@10.2.0: dependencies: - default-browser: 5.2.1 + default-browser: 5.4.0 define-lazy-prop: 3.0.0 is-inside-container: 1.0.0 wsl-utils: 0.1.0 @@ -17745,7 +18389,7 @@ snapshots: openapi3-ts@3.2.0: dependencies: - yaml: 2.8.1 + yaml: 2.8.2 opener@1.5.2: {} @@ -17815,7 +18459,7 @@ snapshots: dependencies: p-limit: 3.1.0 - p-map@7.0.3: {} + p-map@7.0.4: {} p-queue@6.6.2: dependencies: @@ -17858,23 +18502,23 @@ snapshots: pacote@21.0.3: dependencies: - '@npmcli/git': 7.0.0 + '@npmcli/git': 7.0.1 '@npmcli/installed-package-contents': 3.0.0 - '@npmcli/package-json': 7.0.1 + '@npmcli/package-json': 7.0.4 '@npmcli/promise-spawn': 8.0.3 - '@npmcli/run-script': 10.0.0 - cacache: 20.0.1 + '@npmcli/run-script': 10.0.3 + cacache: 20.0.3 fs-minipass: 3.0.3 minipass: 7.1.2 npm-package-arg: 13.0.1 - npm-packlist: 10.0.2 - npm-pick-manifest: 11.0.1 - npm-registry-fetch: 19.0.0 + npm-packlist: 10.0.3 + npm-pick-manifest: 11.0.3 + npm-registry-fetch: 19.1.1 proc-log: 5.0.0 promise-retry: 2.0.1 sigstore: 4.0.0 ssri: 12.0.0 - tar: 7.5.1 + tar: 7.5.2 transitivePeerDependencies: - supports-color @@ -17954,9 +18598,9 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 - path-scurry@2.0.0: + path-scurry@2.0.1: dependencies: - lru-cache: 11.2.2 + lru-cache: 11.2.4 minipass: 7.1.2 path-to-regexp@0.1.12: {} @@ -18043,7 +18687,7 @@ snapshots: optionalDependencies: '@napi-rs/nice': 1.1.1 - pkce-challenge@5.0.0: {} + pkce-challenge@5.0.1: {} portfinder@1.0.38: dependencies: @@ -18054,14 +18698,14 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-loader@8.2.0(postcss@8.5.6)(typescript@5.9.2)(webpack@5.102.1(esbuild@0.25.10)): + postcss-loader@8.2.0(postcss@8.5.6)(typescript@5.9.2)(webpack@5.102.1(esbuild@0.26.0)): dependencies: cosmiconfig: 9.0.0(typescript@5.9.2) jiti: 2.6.1 postcss: 8.5.6 semver: 7.7.3 optionalDependencies: - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) transitivePeerDependencies: - typescript @@ -18075,13 +18719,13 @@ snapshots: dependencies: icss-utils: 5.1.0(postcss@8.5.6) postcss: 8.5.6 - postcss-selector-parser: 7.1.0 + postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 postcss-modules-scope@3.2.1(postcss@8.5.6): dependencies: postcss: 8.5.6 - postcss-selector-parser: 7.1.0 + postcss-selector-parser: 7.1.1 postcss-modules-values@4.0.0(postcss@8.5.6): dependencies: @@ -18103,7 +18747,7 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-selector-parser@7.1.0: + postcss-selector-parser@7.1.1: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 @@ -18128,12 +18772,14 @@ snapshots: prelude-ls@1.1.2: {} - prettier@3.6.2: {} + prettier@3.7.4: {} proc-log@4.2.0: {} proc-log@5.0.0: {} + proc-log@6.1.0: {} + process-nextick-args@2.0.1: {} process@0.11.10: {} @@ -18164,7 +18810,7 @@ snapshots: dependencies: protobufjs: 7.5.4 - proto3-json-serializer@3.0.2: + proto3-json-serializer@3.0.4: dependencies: protobufjs: 7.5.4 @@ -18180,7 +18826,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 22.18.8 + '@types/node': 22.19.2 long: 5.3.2 protobufjs@7.5.4: @@ -18195,7 +18841,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 22.18.8 + '@types/node': 22.19.2 long: 5.3.2 protractor@7.0.0: @@ -18273,16 +18919,17 @@ snapshots: dependencies: escape-goat: 2.1.1 - puppeteer-core@24.23.0(bufferutil@4.0.9): + puppeteer-core@24.32.1(bufferutil@4.0.9): dependencies: - '@puppeteer/browsers': 2.10.10 - chromium-bidi: 9.1.0(devtools-protocol@0.0.1508733) + '@puppeteer/browsers': 2.11.0 + chromium-bidi: 11.0.0(devtools-protocol@0.0.1534754) debug: 4.4.3(supports-color@10.2.2) - devtools-protocol: 0.0.1508733 + devtools-protocol: 0.0.1534754 typed-query-selector: 2.12.0 - webdriver-bidi-protocol: 0.3.6 + webdriver-bidi-protocol: 0.3.9 ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - react-native-b4a @@ -18295,10 +18942,6 @@ snapshots: qjobs@1.2.0: {} - qs@6.13.0: - dependencies: - side-channel: 1.1.0 - qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -18322,17 +18965,17 @@ snapshots: range-parser@1.2.1: {} - raw-body@2.5.2: + raw-body@2.5.3: dependencies: bytes: 3.1.2 - http-errors: 2.0.0 + http-errors: 2.0.1 iconv-lite: 0.4.24 unpipe: 1.0.0 - raw-body@3.0.1: + raw-body@3.0.2: dependencies: bytes: 3.1.2 - http-errors: 2.0.0 + http-errors: 2.0.1 iconv-lite: 0.7.0 unpipe: 1.0.0 @@ -18343,11 +18986,11 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - re2@1.22.1: + re2@1.22.3: dependencies: install-artifact-from-github: 1.4.0 - nan: 2.23.0 - node-gyp: 11.4.2 + nan: 2.24.0 + node-gyp: 11.5.0 transitivePeerDependencies: - supports-color optional: true @@ -18513,13 +19156,13 @@ snapshots: dependencies: debug: 4.4.3(supports-color@10.2.2) module-details-from-path: 1.0.4 - resolve: 1.22.10 + resolve: 1.22.11 transitivePeerDependencies: - supports-color require-main-filename@2.0.0: {} - requirejs@2.3.7: {} + requirejs@2.3.8: {} requires-port@1.0.0: {} @@ -18539,7 +19182,7 @@ snapshots: resolve@1.1.7: {} - resolve@1.22.10: + resolve@1.22.11: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 @@ -18593,70 +19236,73 @@ snapshots: dependencies: glob: 7.2.3 + rimraf@5.0.10: + dependencies: + glob: 10.5.0 + robots-parser@3.0.1: {} - rolldown@1.0.0-beta.43: + rolldown@1.0.0-beta.47: dependencies: - '@oxc-project/types': 0.94.0 - '@rolldown/pluginutils': 1.0.0-beta.43 - ansis: 4.2.0 + '@oxc-project/types': 0.96.0 + '@rolldown/pluginutils': 1.0.0-beta.47 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.43 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.43 - '@rolldown/binding-darwin-x64': 1.0.0-beta.43 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.43 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.43 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.43 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.43 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.43 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.43 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.43 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.43 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.43 - '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.43 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.43 - - rollup-plugin-dts@6.2.3(rollup@4.52.4)(typescript@5.9.2): + '@rolldown/binding-android-arm64': 1.0.0-beta.47 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.47 + '@rolldown/binding-darwin-x64': 1.0.0-beta.47 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.47 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.47 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.47 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.47 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.47 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.47 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.47 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.47 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.47 + '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.47 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.47 + + rollup-plugin-dts@6.2.3(rollup@4.53.3)(typescript@5.9.2): dependencies: magic-string: 0.30.19 - rollup: 4.52.4 + rollup: 4.53.3 typescript: 5.9.2 optionalDependencies: '@babel/code-frame': 7.27.1 - rollup-plugin-sourcemaps2@0.5.4(@types/node@22.18.8)(rollup@4.52.4): + rollup-plugin-sourcemaps2@0.5.4(@types/node@22.19.2)(rollup@4.53.3): dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.52.4) - rollup: 4.52.4 + '@rollup/pluginutils': 5.2.0(rollup@4.53.3) + rollup: 4.53.3 optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 - rollup@4.52.4: + rollup@4.53.3: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.4 - '@rollup/rollup-android-arm64': 4.52.4 - '@rollup/rollup-darwin-arm64': 4.52.4 - '@rollup/rollup-darwin-x64': 4.52.4 - '@rollup/rollup-freebsd-arm64': 4.52.4 - '@rollup/rollup-freebsd-x64': 4.52.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.4 - '@rollup/rollup-linux-arm-musleabihf': 4.52.4 - '@rollup/rollup-linux-arm64-gnu': 4.52.4 - '@rollup/rollup-linux-arm64-musl': 4.52.4 - '@rollup/rollup-linux-loong64-gnu': 4.52.4 - '@rollup/rollup-linux-ppc64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-musl': 4.52.4 - '@rollup/rollup-linux-s390x-gnu': 4.52.4 - '@rollup/rollup-linux-x64-gnu': 4.52.4 - '@rollup/rollup-linux-x64-musl': 4.52.4 - '@rollup/rollup-openharmony-arm64': 4.52.4 - '@rollup/rollup-win32-arm64-msvc': 4.52.4 - '@rollup/rollup-win32-ia32-msvc': 4.52.4 - '@rollup/rollup-win32-x64-gnu': 4.52.4 - '@rollup/rollup-win32-x64-msvc': 4.52.4 + '@rollup/rollup-android-arm-eabi': 4.53.3 + '@rollup/rollup-android-arm64': 4.53.3 + '@rollup/rollup-darwin-arm64': 4.53.3 + '@rollup/rollup-darwin-x64': 4.53.3 + '@rollup/rollup-freebsd-arm64': 4.53.3 + '@rollup/rollup-freebsd-x64': 4.53.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 + '@rollup/rollup-linux-arm-musleabihf': 4.53.3 + '@rollup/rollup-linux-arm64-gnu': 4.53.3 + '@rollup/rollup-linux-arm64-musl': 4.53.3 + '@rollup/rollup-linux-loong64-gnu': 4.53.3 + '@rollup/rollup-linux-ppc64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-musl': 4.53.3 + '@rollup/rollup-linux-s390x-gnu': 4.53.3 + '@rollup/rollup-linux-x64-gnu': 4.53.3 + '@rollup/rollup-linux-x64-musl': 4.53.3 + '@rollup/rollup-openharmony-arm64': 4.53.3 + '@rollup/rollup-win32-arm64-msvc': 4.53.3 + '@rollup/rollup-win32-ia32-msvc': 4.53.3 + '@rollup/rollup-win32-x64-gnu': 4.53.3 + '@rollup/rollup-win32-x64-msvc': 4.53.3 fsevents: 2.3.3 router@2.2.0: @@ -18677,9 +19323,9 @@ snapshots: rxjs-report-usage@1.0.6: dependencies: - '@babel/parser': 7.28.4 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 bent: 7.3.12 chalk: 4.1.2 glob: 7.2.3 @@ -18691,9 +19337,9 @@ snapshots: dependencies: '@phenomnomnominal/tsquery': 4.2.0(typescript@5.9.2) decamelize: 4.0.0 - resolve: 1.22.10 + resolve: 1.22.11 rxjs-report-usage: 1.0.6 - semver: 7.7.2 + semver: 7.7.3 tslib: 2.8.1 tslint: 6.1.3(typescript@5.9.2) tsutils: 3.21.0(typescript@5.9.2) @@ -18739,17 +19385,17 @@ snapshots: safevalues@1.2.0: {} - sass-loader@16.0.5(sass@1.93.2)(webpack@5.102.1(esbuild@0.25.10)): + sass-loader@16.0.5(sass@1.93.2)(webpack@5.102.1(esbuild@0.26.0)): dependencies: neo-async: 2.6.2 optionalDependencies: sass: 1.93.2 - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) sass@1.93.2: dependencies: chokidar: 4.0.3 - immutable: 5.1.3 + immutable: 5.1.4 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.1 @@ -18760,7 +19406,7 @@ snapshots: transitivePeerDependencies: - supports-color - sax@1.4.1: {} + sax@1.4.3: {} schema-utils@4.3.3: dependencies: @@ -18781,7 +19427,7 @@ snapshots: selfsigned@2.4.1: dependencies: '@types/node-forge': 1.3.14 - node-forge: 1.3.1 + node-forge: 1.3.3 semver-diff@3.1.1: dependencies: @@ -18791,8 +19437,6 @@ snapshots: semver@6.3.1: {} - semver@7.7.2: {} - semver@7.7.3: {} send@0.17.2: @@ -18831,6 +19475,24 @@ snapshots: transitivePeerDependencies: - supports-color + send@0.19.1: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + send@1.2.0: dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -18838,8 +19500,8 @@ snapshots: escape-html: 1.0.3 etag: 1.8.1 fresh: 2.0.0 - http-errors: 2.0.0 - mime-types: 3.0.1 + http-errors: 2.0.1 + mime-types: 3.0.2 ms: 2.1.3 on-finished: 2.4.1 range-parser: 1.2.1 @@ -19066,7 +19728,7 @@ snapshots: socks@2.8.7: dependencies: - ip-address: 10.0.1 + ip-address: 10.1.0 smart-buffer: 4.2.0 sort-any@2.0.0: @@ -19075,11 +19737,11 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@5.0.0(webpack@5.102.1(esbuild@0.25.10)): + source-map-loader@5.0.0(webpack@5.102.1(esbuild@0.26.0)): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) source-map-support@0.4.18: dependencies: @@ -19142,7 +19804,7 @@ snapshots: speedline-core@1.4.3: dependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 image-ssim: 0.2.0 jpeg-js: 0.4.4 @@ -19188,6 +19850,10 @@ snapshots: dependencies: minipass: 7.1.2 + ssri@13.0.0: + dependencies: + minipass: 7.1.2 + stack-trace@0.0.10: {} statuses@1.5.0: {} @@ -19235,6 +19901,7 @@ snapshots: fast-fifo: 1.3.2 text-decoder: 1.2.3 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a strict-event-emitter@0.5.1: {} @@ -19253,7 +19920,7 @@ snapshots: string-width@7.2.0: dependencies: - emoji-regex: 10.5.0 + emoji-regex: 10.6.0 get-east-asian-width: 1.4.0 strip-ansi: 7.1.2 @@ -19332,7 +19999,11 @@ snapshots: strip-json-comments@3.1.1: {} - stubborn-fs@1.2.5: {} + stubborn-fs@2.0.0: + dependencies: + stubborn-utils: 1.0.2 + + stubborn-utils@1.0.2: {} stubs@3.0.0: {} @@ -19401,7 +20072,7 @@ snapshots: router: 2.2.0 update-notifier-cjs: 5.1.7(encoding@0.1.13) optionalDependencies: - re2: 1.22.1 + re2: 1.22.3 transitivePeerDependencies: - encoding - supports-color @@ -19460,9 +20131,10 @@ snapshots: pump: 3.0.3 tar-stream: 3.1.7 optionalDependencies: - bare-fs: 4.4.5 + bare-fs: 4.5.2 bare-path: 3.0.0 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a @@ -19472,6 +20144,7 @@ snapshots: fast-fifo: 1.3.2 streamx: 2.23.0 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a tar@6.2.1: @@ -19483,7 +20156,7 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 - tar@7.5.1: + tar@7.5.2: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 @@ -19522,16 +20195,16 @@ snapshots: dependencies: rimraf: 2.5.4 - terser-webpack-plugin@5.3.14(esbuild@0.25.10)(webpack@5.102.1(esbuild@0.25.10)): + terser-webpack-plugin@5.3.15(esbuild@0.26.0)(webpack@5.102.1(esbuild@0.26.0)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 - terser: 5.44.0 - webpack: 5.102.1(esbuild@0.25.10) + terser: 5.44.1 + webpack: 5.102.1(esbuild@0.26.0) optionalDependencies: - esbuild: 0.25.10 + esbuild: 0.26.0 terser@5.44.0: dependencies: @@ -19540,6 +20213,13 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 + terser@5.44.1: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + text-decoder@1.2.3: dependencies: b4a: 1.7.3 @@ -19562,6 +20242,8 @@ snapshots: third-party-web@0.27.0: {} + third-party-web@0.29.0: {} + through2@2.0.5: dependencies: readable-stream: 2.3.8 @@ -19590,11 +20272,11 @@ snapshots: no-case: 2.3.2 upper-case: 1.1.3 - tldts-core@7.0.17: {} + tldts-core@7.0.19: {} - tldts-icann@7.0.17: + tldts-icann@7.0.19: dependencies: - tldts-core: 7.0.17 + tldts-core: 7.0.19 tmp@0.0.30: dependencies: @@ -19633,14 +20315,14 @@ snapshots: trough@1.0.5: {} - ts-node@10.9.2(@types/node@22.18.8)(typescript@5.9.2): + ts-node@10.9.2(@types/node@22.19.2)(typescript@5.9.2): dependencies: '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 + '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.18.8 + '@types/node': 22.19.2 acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 @@ -19654,8 +20336,8 @@ snapshots: tsec@0.2.9(@bazel/bazelisk@1.26.0)(typescript@5.9.2): dependencies: '@bazel/bazelisk': 1.26.0 - glob: 11.0.3 - minimatch: 10.0.3 + glob: 11.1.0 + minimatch: 10.1.1 typescript: 5.9.2 tsickle@0.46.3(typescript@5.9.2): @@ -19675,10 +20357,10 @@ snapshots: commander: 2.20.3 diff: 4.0.2 glob: 7.2.3 - js-yaml: 3.14.1 + js-yaml: 3.14.2 minimatch: 3.1.2 mkdirp: 0.5.6 - resolve: 1.22.10 + resolve: 1.22.11 semver: 5.7.2 tslib: 1.14.1 tsutils: 2.29.0(typescript@5.9.2) @@ -19688,7 +20370,7 @@ snapshots: tsutils-etc@1.4.2(tsutils@3.21.0(typescript@5.9.2))(typescript@5.9.2): dependencies: - '@types/yargs': 17.0.33 + '@types/yargs': 17.0.35 tsutils: 3.21.0(typescript@5.9.2) typescript: 5.9.2 yargs: 17.7.2 @@ -19703,10 +20385,10 @@ snapshots: tslib: 1.14.1 typescript: 5.9.2 - tsx@4.20.6: + tsx@4.21.0: dependencies: - esbuild: 0.25.10 - get-tsconfig: 4.10.1 + esbuild: 0.27.1 + get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 @@ -19714,7 +20396,7 @@ snapshots: dependencies: '@tufjs/models': 4.0.0 debug: 4.4.3(supports-color@10.2.2) - make-fetch-happen: 15.0.2 + make-fetch-happen: 15.0.3 transitivePeerDependencies: - supports-color @@ -19749,7 +20431,7 @@ snapshots: dependencies: content-type: 1.0.5 media-typer: 1.1.0 - mime-types: 3.0.1 + mime-types: 3.0.2 typed-array-buffer@1.0.3: dependencies: @@ -19812,12 +20494,14 @@ snapshots: undici-types@6.21.0: {} - undici-types@7.14.0: {} + undici-types@7.16.0: {} undici@5.29.0: dependencies: '@fastify/busboy': 2.1.1 + undici@7.16.0: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-emoji-modifier-base@1.0.0: {} @@ -19845,10 +20529,20 @@ snapshots: unique-filename@4.0.0: dependencies: unique-slug: 5.0.0 + optional: true + + unique-filename@5.0.0: + dependencies: + unique-slug: 6.0.0 unique-slug@5.0.0: dependencies: imurmurhash: 0.1.4 + optional: true + + unique-slug@6.0.0: + dependencies: + imurmurhash: 0.1.4 unique-string@2.0.0: dependencies: @@ -19879,9 +20573,9 @@ snapshots: unpipe@1.0.0: {} - update-browserslist-db@1.1.3(browserslist@4.26.3): + update-browserslist-db@1.2.2(browserslist@4.28.1): dependencies: - browserslist: 4.26.3 + browserslist: 4.28.1 escalade: 3.2.0 picocolors: 1.1.1 @@ -19979,23 +20673,23 @@ snapshots: unist-util-stringify-position: 1.1.2 vfile-message: 1.1.1 - vite@7.1.10(@types/node@22.18.8)(jiti@2.6.1)(less@4.4.2)(sass@1.93.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): + vite@7.2.2(@types/node@22.19.2)(jiti@2.6.1)(less@4.4.2)(sass@1.93.2)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: - esbuild: 0.25.10 + esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.4 + rollup: 4.53.3 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 22.18.8 + '@types/node': 22.19.2 fsevents: 2.3.3 jiti: 2.6.1 less: 4.4.2 sass: 1.93.2 terser: 5.44.0 - tsx: 4.20.6 - yaml: 2.8.1 + tsx: 4.21.0 + yaml: 2.8.2 void-elements@2.0.1: {} @@ -20026,7 +20720,7 @@ snapshots: web-vitals@4.2.4: {} - webdriver-bidi-protocol@0.3.6: {} + webdriver-bidi-protocol@0.3.9: {} webdriver-js-extender@2.1.0: dependencies: @@ -20049,25 +20743,25 @@ snapshots: webidl-conversions@3.0.1: {} - webpack-dev-middleware@7.4.5(webpack@5.102.1(esbuild@0.25.10)): + webpack-dev-middleware@7.4.5(webpack@5.102.1(esbuild@0.26.0)): dependencies: colorette: 2.0.20 - memfs: 4.48.1 - mime-types: 3.0.1 + memfs: 4.51.1 + mime-types: 3.0.2 on-finished: 2.4.1 range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) - webpack-dev-server@5.2.2(bufferutil@4.0.9)(webpack@5.102.1(esbuild@0.25.10)): + webpack-dev-server@5.2.2(bufferutil@4.0.9)(webpack@5.102.1(esbuild@0.26.0)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 - '@types/express': 4.17.23 - '@types/express-serve-static-core': 4.19.6 + '@types/express': 4.17.25 + '@types/express-serve-static-core': 4.19.7 '@types/serve-index': 1.9.4 - '@types/serve-static': 1.15.9 + '@types/serve-static': 1.15.10 '@types/sockjs': 0.3.36 '@types/ws': 8.18.1 ansi-html-community: 0.0.8 @@ -20076,11 +20770,11 @@ snapshots: colorette: 2.0.20 compression: 1.8.1 connect-history-api-fallback: 2.0.0 - express: 4.21.2 + express: 4.22.1 graceful-fs: 4.2.11 - http-proxy-middleware: 2.0.9(@types/express@4.17.23) - ipaddr.js: 2.2.0 - launch-editor: 2.11.1 + http-proxy-middleware: 2.0.9(@types/express@4.17.25) + ipaddr.js: 2.3.0 + launch-editor: 2.12.0 open: 10.2.0 p-retry: 6.2.1 schema-utils: 4.3.3 @@ -20088,10 +20782,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.5(webpack@5.102.1(esbuild@0.25.10)) + webpack-dev-middleware: 7.4.5(webpack@5.102.1(esbuild@0.26.0)) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) optionalDependencies: - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) transitivePeerDependencies: - bufferutil - debug @@ -20106,12 +20800,12 @@ snapshots: webpack-sources@3.3.3: {} - webpack-subresource-integrity@5.1.0(webpack@5.102.1(esbuild@0.25.10)): + webpack-subresource-integrity@5.1.0(webpack@5.102.1(esbuild@0.26.0)): dependencies: typed-assert: 1.0.9 - webpack: 5.102.1(esbuild@0.25.10) + webpack: 5.102.1(esbuild@0.26.0) - webpack@5.102.1(esbuild@0.25.10): + webpack@5.102.1(esbuild@0.26.0): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -20121,7 +20815,7 @@ snapshots: '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.15.0 acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.26.3 + browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.3 es-module-lexer: 1.7.0 @@ -20130,12 +20824,12 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 + loader-runner: 4.3.1 mime-types: 2.1.35 neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(esbuild@0.25.10)(webpack@5.102.1(esbuild@0.25.10)) + terser-webpack-plugin: 5.3.15(esbuild@0.26.0)(webpack@5.102.1(esbuild@0.26.0)) watchpack: 2.4.4 webpack-sources: 3.3.3 transitivePeerDependencies: @@ -20158,7 +20852,7 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 - when-exit@2.1.4: {} + when-exit@2.1.5: {} which-boxed-primitive@1.1.1: dependencies: @@ -20219,6 +20913,10 @@ snapshots: dependencies: isexe: 3.1.1 + which@6.0.0: + dependencies: + isexe: 3.1.1 + widest-line@3.1.0: dependencies: string-width: 4.2.3 @@ -20240,7 +20938,7 @@ snapshots: isstream: 0.1.2 stack-trace: 0.0.10 - winston@3.18.3: + winston@3.19.0: dependencies: '@colors/colors': 1.6.0 '@dabh/diagnostics': 2.0.8 @@ -20323,7 +21021,7 @@ snapshots: xml2js@0.4.23: dependencies: - sax: 1.4.1 + sax: 1.4.3 xmlbuilder: 11.0.1 xmlbuilder@11.0.1: {} @@ -20342,7 +21040,7 @@ snapshots: yaml@1.10.2: {} - yaml@2.8.1: {} + yaml@2.8.2: {} yargs-parser@18.1.3: dependencies: @@ -20417,12 +21115,18 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.7.0 - zod-to-json-schema@3.24.6(zod@3.25.76): + zod-to-json-schema@3.25.0(zod@3.25.76): dependencies: zod: 3.25.76 + zod-to-json-schema@3.25.0(zod@4.1.13): + dependencies: + zod: 4.1.13 + zod@3.25.76: {} + zod@4.1.13: {} + zone.js@0.15.1: {} - zx@8.8.4: {} + zx@8.8.5: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c70514a65a67..0ea365066b9f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -18,23 +18,23 @@ packages: - src/youtube-player catalog: - '@angular-devkit/build-angular': 21.0.0-next.8 - '@angular-devkit/core': 21.0.0-next.8 - '@angular-devkit/schematics': 21.0.0-next.8 - '@angular/build': 21.0.0-next.8 - '@angular/cli': 21.0.0-next.8 - '@angular/common': 21.0.0-next.8 - '@angular/compiler-cli': 21.0.0-next.8 - '@angular/compiler': 21.0.0-next.8 - '@angular/core': 21.0.0-next.8 - '@angular/ssr': 21.0.0-next.8 - '@angular/forms': 21.0.0-next.8 - '@angular/localize': 21.0.0-next.8 - '@angular/platform-browser': 21.0.0-next.8 - '@angular/platform-browser-dynamic': 21.0.0-next.8 - '@angular/platform-server': 21.0.0-next.8 - '@angular/router': 21.0.0-next.8 - '@schematics/angular': 21.0.0-next.8 + '@angular-devkit/build-angular': 21.0.3 + '@angular-devkit/core': 21.0.3 + '@angular-devkit/schematics': 21.0.3 + '@angular/build': 21.0.3 + '@angular/cli': 21.0.3 + '@angular/common': 21.0.5 + '@angular/compiler-cli': 21.0.5 + '@angular/compiler': 21.0.5 + '@angular/core': 21.0.5 + '@angular/ssr': 21.0.3 + '@angular/forms': 21.0.5 + '@angular/localize': 21.0.5 + '@angular/platform-browser': 21.0.5 + '@angular/platform-browser-dynamic': 21.0.5 + '@angular/platform-server': 21.0.5 + '@angular/router': 21.0.5 + '@schematics/angular': 21.0.3 'rxjs': ^6.6.7 # The minimum age of a release to be considered for dependency installation. diff --git a/scripts/build-docs-content.mts b/scripts/build-docs-content.mts index e2b0b7cd2486..a7cd52888860 100644 --- a/scripts/build-docs-content.mts +++ b/scripts/build-docs-content.mts @@ -35,8 +35,10 @@ export function buildDocsContentPackage(): BuiltPackage { // Go to project directory. sh.cd(projectDir); + // TODO: Remove --ignore_all_rc_files flag once a repository can be loaded in bazelrc during info + // commands again. See https://github.com/bazelbuild/bazel/issues/25145 for more context. /** Path to the bazel bin output directory. */ - const bazelBinPath = sh.exec(`${bazelCmd} info bazel-bin`).stdout.trim(); + const bazelBinPath = sh.exec(`${bazelCmd} --ignore_all_rc_files info bazel-bin`).stdout.trim(); /** Path where the NPM package is built into by Bazel. */ const bazelBinOutDir = join(bazelBinPath, 'src/components-examples/npm_package'); diff --git a/scripts/build-packages-dist.mts b/scripts/build-packages-dist.mts index abffdb706efd..1f99e41c8916 100755 --- a/scripts/build-packages-dist.mts +++ b/scripts/build-packages-dist.mts @@ -55,7 +55,9 @@ function buildReleasePackages(distPath: string, isSnapshotBuild: boolean): Built // List of targets to build. e.g. "src/cdk:npm_package", or "src/material:npm_package". const targets = exec(queryPackagesCmd, true).split(/\r?\n/); const packageNames = getPackageNamesOfTargets(targets); - const bazelBinPath = exec(`${bazelCmd} info bazel-bin`, true); + // TODO: Remove --ignore_all_rc_files flag once a repository can be loaded in bazelrc during info + // commands again. See https://github.com/bazelbuild/bazel/issues/25145 for more context. + const bazelBinPath = exec(`${bazelCmd} --ignore_all_rc_files info bazel-bin`, true); const getBazelOutputPath = (pkgName: string) => join(bazelBinPath, 'src', pkgName, 'npm_package'); const getDistPath = (pkgName: string) => join(distPath, pkgName); diff --git a/scripts/deploy-dev-app.js b/scripts/deploy-dev-app.js index fc2b2625f234..19514a2d73d2 100644 --- a/scripts/deploy-dev-app.js +++ b/scripts/deploy-dev-app.js @@ -17,8 +17,10 @@ const projectDirPath = join(__dirname, '../'); // Go to project directory. cd(projectDirPath); +// TODO: Remove --ignore_all_rc_files flag once a repository can be loaded in bazelrc during info +// commands again. See https://github.com/bazelbuild/bazel/issues/25145 for more context. /** Path to the bazel-bin directory. */ -const bazelBinPath = exec(`pnpm -s bazel info bazel-bin`).stdout.trim(); +const bazelBinPath = exec(`pnpm -s bazel --ignore_all_rc_files info bazel-bin`).stdout.trim(); /** Output path for the Bazel dev-app web package target. */ const webPackagePath = join(bazelBinPath, 'src/dev-app/web_package'); diff --git a/scripts/deploy/publish-build-artifacts.sh b/scripts/deploy/publish-build-artifacts.sh index 770993e481a3..c8e4a1cb39a8 100755 --- a/scripts/deploy/publish-build-artifacts.sh +++ b/scripts/deploy/publish-build-artifacts.sh @@ -17,14 +17,14 @@ fi # Release packages that need to published as snapshots. PACKAGES=( - # aria TODO(crisbeto): enable this once there's a builds repo for ARIA + aria cdk cdk-experimental material material-experimental material-moment-adapter - # material-luxon-adapter TODO(crisbeto): enable this once we have a builds repo - # material-date-fns-adapter TODO(crisbeto): enable this once we have a builds repo + material-luxon-adapter + material-date-fns-adapter google-maps youtube-player ) diff --git a/scripts/ownerslint.mts b/scripts/ownerslint.mts deleted file mode 100644 index ea4b49634d4a..000000000000 --- a/scripts/ownerslint.mts +++ /dev/null @@ -1,86 +0,0 @@ -import chalk from 'chalk'; -import {readdirSync, readFileSync, statSync} from 'fs'; -import {Minimatch} from 'minimatch'; -import {join} from 'path'; - -/** - * Script that lints the CODEOWNERS file and makes sure that all files have an owner. - */ - -/** Path for the Github owners file. */ -const ownersFilePath = '.github/CODEOWNERS'; - -/** Path for the .gitignore file. */ -const gitIgnorePath = '.gitignore'; - -let errors = 0; -const ownedPaths = readFileSync(ownersFilePath, 'utf8') - .split('\n') - // Trim lines. - .map(line => line.trim()) - // Remove empty lines and comments. - .filter(line => line && !line.startsWith('#')) - // Split off just the path glob. - .map(line => line.split(/\s+/)[0]) - // Turn paths into Minimatch objects. - .map(path => new Minimatch(path, {dot: true, matchBase: true})); - -const ignoredPaths = readFileSync(gitIgnorePath, 'utf8') - .split('\n') - // Trim lines. - .map(line => line.trim()) - // Remove empty lines and comments. - .filter(line => line && !line.startsWith('#')) - // Turn paths into Minimatch objects. - .map(path => new Minimatch(path, {dot: true, matchBase: true})); - -for (let paths = getChildPaths('.'); paths.length; ) { - paths = Array.prototype.concat( - ...paths - // Remove ignored paths - .filter( - path => - !ignoredPaths.reduce( - (isIgnored, ignoredPath) => isIgnored || ignoredPath.match('/' + path), - false, - ), - ) - // Remove paths that match an owned path. - .filter( - path => - !ownedPaths.reduce((isOwned, ownedPath) => isOwned || isOwnedBy(path, ownedPath), false), - ) - // Report an error for any files that didn't match any owned paths. - .filter(path => { - if (statSync(path).isFile()) { - console.log(chalk.red(`No code owner found for "${path}".`)); - errors++; - return false; - } - return true; - }) - // Get the next level of children for any directories. - .map(path => getChildPaths(path)), - ); -} - -if (errors) { - throw Error( - `Found ${errors} files with no owner. Code owners for the files ` + - `should be added in the CODEOWNERS file.`, - ); -} - -/** Check if the given path is owned by the given owned path matcher. */ -function isOwnedBy(path: string, ownedPath: Minimatch) { - // If the owned path ends with `**` its safe to eliminate whole directories. - if (ownedPath.pattern.endsWith('**') || statSync(path).isFile()) { - return ownedPath.match('/' + path); - } - return false; -} - -/** Get the immediate child paths of the given path. */ -function getChildPaths(path: string) { - return readdirSync(path).map(child => join(path, child)); -} diff --git a/src/aria/BUILD.bazel b/src/aria/BUILD.bazel index 39343a966e93..33fdaeea598d 100644 --- a/src/aria/BUILD.bazel +++ b/src/aria/BUILD.bazel @@ -1,3 +1,4 @@ +load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory") load("@npm//:defs.bzl", "npm_link_all_packages") load("//src/aria:config.bzl", "ARIA_TARGETS") load("//tools:defaults.bzl", "ng_package", "ts_project") @@ -19,9 +20,16 @@ ng_package( name = "npm_package", package_name = "@angular/aria", srcs = ["package.json"], + nested_packages = select({ + "//:snapshot_adev_assets": [":adev_assets"], + "//conditions:default": [], + }), package_deps = [ ":node_modules/@angular/cdk", ], + replace_prefixes = { + "adev_assets/": "_adev_assets/", + }, tags = ["release-package"], visibility = [ "//:__pkg__", @@ -31,3 +39,20 @@ ng_package( ], deps = ARIA_TARGETS, ) + +copy_to_directory( + name = "adev_assets", + srcs = [ + "//src/aria/accordion:json_api", + "//src/aria/combobox:json_api", + "//src/aria/grid:json_api", + "//src/aria/listbox:json_api", + "//src/aria/menu:json_api", + "//src/aria/tabs:json_api", + "//src/aria/toolbar:json_api", + "//src/aria/tree:json_api", + ], + replace_prefixes = { + "**/": "", + }, +) diff --git a/src/aria/accordion/BUILD.bazel b/src/aria/accordion/BUILD.bazel index 2876dab751ed..51ffb8340196 100644 --- a/src/aria/accordion/BUILD.bazel +++ b/src/aria/accordion/BUILD.bazel @@ -1,17 +1,16 @@ -load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite") +load("//tools:defaults.bzl", "extract_api_to_json", "ng_project", "ng_web_test_suite") package(default_visibility = ["//visibility:public"]) ng_project( name = "accordion", - srcs = [ - "accordion.ts", - "index.ts", - ], + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), deps = [ "//:node_modules/@angular/core", - "//src/aria/deferred-content", - "//src/aria/ui-patterns", + "//src/aria/private", "//src/cdk/a11y", "//src/cdk/bidi", ], @@ -35,3 +34,23 @@ ng_web_test_suite( name = "unit_tests", deps = [":unit_test_sources"], ) + +filegroup( + name = "source-files", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), +) + +extract_api_to_json( + name = "json_api", + srcs = [ + ":source-files", + ], + entry_point = ":index.ts", + module_name = "@angular/aria/accordion", + output_name = "aria-accordion.json", + private_modules = [""], + repo = "angular/components", +) diff --git a/src/aria/accordion/accordion-content.ts b/src/aria/accordion/accordion-content.ts new file mode 100644 index 000000000000..94dac47652a0 --- /dev/null +++ b/src/aria/accordion/accordion-content.ts @@ -0,0 +1,35 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Directive} from '@angular/core'; +import {DeferredContent} from '../private'; + +/** + * A structural directive that provides a mechanism for lazily rendering the content for an + * `ngAccordionPanel`. + * + * This directive should be applied to an `ng-template` inside an `ngAccordionPanel`. + * It allows the content of the panel to be lazily rendered, improving performance + * by only creating the content when the panel is first expanded. + * + * ```html + *
+ * + *

This is the content that will be displayed inside the panel.

+ *
+ *
+ * ``` + * + * @developerPreview 21.0 + * @see [Accordion](guide/aria/accordion) + */ +@Directive({ + selector: 'ng-template[ngAccordionContent]', + hostDirectives: [DeferredContent], +}) +export class AccordionContent {} diff --git a/src/aria/accordion/accordion-group.ts b/src/aria/accordion/accordion-group.ts new file mode 100644 index 000000000000..4e12b0368347 --- /dev/null +++ b/src/aria/accordion/accordion-group.ts @@ -0,0 +1,158 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Directive, + input, + ElementRef, + inject, + contentChildren, + afterRenderEffect, + signal, + booleanAttribute, + computed, +} from '@angular/core'; +import {Directionality} from '@angular/cdk/bidi'; +import {AccordionGroupPattern, AccordionTriggerPattern} from '../private'; +import {AccordionTrigger} from './accordion-trigger'; +import {AccordionPanel} from './accordion-panel'; +import {ACCORDION_GROUP} from './accordion-tokens'; + +/** + * A container for a group of accordion items. It manages the overall state and + * interactions of the accordion, such as keyboard navigation and expansion mode. + * + * The `ngAccordionGroup` serves as the root of a group of accordion triggers and panels, + * coordinating the behavior of the `ngAccordionTrigger` and `ngAccordionPanel` elements within it. + * It supports both single and multiple expansion modes. + * + * ```html + *
+ *
+ *

+ * + *

+ *
+ * + *

Content for Item 1.

+ *
+ *
+ *
+ *
+ *

+ * + *

+ *
+ * + *

Content for Item 2.

+ *
+ *
+ *
+ *
+ * ``` + * + * @developerPreview 21.0 + * @see [Accordion](guide/aria/accordion) + */ +@Directive({ + selector: '[ngAccordionGroup]', + exportAs: 'ngAccordionGroup', + host: { + '(keydown)': '_pattern.onKeydown($event)', + '(pointerdown)': '_pattern.onPointerdown($event)', + '(focusin)': '_pattern.onFocus($event)', + }, + providers: [{provide: ACCORDION_GROUP, useExisting: AccordionGroup}], +}) +export class AccordionGroup { + /** A reference to the group element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the group element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The AccordionTriggers nested inside this group. */ + private readonly _triggers = contentChildren(AccordionTrigger, {descendants: true}); + + /** The AccordionTrigger patterns nested inside this group. */ + private readonly _triggerPatterns = computed(() => this._triggers().map(t => t._pattern)); + + /** The AccordionPanels nested inside this group. */ + private readonly _panels = contentChildren(AccordionPanel, {descendants: true}); + + /** The text direction (ltr or rtl). */ + readonly textDirection = inject(Directionality).valueSignal; + + /** Whether the entire accordion group is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** Whether multiple accordion items can be expanded simultaneously. */ + readonly multiExpandable = input(true, {transform: booleanAttribute}); + + /** + * Whether to allow disabled items to receive focus. When `true`, disabled items are + * focusable but not interactive. When `false`, disabled items are skipped during navigation. + */ + readonly softDisabled = input(true, {transform: booleanAttribute}); + + /** Whether keyboard navigation should wrap around from the last item to the first, and vice-versa. */ + readonly wrap = input(false, {transform: booleanAttribute}); + + /** The UI pattern instance for this accordion group. */ + readonly _pattern: AccordionGroupPattern = new AccordionGroupPattern({ + ...this, + activeItem: signal(undefined), + items: this._triggerPatterns, + // TODO(ok7sai): Investigate whether an accordion should support horizontal mode. + orientation: () => 'vertical', + getItem: e => this._getItem(e), + element: () => this.element, + }); + + constructor() { + // Effect to link triggers with their corresponding panels and update the group's items. + afterRenderEffect(() => { + const triggers = this._triggers(); + const panels = this._panels(); + + for (const trigger of triggers) { + const panel = panels.find(p => p.panelId() === trigger.panelId()); + trigger._accordionPanelPattern.set(panel?._pattern); + if (panel) { + panel._accordionTriggerPattern.set(trigger._pattern); + } + } + }); + } + + /** Expands all accordion panels if multi-expandable. */ + expandAll() { + this._pattern.expansionBehavior.openAll(); + } + + /** Collapses all accordion panels. */ + collapseAll() { + this._pattern.expansionBehavior.closeAll(); + } + + /** Gets the trigger pattern for a given element. */ + private _getItem(element: Element | null | undefined): AccordionTriggerPattern | undefined { + let target = element; + + while (target) { + const pattern = this._triggerPatterns().find(t => t.element() === target); + if (pattern) { + return pattern; + } + + target = target.parentElement?.closest('[ngAccordionTrigger]'); + } + + return undefined; + } +} diff --git a/src/aria/accordion/accordion-panel.ts b/src/aria/accordion/accordion-panel.ts new file mode 100644 index 000000000000..e7d0749ef5ca --- /dev/null +++ b/src/aria/accordion/accordion-panel.ts @@ -0,0 +1,103 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Directive, + input, + inject, + afterRenderEffect, + signal, + computed, + WritableSignal, +} from '@angular/core'; +import {_IdGenerator} from '@angular/cdk/a11y'; +import {DeferredContentAware, AccordionPanelPattern, AccordionTriggerPattern} from '../private'; + +/** + * The content panel of an accordion item that is conditionally visible. + * + * This directive is a container for the content that is shown or hidden. It requires + * a `panelId` that must match the `panelId` of its corresponding `ngAccordionTrigger`. + * The content within the panel should be provided using an `ng-template` with the + * `ngAccordionContent` directive so that the content is not rendered on the page until the trigger + * is expanded. It applies `role="region"` for accessibility and uses the `inert` attribute to hide + * its content from assistive technologies when not visible. + * + * ```html + *
+ * + *

This content is lazily rendered and will be shown when the panel is expanded.

+ *
+ *
+ * ``` + * + * @developerPreview 21.0 + * @see [Accordion](guide/aria/accordion) + */ +@Directive({ + selector: '[ngAccordionPanel]', + exportAs: 'ngAccordionPanel', + hostDirectives: [ + { + directive: DeferredContentAware, + inputs: ['preserveContent'], + }, + ], + host: { + 'role': 'region', + '[attr.id]': '_pattern.id()', + '[attr.aria-labelledby]': '_pattern.accordionTrigger()?.id()', + '[attr.inert]': '!visible() ? true : null', + }, +}) +export class AccordionPanel { + /** The DeferredContentAware host directive. */ + private readonly _deferredContentAware = inject(DeferredContentAware); + + /** A global unique identifier for the panel. */ + readonly id = input(inject(_IdGenerator).getId('ng-accordion-panel-', true)); + + /** A local unique identifier for the panel, used to match with its trigger's `panelId`. */ + readonly panelId = input.required(); + + /** Whether the accordion panel is visible. True if the associated trigger is expanded. */ + readonly visible = computed(() => !this._pattern.hidden()); + + /** The parent accordion trigger pattern that controls this panel. This is set by AccordionGroup. */ + readonly _accordionTriggerPattern: WritableSignal = + signal(undefined); + + /** The UI pattern instance for this panel. */ + readonly _pattern: AccordionPanelPattern = new AccordionPanelPattern({ + id: this.id, + panelId: this.panelId, + accordionTrigger: () => this._accordionTriggerPattern(), + }); + + constructor() { + // Connect the panel's hidden state to the DeferredContentAware's visibility. + afterRenderEffect(() => { + this._deferredContentAware.contentVisible.set(this.visible()); + }); + } + + /** Expands this item. */ + expand() { + this._accordionTriggerPattern()?.open(); + } + + /** Collapses this item. */ + collapse() { + this._accordionTriggerPattern()?.close(); + } + + /** Toggles the expansion state of this item. */ + toggle() { + this._accordionTriggerPattern()?.toggle(); + } +} diff --git a/src/aria/accordion/accordion-tokens.ts b/src/aria/accordion/accordion-tokens.ts new file mode 100644 index 000000000000..efe8491e8dc6 --- /dev/null +++ b/src/aria/accordion/accordion-tokens.ts @@ -0,0 +1,13 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {InjectionToken} from '@angular/core'; +import type {AccordionGroup} from './accordion-group'; + +/** Token used to expose the accordion group. */ +export const ACCORDION_GROUP = new InjectionToken('ACCORDION_GROUP'); diff --git a/src/aria/accordion/accordion-trigger.ts b/src/aria/accordion/accordion-trigger.ts new file mode 100644 index 000000000000..a2e8fcb5527c --- /dev/null +++ b/src/aria/accordion/accordion-trigger.ts @@ -0,0 +1,107 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Directive, + input, + ElementRef, + inject, + signal, + model, + booleanAttribute, + computed, + WritableSignal, +} from '@angular/core'; +import {_IdGenerator} from '@angular/cdk/a11y'; +import {AccordionPanelPattern, AccordionTriggerPattern} from '../private'; +import {ACCORDION_GROUP} from './accordion-tokens'; + +/** + * The trigger that toggles the visibility of its associated `ngAccordionPanel`. + * + * This directive requires a `panelId` that must match the `panelId` of the `ngAccordionPanel` it + * controls. When clicked, it will expand or collapse the panel. It also handles keyboard + * interactions for navigation within the `ngAccordionGroup`. It applies `role="button"` and manages + * `aria-expanded`, `aria-controls`, and `aria-disabled` attributes for accessibility. + * The `disabled` input can be used to disable the trigger. + * + * ```html + * + * ``` + * + * @developerPreview 21.0 + * @see [Accordion](guide/aria/accordion) + */ +@Directive({ + selector: '[ngAccordionTrigger]', + exportAs: 'ngAccordionTrigger', + host: { + '[attr.data-active]': 'active()', + 'role': 'button', + '[id]': '_pattern.id()', + '[attr.aria-expanded]': 'expanded()', + '[attr.aria-controls]': '_pattern.controls()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.disabled]': '_pattern.hardDisabled() ? true : null', + '[attr.tabindex]': '_pattern.tabIndex()', + }, +}) +export class AccordionTrigger { + /** A reference to the trigger element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the trigger element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The parent AccordionGroup. */ + private readonly _accordionGroup = inject(ACCORDION_GROUP); + + /** A unique identifier for the widget. */ + readonly id = input(inject(_IdGenerator).getId('ng-accordion-trigger-', true)); + + /** A local unique identifier for the trigger, used to match with its panel's `panelId`. */ + readonly panelId = input.required(); + + /** Whether the trigger is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** Whether the corresponding panel is expanded. */ + readonly expanded = model(false); + + /** Whether the trigger is active. */ + readonly active = computed(() => this._pattern.active()); + + /** The accordion panel pattern controlled by this trigger. This is set by AccordionGroup. */ + readonly _accordionPanelPattern: WritableSignal = + signal(undefined); + + /** The UI pattern instance for this trigger. */ + readonly _pattern: AccordionTriggerPattern = new AccordionTriggerPattern({ + ...this, + accordionGroup: computed(() => this._accordionGroup._pattern), + accordionPanel: this._accordionPanelPattern, + element: () => this.element, + }); + + /** Expands this item. */ + expand() { + this._pattern.open(); + } + + /** Collapses this item. */ + collapse() { + this._pattern.close(); + } + + /** Toggles the expansion state of this item. */ + toggle() { + this._pattern.toggle(); + } +} diff --git a/src/aria/accordion/accordion.spec.ts b/src/aria/accordion/accordion.spec.ts index a462023a5db2..ae8b932cedef 100644 --- a/src/aria/accordion/accordion.spec.ts +++ b/src/aria/accordion/accordion.spec.ts @@ -1,16 +1,17 @@ -import {Component, DebugElement, signal, model} from '@angular/core'; +import {Component, DebugElement, signal} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {provideFakeDirectionality, runAccessibilityChecks} from '@angular/cdk/testing/private'; import {_IdGenerator} from '@angular/cdk/a11y'; -import {AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent} from './accordion'; +import {AccordionPanel} from './accordion-panel'; +import {AccordionTrigger} from './accordion-trigger'; +import {AccordionContent} from './accordion-content'; +import {AccordionGroup} from './accordion-group'; describe('AccordionGroup', () => { let fixture: ComponentFixture; - let groupDebugElement: DebugElement; let triggerDebugElements: DebugElement[]; let panelDebugElements: DebugElement[]; - let groupInstance: AccordionGroup; let triggerElements: HTMLElement[]; let panelElements: HTMLElement[]; @@ -32,28 +33,25 @@ describe('AccordionGroup', () => { const endKey = (target: HTMLElement) => keydown(target, 'End'); interface SetupOptions { - initialValue?: string[]; multiExpandable?: boolean; disabledGroup?: boolean; + expandedItemValues?: string[]; disabledItemValues?: string[]; - skipDisabled?: boolean; + softDisabled?: boolean; wrap?: boolean; } function configureAccordionComponent(opts: SetupOptions = {}) { const testComponent = fixture.componentInstance as AccordionGroupExample; - if (opts.initialValue !== undefined) { - testComponent.value.set(opts.initialValue); - } if (opts.multiExpandable !== undefined) { testComponent.multiExpandable.set(opts.multiExpandable); } if (opts.disabledGroup !== undefined) { testComponent.disabledGroup.set(opts.disabledGroup); } - if (opts.skipDisabled !== undefined) { - testComponent.skipDisabled.set(opts.skipDisabled); + if (opts.softDisabled !== undefined) { + testComponent.softDisabled.set(opts.softDisabled); } if (opts.wrap !== undefined) { testComponent.wrap.set(opts.wrap); @@ -61,17 +59,18 @@ describe('AccordionGroup', () => { if (opts.disabledItemValues !== undefined) { opts.disabledItemValues.forEach(value => testComponent.disableItem(value, true)); } + if (opts.expandedItemValues !== undefined) { + opts.expandedItemValues.forEach(value => testComponent.expandItem(value, true)); + } fixture.detectChanges(); defineTestVariables(fixture); } function defineTestVariables(currentFixture: ComponentFixture) { - groupDebugElement = currentFixture.debugElement.query(By.directive(AccordionGroup)); triggerDebugElements = currentFixture.debugElement.queryAll(By.directive(AccordionTrigger)); panelDebugElements = currentFixture.debugElement.queryAll(By.directive(AccordionPanel)); - groupInstance = groupDebugElement.injector.get(AccordionGroup); triggerElements = triggerDebugElements.map(el => el.nativeElement); panelElements = panelDebugElements.map(el => el.nativeElement); } @@ -109,7 +108,7 @@ describe('AccordionGroup', () => { }); it('should have aria-expanded="false" when collapsed', () => { - configureAccordionComponent({initialValue: []}); + configureAccordionComponent(); expect(triggerElements[0].getAttribute('aria-expanded')).toBe('false'); expect(triggerElements[1].getAttribute('aria-expanded')).toBe('false'); expect(triggerElements[2].getAttribute('aria-expanded')).toBe('false'); @@ -154,7 +153,7 @@ describe('AccordionGroup', () => { }); it('should have "inert" attribute when collapsed', () => { - configureAccordionComponent({initialValue: []}); + configureAccordionComponent(); expect(panelElements[0].hasAttribute('inert')).toBeTrue(); expect(panelElements[1].hasAttribute('inert')).toBeTrue(); expect(panelElements[2].hasAttribute('inert')).toBeTrue(); @@ -168,36 +167,32 @@ describe('AccordionGroup', () => { configureAccordionComponent({multiExpandable: false}); }); - it('should expand panel on trigger click and update value', () => { + it('should expand panel on trigger click and update expanded panels', () => { click(triggerElements[0]); expect(isTriggerExpanded(triggerElements[0])).toBeTrue(); expect(panelElements[0].hasAttribute('inert')).toBeFalse(); - expect(groupInstance.value()).toEqual(['item-1']); }); - it('should collapes panel on trigger click and update value', () => { + it('should collapes panel on trigger click and update expanded panels', () => { click(triggerElements[0]); click(triggerElements[0]); // Collapse expect(isTriggerExpanded(triggerElements[0])).toBeFalse(); expect(panelElements[0].hasAttribute('inert')).toBeTrue(); - expect(groupInstance.value()).toEqual([]); }); it('should expand one and collapse others', () => { click(triggerElements[0]); expect(isTriggerExpanded(triggerElements[0])).toBeTrue(); - expect(groupInstance.value()).toEqual(['item-1']); click(triggerElements[1]); expect(isTriggerExpanded(triggerElements[0])).toBeFalse(); expect(panelElements[0].hasAttribute('inert')).toBeTrue(); expect(isTriggerExpanded(triggerElements[1])).toBeTrue(); expect(panelElements[1].hasAttribute('inert')).toBeFalse(); - expect(groupInstance.value()).toEqual(['item-2']); }); it('should allow setting initial value', () => { - configureAccordionComponent({initialValue: ['item-2'], multiExpandable: false}); + configureAccordionComponent({expandedItemValues: ['item-2'], multiExpandable: false}); expect(isTriggerExpanded(triggerElements[0])).toBeFalse(); expect(isTriggerExpanded(triggerElements[1])).toBeTrue(); expect(isTriggerExpanded(triggerElements[2])).toBeFalse(); @@ -221,16 +216,19 @@ describe('AccordionGroup', () => { it('should collapse an item without affecting others', () => { click(triggerElements[0]); click(triggerElements[1]); - expect(groupInstance.value()).toEqual(jasmine.arrayWithExactContents(['item-1', 'item-2'])); + expect(isTriggerExpanded(triggerElements[0])).toBeTrue(); + expect(isTriggerExpanded(triggerElements[1])).toBeTrue(); click(triggerElements[0]); expect(isTriggerExpanded(triggerElements[0])).toBeFalse(); expect(isTriggerExpanded(triggerElements[1])).toBeTrue(); - expect(groupInstance.value()).toEqual(['item-2']); }); it('should allow setting initial multiple values', () => { - configureAccordionComponent({initialValue: ['item-1', 'item-3'], multiExpandable: true}); + configureAccordionComponent({ + expandedItemValues: ['item-1', 'item-3'], + multiExpandable: true, + }); expect(isTriggerExpanded(triggerElements[0])).toBeTrue(); expect(isTriggerExpanded(triggerElements[1])).toBeFalse(); expect(isTriggerExpanded(triggerElements[2])).toBeTrue(); @@ -242,7 +240,6 @@ describe('AccordionGroup', () => { configureAccordionComponent({disabledItemValues: ['item-1']}); click(triggerElements[0]); expect(isTriggerExpanded(triggerElements[0])).toBeFalse(); - expect(groupInstance.value()).toEqual([]); expect(triggerElements[0].getAttribute('aria-disabled')).toBe('true'); }); @@ -250,7 +247,6 @@ describe('AccordionGroup', () => { configureAccordionComponent({disabledGroup: true}); click(triggerElements[0]); expect(isTriggerExpanded(triggerElements[0])).toBeFalse(); - expect(groupInstance.value()).toEqual([]); click(triggerElements[1]); expect(isTriggerExpanded(triggerElements[1])).toBeFalse(); }); @@ -342,17 +338,17 @@ describe('AccordionGroup', () => { }); }); - describe('skipDisabled behavior', () => { - it('should skip disabled items if skipDisabled=true', () => { - configureAccordionComponent({skipDisabled: true, disabledItemValues: ['item-2']}); + describe('softDisabled behavior', () => { + it('should skip disabled items if softDisabled=false', () => { + configureAccordionComponent({softDisabled: false, disabledItemValues: ['item-2']}); expect(isTriggerActive(triggerElements[0])).toBeTrue(); downArrowKey(triggerElements[0]); expect(isTriggerActive(triggerElements[2])).toBeTrue(); }); - it('should focus disabled items if skipDisabled=false', () => { - configureAccordionComponent({skipDisabled: false, disabledItemValues: ['item-2']}); + it('should focus disabled items if softDisabled=true', () => { + configureAccordionComponent({softDisabled: true, disabledItemValues: ['item-2']}); expect(isTriggerActive(triggerElements[0])).toBeTrue(); downArrowKey(triggerElements[0]); @@ -382,22 +378,22 @@ describe('AccordionGroup', () => { template: `
- @for (item of items(); track item.value) { + @for (item of items(); track item.panelId) {
{{ item.content }} @@ -411,20 +407,43 @@ describe('AccordionGroup', () => { }) class AccordionGroupExample { items = signal([ - {value: 'item-1', header: 'Item 1 Header', content: 'Item 1 Content', disabled: false}, - {value: 'item-2', header: 'Item 2 Header', content: 'Item 2 Content', disabled: false}, - {value: 'item-3', header: 'Item 3 Header', content: 'Item 3 Content', disabled: false}, + { + panelId: 'item-1', + header: 'Item 1 Header', + content: 'Item 1 Content', + disabled: false, + expanded: false, + }, + { + panelId: 'item-2', + header: 'Item 2 Header', + content: 'Item 2 Content', + disabled: false, + expanded: false, + }, + { + panelId: 'item-3', + header: 'Item 3 Header', + content: 'Item 3 Content', + disabled: false, + expanded: false, + }, ]); - value = model([]); multiExpandable = signal(false); disabledGroup = signal(false); - skipDisabled = signal(true); + softDisabled = signal(true); wrap = signal(false); disableItem(itemValue: string, disabled: boolean) { this.items.update(items => - items.map(item => (item.value === itemValue ? {...item, disabled} : item)), + items.map(item => (item.panelId === itemValue ? {...item, disabled} : item)), + ); + } + + expandItem(itemValue: string, expanded: boolean) { + this.items.update(items => + items.map(item => (item.panelId === itemValue ? {...item, expanded} : item)), ); } } diff --git a/src/aria/accordion/accordion.ts b/src/aria/accordion/accordion.ts deleted file mode 100644 index 504c430a957f..000000000000 --- a/src/aria/accordion/accordion.ts +++ /dev/null @@ -1,217 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import { - Directive, - input, - ElementRef, - inject, - contentChildren, - afterRenderEffect, - signal, - model, - booleanAttribute, - computed, - WritableSignal, -} from '@angular/core'; -import {_IdGenerator} from '@angular/cdk/a11y'; -import {Directionality} from '@angular/cdk/bidi'; -import {DeferredContent, DeferredContentAware} from '@angular/aria/deferred-content'; -import { - AccordionGroupPattern, - AccordionPanelPattern, - AccordionTriggerPattern, -} from '@angular/aria/ui-patterns'; - -/** - * Represents the content panel of an accordion item. It is controlled by an - * associated `AccordionTrigger`. - */ -@Directive({ - selector: '[ngAccordionPanel]', - exportAs: 'ngAccordionPanel', - hostDirectives: [ - { - directive: DeferredContentAware, - inputs: ['preserveContent'], - }, - ], - host: { - 'class': 'ng-accordion-panel', - 'role': 'region', - '[attr.id]': 'pattern.id()', - '[attr.aria-labelledby]': 'pattern.accordionTrigger()?.id()', - '[attr.inert]': 'pattern.hidden() ? true : null', - }, -}) -export class AccordionPanel { - /** The DeferredContentAware host directive. */ - private readonly _deferredContentAware = inject(DeferredContentAware); - - /** A global unique identifier for the panel. */ - private readonly _id = inject(_IdGenerator).getId('accordion-trigger-'); - - /** A local unique identifier for the panel, used to match with its trigger's value. */ - value = input.required(); - - /** The parent accordion trigger pattern that controls this panel. This is set by AccordionGroup. */ - readonly accordionTrigger: WritableSignal = - signal(undefined); - - /** The UI pattern instance for this panel. */ - readonly pattern: AccordionPanelPattern = new AccordionPanelPattern({ - id: () => this._id, - value: this.value, - accordionTrigger: () => this.accordionTrigger(), - }); - - constructor() { - // Connect the panel's hidden state to the DeferredContentAware's visibility. - afterRenderEffect(() => { - this._deferredContentAware.contentVisible.set(!this.pattern.hidden()); - }); - } -} - -/** - * Represents the trigger button for an accordion item. It controls the expansion - * state of an associated `AccordionPanel`. - */ -@Directive({ - selector: '[ngAccordionTrigger]', - exportAs: 'ngAccordionTrigger', - host: { - 'class': 'ng-accordion-trigger', - '[attr.data-active]': 'pattern.active()', - 'role': 'button', - '[id]': 'pattern.id()', - '[attr.aria-expanded]': 'pattern.expanded()', - '[attr.aria-controls]': 'pattern.controls()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[attr.disabled]': 'hardDisabled() ? true : null', - '[attr.tabindex]': 'pattern.tabindex()', - '(keydown)': 'pattern.onKeydown($event)', - '(pointerdown)': 'pattern.onPointerdown($event)', - '(focusin)': 'pattern.onFocus($event)', - }, -}) -export class AccordionTrigger { - /** A global unique identifier for the trigger. */ - private readonly _id = inject(_IdGenerator).getId('ng-accordion-trigger-'); - - /** A reference to the trigger element. */ - private readonly _elementRef = inject(ElementRef); - - /** The parent AccordionGroup. */ - private readonly _accordionGroup = inject(AccordionGroup); - - /** A local unique identifier for the trigger, used to match with its panel's value. */ - value = input.required(); - - /** Whether the trigger is disabled. */ - disabled = input(false, {transform: booleanAttribute}); - - /** - * Whether this trigger is completely inaccessible. - * - * TODO(ok7sai): Consider move this to UI patterns. - */ - readonly hardDisabled = computed(() => this.pattern.disabled() && this.pattern.tabindex() < 0); - - /** The accordion panel pattern controlled by this trigger. This is set by AccordionGroup. */ - readonly accordionPanel: WritableSignal = signal(undefined); - - /** The UI pattern instance for this trigger. */ - readonly pattern: AccordionTriggerPattern = new AccordionTriggerPattern({ - id: () => this._id, - value: this.value, - disabled: this.disabled, - element: () => this._elementRef.nativeElement, - accordionGroup: computed(() => this._accordionGroup.pattern), - accordionPanel: this.accordionPanel, - }); -} - -/** - * Container for a group of accordion items. It manages the overall state and - * interactions of the accordion, such as keyboard navigation and expansion mode. - */ -@Directive({ - selector: '[ngAccordionGroup]', - exportAs: 'ngAccordionGroup', - host: { - 'class': 'ng-accordion-group', - }, -}) -export class AccordionGroup { - /** A reference to the group element. */ - private readonly _elementRef = inject(ElementRef); - - /** The AccordionTriggers nested inside this group. */ - protected readonly _triggers = contentChildren(AccordionTrigger, {descendants: true}); - - /** The AccordionPanels nested inside this group. */ - protected readonly _panels = contentChildren(AccordionPanel, {descendants: true}); - - /** The text direction (ltr or rtl). */ - readonly textDirection = inject(Directionality).valueSignal; - - /** Whether the entire accordion group is disabled. */ - disabled = input(false, {transform: booleanAttribute}); - - /** Whether multiple accordion items can be expanded simultaneously. */ - multiExpandable = input(true, {transform: booleanAttribute}); - - /** The values of the current selected/expanded accordions. */ - value = model([]); - - /** Whether disabled items should be skipped during keyboard navigation. */ - skipDisabled = input(true, {transform: booleanAttribute}); - - /** Whether keyboard navigation should wrap around from the last item to the first, and vice-versa. */ - wrap = input(false, {transform: booleanAttribute}); - - /** The UI pattern instance for this accordion group. */ - readonly pattern: AccordionGroupPattern = new AccordionGroupPattern({ - ...this, - // TODO(ok7sai): Consider making `activeItem` an internal state in the pattern and call - // `setDefaultState` in the CDK. - activeItem: signal(undefined), - items: computed(() => this._triggers().map(trigger => trigger.pattern)), - expandedIds: this.value, - // TODO(ok7sai): Investigate whether an accordion should support horizontal mode. - orientation: () => 'vertical', - element: () => this._elementRef.nativeElement, - }); - - constructor() { - // Effect to link triggers with their corresponding panels and update the group's items. - afterRenderEffect(() => { - const triggers = this._triggers(); - const panels = this._panels(); - - for (const trigger of triggers) { - const panel = panels.find(p => p.value() === trigger.value()); - trigger.accordionPanel.set(panel?.pattern); - if (panel) { - panel.accordionTrigger.set(trigger.pattern); - } - } - }); - } -} - -/** - * A structural directive that marks the `ng-template` to be used as the content - * for a `AccordionPanel`. This content can be lazily loaded. - */ -@Directive({ - selector: 'ng-template[ngAccordionContent]', - hostDirectives: [DeferredContent], -}) -export class AccordionContent {} diff --git a/src/aria/accordion/index.ts b/src/aria/accordion/index.ts index 66aa4d173aa8..8f2c83525069 100644 --- a/src/aria/accordion/index.ts +++ b/src/aria/accordion/index.ts @@ -6,4 +6,11 @@ * found in the LICENSE file at https://angular.dev/license */ -export {AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent} from './accordion'; +export {AccordionPanel} from './accordion-panel'; +export {AccordionGroup} from './accordion-group'; +export {AccordionTrigger} from './accordion-trigger'; +export {AccordionContent} from './accordion-content'; + +// This needs to be re-exported, because it's used by the accordion components. +// See: https://github.com/angular/components/issues/30663. +export {DeferredContent as ɵɵDeferredContent} from '../private'; diff --git a/src/aria/accordion/public-api.ts b/src/aria/accordion/public-api.ts new file mode 100644 index 000000000000..73d592f44124 --- /dev/null +++ b/src/aria/accordion/public-api.ts @@ -0,0 +1,19 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +export {AccordionPanel} from './accordion-panel'; +export {AccordionGroup} from './accordion-group'; +export {AccordionTrigger} from './accordion-trigger'; +export {AccordionContent} from './accordion-content'; + +// This needs to be re-exported, because it's used by the accordion components. +// See: https://github.com/angular/components/issues/30663. +export { + DeferredContent as ɵɵDeferredContent, + DeferredContentAware as ɵɵDeferredContentAware, +} from '../private'; diff --git a/src/aria/combobox/BUILD.bazel b/src/aria/combobox/BUILD.bazel index 410b5174c435..e0b7cbae2ad0 100644 --- a/src/aria/combobox/BUILD.bazel +++ b/src/aria/combobox/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite", "ts_project") +load("//tools:defaults.bzl", "extract_api_to_json", "ng_project", "ng_web_test_suite", "ts_project") package(default_visibility = ["//visibility:public"]) @@ -10,8 +10,7 @@ ng_project( ), deps = [ "//:node_modules/@angular/core", - "//src/aria/deferred-content", - "//src/aria/ui-patterns", + "//src/aria/private", "//src/cdk/bidi", ], ) @@ -39,3 +38,23 @@ ng_web_test_suite( name = "unit_tests", deps = [":unit_test_sources"], ) + +filegroup( + name = "source-files", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), +) + +extract_api_to_json( + name = "json_api", + srcs = [ + ":source-files", + ], + entry_point = ":index.ts", + module_name = "@angular/aria/combobox", + output_name = "aria-combobox.json", + private_modules = [""], + repo = "angular/components", +) diff --git a/src/aria/combobox/combobox-dialog.ts b/src/aria/combobox/combobox-dialog.ts new file mode 100644 index 000000000000..903d3087d3c0 --- /dev/null +++ b/src/aria/combobox/combobox-dialog.ts @@ -0,0 +1,84 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {afterRenderEffect, Directive, ElementRef, inject} from '@angular/core'; +import {ComboboxDialogPattern} from '../private'; +import {Combobox} from './combobox'; +import {ComboboxPopup} from './combobox-popup'; + +/** + * Integrates a native `` element with the combobox, allowing for + * a modal or non-modal popup experience. It handles the opening and closing of the dialog + * based on the combobox's expanded state. + * + * ```html + * + * + * + * + * + * ``` + * + * @developerPreview 21.0 + * + * @see [Combobox](guide/aria/combobox) + * @see [Select](guide/aria/select) + * @see [Multiselect](guide/aria/multiselect) + * @see [Autocomplete](guide/aria/autocomplete) + */ +@Directive({ + selector: 'dialog[ngComboboxDialog]', + exportAs: 'ngComboboxDialog', + host: { + '[attr.data-open]': 'combobox._pattern.expanded()', + '(keydown)': '_pattern.onKeydown($event)', + '(click)': '_pattern.onClick($event)', + }, + hostDirectives: [ComboboxPopup], +}) +export class ComboboxDialog { + /** The dialog element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the dialog element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The combobox that the dialog belongs to. */ + readonly combobox = inject(Combobox); + + /** A reference to the parent combobox popup, if one exists. */ + private readonly _popup = inject>(ComboboxPopup, { + optional: true, + }); + + _pattern: ComboboxDialogPattern; + + constructor() { + this._pattern = new ComboboxDialogPattern({ + id: () => '', + element: () => this._elementRef.nativeElement, + combobox: this.combobox._pattern, + }); + + if (this._popup) { + this._popup._controls.set(this._pattern); + } + + afterRenderEffect(() => { + if (this._elementRef) { + this.combobox._pattern.expanded() + ? this._elementRef.nativeElement.showModal() + : this._elementRef.nativeElement.close(); + } + }); + } + + close() { + this._popup?.combobox?._pattern.close(); + } +} diff --git a/src/aria/combobox/combobox-input.ts b/src/aria/combobox/combobox-input.ts new file mode 100644 index 000000000000..3a79ba895b77 --- /dev/null +++ b/src/aria/combobox/combobox-input.ts @@ -0,0 +1,90 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + afterRenderEffect, + Directive, + ElementRef, + inject, + model, + untracked, + WritableSignal, +} from '@angular/core'; +import {ComboboxDialogPattern} from '../private'; +import {Combobox} from './combobox'; + +/** + * An input that is part of a combobox. It is responsible for displaying the + * current value and handling user input for filtering and selection. + * + * This directive should be applied to an `` element within an `ngCombobox` + * container. It automatically handles keyboard interactions, such as opening the + * popup and navigating through the options. + * + * ```html + * + * ``` + * + * @developerPreview 21.0 + * + * @see [Combobox](guide/aria/combobox) + * @see [Select](guide/aria/select) + * @see [Multiselect](guide/aria/multiselect) + * @see [Autocomplete](guide/aria/autocomplete) + */ +@Directive({ + selector: 'input[ngComboboxInput]', + exportAs: 'ngComboboxInput', + host: { + 'role': 'combobox', + '[value]': 'value()', + '[attr.aria-disabled]': 'combobox._pattern.disabled()', + '[attr.aria-expanded]': 'combobox._pattern.expanded()', + '[attr.aria-activedescendant]': 'combobox._pattern.activeDescendant()', + '[attr.aria-controls]': 'combobox._pattern.popupId()', + '[attr.aria-haspopup]': 'combobox._pattern.hasPopup()', + '[attr.aria-autocomplete]': 'combobox._pattern.autocomplete()', + '[attr.readonly]': 'combobox._pattern.readonly()', + }, +}) +export class ComboboxInput { + /** The element that the combobox is attached to. */ + private readonly _elementRef = inject>(ElementRef); + + /** A reference to the input element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The combobox that the input belongs to. */ + readonly combobox = inject(Combobox); + + /** The value of the input. */ + value = model(''); + + constructor() { + (this.combobox._pattern.inputs.inputEl as WritableSignal).set( + this._elementRef.nativeElement, + ); + this.combobox._pattern.inputs.inputValue = this.value; + + const controls = this.combobox.popup()?._controls(); + if (controls instanceof ComboboxDialogPattern) { + return; + } + + /** Focuses & selects the first item in the combobox if the user changes the input value. */ + afterRenderEffect(() => { + this.value(); + controls?.items(); + untracked(() => this.combobox._pattern.onFilter()); + }); + } +} diff --git a/src/aria/combobox/combobox-popup-container.ts b/src/aria/combobox/combobox-popup-container.ts new file mode 100644 index 000000000000..d25e3bb90531 --- /dev/null +++ b/src/aria/combobox/combobox-popup-container.ts @@ -0,0 +1,52 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Directive} from '@angular/core'; +import {DeferredContent} from '../private'; + +/** + * A structural directive that marks the `ng-template` to be used as the popup + * for a combobox. This content is conditionally rendered. + * + * The content of the popup can be a `ngListbox`, `ngTree`, or `role="dialog"`, allowing for + * flexible and complex combobox implementations. The consumer is responsible for + * implementing the filtering logic based on the `ngComboboxInput`'s value. + * + * ```html + * + *
+ * + *
+ *
+ * ``` + * + * When using CdkOverlay, this directive can be replaced by `cdkConnectedOverlay`. + * + * ```html + * + *
+ * + *
+ *
+ * ``` + * + * @developerPreview 21.0 + * + * @see [Combobox](guide/aria/combobox) + * @see [Select](guide/aria/select) + * @see [Multiselect](guide/aria/multiselect) + * @see [Autocomplete](guide/aria/autocomplete) + */ +@Directive({ + selector: 'ng-template[ngComboboxPopupContainer]', + exportAs: 'ngComboboxPopupContainer', + hostDirectives: [DeferredContent], +}) +export class ComboboxPopupContainer {} diff --git a/src/aria/combobox/combobox-popup.ts b/src/aria/combobox/combobox-popup.ts new file mode 100644 index 000000000000..3ecc0d227732 --- /dev/null +++ b/src/aria/combobox/combobox-popup.ts @@ -0,0 +1,44 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Directive, inject, signal} from '@angular/core'; +import {ComboboxListboxControls, ComboboxTreeControls, ComboboxDialogPattern} from '../private'; +import type {Combobox} from './combobox'; +import {COMBOBOX} from './combobox-tokens'; + +/** + * Identifies an element as a popup for an `ngCombobox`. + * + * This directive acts as a bridge, allowing the `ngCombobox` to discover and interact + * with the underlying control (e.g., `ngListbox`, `ngTree`, or `ngComboboxDialog`) that + * manages the options. It's primarily used as a host directive and is responsible for + * exposing the popup's control pattern to the parent combobox. + * + * @developerPreview 21.0 + * + * @see [Combobox](guide/aria/combobox) + * @see [Select](guide/aria/select) + * @see [Multiselect](guide/aria/multiselect) + * @see [Autocomplete](guide/aria/autocomplete) + */ +@Directive({ + selector: '[ngComboboxPopup]', + exportAs: 'ngComboboxPopup', +}) +export class ComboboxPopup { + /** The combobox that the popup belongs to. */ + readonly combobox = inject>(COMBOBOX, {optional: true}); + + /** The popup controls exposed to the combobox. */ + readonly _controls = signal< + | ComboboxListboxControls + | ComboboxTreeControls + | ComboboxDialogPattern + | undefined + >(undefined); +} diff --git a/src/aria/combobox/combobox-tokens.ts b/src/aria/combobox/combobox-tokens.ts new file mode 100644 index 000000000000..bcc7d9d1c4d8 --- /dev/null +++ b/src/aria/combobox/combobox-tokens.ts @@ -0,0 +1,13 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {InjectionToken} from '@angular/core'; +import type {Combobox} from './combobox'; + +/** Token used to provide the combobox to child components. */ +export const COMBOBOX = new InjectionToken>('COMBOBOX'); diff --git a/src/aria/combobox/combobox.spec.ts b/src/aria/combobox/combobox.spec.ts index 4eae17061f5e..0cbeca485a38 100644 --- a/src/aria/combobox/combobox.spec.ts +++ b/src/aria/combobox/combobox.spec.ts @@ -1,5 +1,5 @@ import {Component, computed, DebugElement, signal} from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Combobox, ComboboxInput, ComboboxPopup, ComboboxPopupContainer} from '../combobox'; import {Listbox, Option} from '../listbox'; @@ -33,7 +33,7 @@ describe('Combobox', () => { const click = (element: HTMLElement, eventInit?: PointerEventInit) => { focus(); - element.dispatchEvent(new PointerEvent('pointerup', {bubbles: true, ...eventInit})); + element.dispatchEvent(new PointerEvent('click', {bubbles: true, ...eventInit})); fixture.detectChanges(); }; @@ -52,14 +52,18 @@ describe('Combobox', () => { const enter = (modifierKeys?: {}) => keydown('Enter', modifierKeys); const escape = (modifierKeys?: {}) => keydown('Escape', modifierKeys); - function setupCombobox(opts: {filterMode?: 'manual' | 'auto-select' | 'highlight'} = {}) { - TestBed.configureTestingModule({}); + function setupCombobox( + opts: {readonly?: boolean; filterMode?: 'manual' | 'auto-select' | 'highlight'} = {}, + ) { fixture = TestBed.createComponent(ComboboxListboxExample); const testComponent = fixture.componentInstance; if (opts.filterMode) { testComponent.filterMode.set(opts.filterMode); } + if (opts.readonly) { + testComponent.readonly.set(true); + } fixture.detectChanges(); defineTestVariables(); @@ -206,12 +210,6 @@ describe('Combobox', () => { describe('Expansion', () => { beforeEach(() => setupCombobox()); - it('should open on click', () => { - focus(); - click(inputElement); - expect(inputElement.getAttribute('aria-expanded')).toBe('true'); - }); - it('should open on ArrowDown', () => { focus(); keydown('ArrowDown'); @@ -242,17 +240,19 @@ describe('Combobox', () => { expect(inputElement.getAttribute('aria-expanded')).toBe('true'); }); - it('should clear the completion string and not close on escape when a completion is present', () => { + it('should close then clear the completion string', () => { fixture.componentInstance.filterMode.set('highlight'); focus(); - input('A'); + input('Ala'); expect(inputElement.value).toBe('Alabama'); expect(inputElement.getAttribute('aria-expanded')).toBe('true'); escape(); - expect(inputElement.value).toBe('A'); - expect(inputElement.getAttribute('aria-expanded')).toBe('true'); + expect(inputElement.value).toBe('Alabama'); + expect(inputElement.selectionEnd).toBe(7); + expect(inputElement.selectionStart).toBe(3); + expect(inputElement.getAttribute('aria-expanded')).toBe('false'); // close escape(); - expect(inputElement.value).toBe('A'); + expect(inputElement.value).toBe(''); // clear input expect(inputElement.getAttribute('aria-expanded')).toBe('false'); }); @@ -280,7 +280,7 @@ describe('Combobox', () => { click(options[0]); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['Alabama']); + expect(fixture.componentInstance.values()).toEqual(['Alabama']); expect(inputElement.value).toBe('Alabama'); }); @@ -289,7 +289,7 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Alabama']); + expect(fixture.componentInstance.values()).toEqual(['Alabama']); expect(inputElement.value).toBe('Alabama'); }); @@ -297,7 +297,7 @@ describe('Combobox', () => { down(); down(); - expect(fixture.componentInstance.value()).toEqual([]); + expect(fixture.componentInstance.values()).toEqual([]); }); it('should select on focusout if the input text exactly matches an item', () => { @@ -305,7 +305,7 @@ describe('Combobox', () => { input('Alabama'); blur(); - expect(fixture.componentInstance.value()).toEqual(['Alabama']); + expect(fixture.componentInstance.values()).toEqual(['Alabama']); }); it('should not select on focusout if the input text does not match an item', () => { @@ -313,7 +313,7 @@ describe('Combobox', () => { input('Appl'); blur(); - expect(fixture.componentInstance.value()).toEqual([]); + expect(fixture.componentInstance.values()).toEqual([]); expect(inputElement.value).toBe('Appl'); }); }); @@ -327,7 +327,7 @@ describe('Combobox', () => { click(options[1]); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['Alaska']); + expect(fixture.componentInstance.values()).toEqual(['Alaska']); expect(inputElement.value).toBe('Alaska'); }); @@ -336,26 +336,26 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Alaska']); + expect(fixture.componentInstance.values()).toEqual(['Alaska']); expect(inputElement.value).toBe('Alaska'); }); it('should select on navigation', () => { down(); - expect(fixture.componentInstance.value()).toEqual(['Alabama']); + expect(fixture.componentInstance.values()).toEqual(['Alabama']); down(); - expect(fixture.componentInstance.value()).toEqual(['Alaska']); + expect(fixture.componentInstance.values()).toEqual(['Alaska']); down(); - expect(fixture.componentInstance.value()).toEqual(['Arizona']); + expect(fixture.componentInstance.values()).toEqual(['Arizona']); }); it('should select the first option on input', () => { focus(); input('W'); - expect(fixture.componentInstance.value()).toEqual(['Washington']); + expect(fixture.componentInstance.values()).toEqual(['Washington']); }); it('should commit the selected option on focusout', () => { @@ -364,7 +364,7 @@ describe('Combobox', () => { blur(); expect(inputElement.value).toBe('Georgia'); - expect(fixture.componentInstance.value()).toEqual(['Georgia']); + expect(fixture.componentInstance.values()).toEqual(['Georgia']); }); }); @@ -377,7 +377,7 @@ describe('Combobox', () => { click(options[2]); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['Arizona']); + expect(fixture.componentInstance.values()).toEqual(['Arizona']); expect(inputElement.value).toBe('Arizona'); }); @@ -387,16 +387,16 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Arizona']); + expect(fixture.componentInstance.values()).toEqual(['Arizona']); expect(inputElement.value).toBe('Arizona'); }); it('should select on navigation', () => { down(); - expect(fixture.componentInstance.value()).toEqual(['Alabama']); + expect(fixture.componentInstance.values()).toEqual(['Alabama']); down(); - expect(fixture.componentInstance.value()).toEqual(['Alaska']); + expect(fixture.componentInstance.values()).toEqual(['Alaska']); }); it('should update input value on navigation', () => { @@ -411,18 +411,36 @@ describe('Combobox', () => { focus(); input('Cali'); - expect(fixture.componentInstance.value()).toEqual(['California']); + expect(fixture.componentInstance.values()).toEqual(['California']); }); - it('should insert a highlighted completion string on input', fakeAsync(() => { + it('should insert a highlighted completion string on input', () => { focus(); input('A'); - tick(); expect(inputElement.value).toBe('Alabama'); expect(inputElement.selectionStart).toBe(1); expect(inputElement.selectionEnd).toBe(7); - })); + }); + + it('should not insert a completion string on backspace', () => { + focus(); + input('New'); + + expect(inputElement.value).toBe('New Hampshire'); + expect(inputElement.selectionStart).toBe(3); + expect(inputElement.selectionEnd).toBe(13); + }); + + it('should insert a completion string even if the items are not changed', () => { + focus(); + input('New'); + + input('New '); + expect(inputElement.value).toBe('New Hampshire'); + expect(inputElement.selectionStart).toBe(4); + expect(inputElement.selectionEnd).toBe(13); + }); it('should commit the selected option on focusout', () => { focus(); @@ -430,7 +448,7 @@ describe('Combobox', () => { blur(); expect(inputElement.value).toBe('California'); - expect(fixture.componentInstance.value()).toEqual(['California']); + expect(fixture.componentInstance.values()).toEqual(['California']); }); }); }); @@ -438,15 +456,15 @@ describe('Combobox', () => { // TODO(wagnermaciel): Add unit tests for disabled options. describe('Filtering', () => { - beforeEach(() => setupCombobox()); - it('should lazily render options', () => { + setupCombobox(); expect(getOptions().length).toBe(0); focus(); expect(getOptions().length).toBe(50); }); it('should filter the options based on the input value', () => { + setupCombobox(); focus(); input('New'); @@ -459,6 +477,7 @@ describe('Combobox', () => { }); it('should show no options if nothing matches', () => { + setupCombobox(); focus(); input('xyz'); const options = getOptions(); @@ -466,6 +485,7 @@ describe('Combobox', () => { }); it('should show all options when the input is cleared', () => { + setupCombobox(); focus(); input('Alabama'); expect(getOptions().length).toBe(1); @@ -473,6 +493,51 @@ describe('Combobox', () => { input(''); expect(getOptions().length).toBe(50); }); + + it('should determine the highlighted state on open', () => { + setupCombobox({filterMode: 'highlight'}); + focus(); + input('N'); + expect(inputElement.value).toBe('Nebraska'); + expect(inputElement.selectionEnd).toBe(8); + expect(inputElement.selectionStart).toBe(1); + expect(getOptions().length).toBe(8); + + escape(); // close + inputElement.selectionStart = 2; // Change highlighting + down(); // open + + expect(inputElement.value).toBe('Nebraska'); + expect(inputElement.selectionEnd).toBe(8); + expect(inputElement.selectionStart).toBe(2); + expect(getOptions().length).toBe(6); + + escape(); // close + inputElement.selectionStart = 3; // Change highlighting + down(); // open + + expect(getOptions().length).toBe(1); + }); + }); + + describe('Readonly', () => { + beforeEach(() => setupCombobox({readonly: true})); + + it('should close on selection', () => { + focus(); + down(); + click(getOption('Alabama')!); + expect(inputElement.value).toBe('Alabama'); + expect(inputElement.getAttribute('aria-expanded')).toBe('false'); + }); + + it('should close on escape', () => { + focus(); + down(); + expect(inputElement.getAttribute('aria-expanded')).toBe('true'); + escape(); + expect(inputElement.getAttribute('aria-expanded')).toBe('false'); + }); }); // describe('with programmatic value changes', () => { @@ -483,7 +548,7 @@ describe('Combobox', () => { // focus(); // fixture.componentInstance.value.set(['Banana']); // fixture.detectChanges(); - // expect(fixture.componentInstance.value()).toEqual(['Banana']); + // expect(fixture.componentInstance.values()).toEqual(['Banana']); // const bananaOption = getOption('Banana')!; // expect(bananaOption.getAttribute('aria-selected')).toBe('true'); // }); @@ -518,7 +583,7 @@ describe('Combobox', () => { const click = (element: HTMLElement, eventInit?: PointerEventInit) => { focus(); - element.dispatchEvent(new PointerEvent('pointerup', {bubbles: true, ...eventInit})); + element.dispatchEvent(new PointerEvent('click', {bubbles: true, ...eventInit})); fixture.detectChanges(); }; @@ -539,14 +604,18 @@ describe('Combobox', () => { const enter = (modifierKeys?: {}) => keydown('Enter', modifierKeys); const escape = (modifierKeys?: {}) => keydown('Escape', modifierKeys); - function setupCombobox(opts: {filterMode?: 'manual' | 'auto-select' | 'highlight'} = {}) { - TestBed.configureTestingModule({}); + function setupCombobox( + opts: {readonly?: boolean; filterMode?: 'manual' | 'auto-select' | 'highlight'} = {}, + ) { fixture = TestBed.createComponent(ComboboxTreeExample); const testComponent = fixture.componentInstance; if (opts.filterMode) { testComponent.filterMode.set(opts.filterMode); } + if (opts.readonly) { + testComponent.readonly.set(true); + } fixture.detectChanges(); defineTestVariables(); @@ -715,7 +784,7 @@ describe('Combobox', () => { click(item); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['April']); + expect(fixture.componentInstance.values()).toEqual(['April']); expect(inputElement.value).toBe('April'); }); @@ -723,7 +792,7 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Winter']); + expect(fixture.componentInstance.values()).toEqual(['Winter']); expect(inputElement.value).toBe('Winter'); }); @@ -732,14 +801,14 @@ describe('Combobox', () => { input('November'); blur(); - expect(fixture.componentInstance.value()).toEqual(['November']); + expect(fixture.componentInstance.values()).toEqual(['November']); }); it('should not select on navigation', () => { down(); down(); - expect(fixture.componentInstance.value()).toEqual([]); + expect(fixture.componentInstance.values()).toEqual([]); }); it('should not select on focusout if the input text does not match an item', () => { @@ -747,7 +816,7 @@ describe('Combobox', () => { input('Appl'); blur(); - expect(fixture.componentInstance.value()).toEqual([]); + expect(fixture.componentInstance.values()).toEqual([]); expect(inputElement.value).toBe('Appl'); }); }); @@ -763,7 +832,7 @@ describe('Combobox', () => { click(item); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['February']); + expect(fixture.componentInstance.values()).toEqual(['February']); expect(inputElement.value).toBe('February'); }); @@ -772,22 +841,22 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Spring']); + expect(fixture.componentInstance.values()).toEqual(['Spring']); expect(inputElement.value).toBe('Spring'); }); it('should select on navigation', () => { down(); - expect(fixture.componentInstance.value()).toEqual(['Winter']); + expect(fixture.componentInstance.values()).toEqual(['Winter']); down(); - expect(fixture.componentInstance.value()).toEqual(['Spring']); + expect(fixture.componentInstance.values()).toEqual(['Spring']); }); it('should select the first option on input', () => { focus(); input('Dec'); - expect(fixture.componentInstance.value()).toEqual(['December']); + expect(fixture.componentInstance.values()).toEqual(['December']); }); it('should commit the selected option on focusout', () => { @@ -796,7 +865,7 @@ describe('Combobox', () => { blur(); expect(inputElement.value).toBe('June'); - expect(fixture.componentInstance.value()).toEqual(['June']); + expect(fixture.componentInstance.values()).toEqual(['June']); }); }); @@ -811,7 +880,7 @@ describe('Combobox', () => { click(item); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['February']); + expect(fixture.componentInstance.values()).toEqual(['February']); expect(inputElement.value).toBe('February'); }); @@ -820,16 +889,16 @@ describe('Combobox', () => { down(); enter(); - expect(fixture.componentInstance.value()).toEqual(['Spring']); + expect(fixture.componentInstance.values()).toEqual(['Spring']); expect(inputElement.value).toBe('Spring'); }); it('should select on navigation', () => { down(); - expect(fixture.componentInstance.value()).toEqual(['Winter']); + expect(fixture.componentInstance.values()).toEqual(['Winter']); down(); - expect(fixture.componentInstance.value()).toEqual(['Spring']); + expect(fixture.componentInstance.values()).toEqual(['Spring']); }); it('should update input value on navigation', () => { @@ -844,18 +913,17 @@ describe('Combobox', () => { focus(); input('Sept'); - expect(fixture.componentInstance.value()).toEqual(['September']); + expect(fixture.componentInstance.values()).toEqual(['September']); }); - it('should insert a highlighted completion string on input', fakeAsync(() => { + it('should insert a highlighted completion string on input', () => { focus(); input('Feb'); - tick(); expect(inputElement.value).toBe('February'); expect(inputElement.selectionStart).toBe(3); expect(inputElement.selectionEnd).toBe(8); - })); + }); it('should commit the selected option on focusout', () => { focus(); @@ -863,7 +931,7 @@ describe('Combobox', () => { blur(); expect(inputElement.value).toBe('January'); - expect(fixture.componentInstance.value()).toEqual(['January']); + expect(fixture.componentInstance.values()).toEqual(['January']); }); }); }); @@ -871,12 +939,6 @@ describe('Combobox', () => { describe('Expansion', () => { beforeEach(() => setupCombobox()); - it('should open on click', () => { - focus(); - click(inputElement); - expect(inputElement.getAttribute('aria-expanded')).toBe('true'); - }); - it('should open on ArrowDown', () => { focus(); keydown('ArrowDown'); @@ -907,17 +969,17 @@ describe('Combobox', () => { expect(inputElement.getAttribute('aria-expanded')).toBe('true'); }); - it('should clear the completion string and not close on escape when a completion is present', () => { + it('should close then clear the completion string', () => { fixture.componentInstance.filterMode.set('highlight'); focus(); input('Mar'); expect(inputElement.value).toBe('March'); expect(inputElement.getAttribute('aria-expanded')).toBe('true'); escape(); - expect(inputElement.value).toBe('Mar'); - expect(inputElement.getAttribute('aria-expanded')).toBe('true'); + expect(inputElement.value).toBe('March'); + expect(inputElement.getAttribute('aria-expanded')).toBe('false'); // close escape(); - expect(inputElement.value).toBe('Mar'); + expect(inputElement.value).toBe(''); // clear input expect(inputElement.getAttribute('aria-expanded')).toBe('false'); }); @@ -996,12 +1058,34 @@ describe('Combobox', () => { it('should update the selected item when the value is set programmatically', () => { setupCombobox(); focus(); - fixture.componentInstance.value.set(['August']); + fixture.componentInstance.values.set(['August']); fixture.detectChanges(); - expect(fixture.componentInstance.value()).toEqual(['August']); + expect(fixture.componentInstance.values()).toEqual(['August']); expect(getTreeItem('August')!.getAttribute('aria-selected')).toBe('true'); }); }); + + describe('Readonly', () => { + beforeEach(() => setupCombobox({readonly: true})); + + it('should close on selection', () => { + focus(); + down(); + right(); + right(); + enter(); + expect(inputElement.value).toBe('December'); + expect(inputElement.getAttribute('aria-expanded')).toBe('false'); + }); + + it('should close on escape', () => { + focus(); + down(); + expect(inputElement.getAttribute('aria-expanded')).toBe('true'); + escape(); + expect(inputElement.getAttribute('aria-expanded')).toBe('false'); + }); + }); }); }); @@ -1010,6 +1094,7 @@ describe('Combobox', () => {
{ /> -
+
@for (option of options(); track option) {
{ imports: [Combobox, ComboboxInput, ComboboxPopup, ComboboxPopupContainer, Listbox, Option], }) class ComboboxListboxExample { - value = signal([]); - - filterMode = signal<'manual' | 'auto-select' | 'highlight'>('manual'); - + readonly = signal(false); searchString = signal(''); + values = signal([]); + filterMode = signal<'manual' | 'auto-select' | 'highlight'>('manual'); options = computed(() => states.filter(state => state.toLowerCase().startsWith(this.searchString().toLowerCase())), @@ -1052,6 +1136,7 @@ class ComboboxListboxExample {
@@ -1062,7 +1147,7 @@ class ComboboxListboxExample { /> -
    +
      ([]); - - filterMode = signal<'manual' | 'auto-select' | 'highlight'>('manual'); - + readonly = signal(false); searchString = signal(''); - + values = signal([]); nodes = computed(() => this.filterTreeNodes(TREE_NODES)); + filterMode = signal<'manual' | 'auto-select' | 'highlight'>('manual'); firstMatch = computed(() => { const flatNodes = this.flattenTreeNodes(this.nodes()); @@ -1141,12 +1224,12 @@ class ComboboxTreeExample { } } -export interface TreeNode { +interface TreeNode { name: string; children?: TreeNode[]; } -export const TREE_NODES = [ +const TREE_NODES = [ { name: 'Winter', children: [{name: 'December'}, {name: 'January'}, {name: 'February'}], diff --git a/src/aria/combobox/combobox.ts b/src/aria/combobox/combobox.ts index 2c0af9581db7..e5aa15c5b54d 100644 --- a/src/aria/combobox/combobox.ts +++ b/src/aria/combobox/combobox.ts @@ -8,25 +8,55 @@ import { afterRenderEffect, + booleanAttribute, + computed, contentChild, Directive, ElementRef, inject, input, - model, signal, - untracked, - WritableSignal, } from '@angular/core'; -import {DeferredContent, DeferredContentAware} from '@angular/aria/deferred-content'; -import { - ComboboxPattern, - ComboboxListboxControls, - ComboboxTreeControls, -} from '@angular/aria/ui-patterns'; +import {DeferredContentAware, ComboboxPattern} from '../private'; import {Directionality} from '@angular/cdk/bidi'; -import {toSignal} from '@angular/core/rxjs-interop'; +import {COMBOBOX} from './combobox-tokens'; +import {ComboboxPopup} from './combobox-popup'; +/** + * The container element that wraps a combobox input and popup, and orchestrates its behavior. + * + * The `ngCombobox` directive is the main entry point for creating a combobox and customizing its + * behavior. It coordinates the interactions between the `ngComboboxInput` and the popup, which + * is defined by a `ng-template` with the `ngComboboxPopupContainer` directive. If using the + * `CdkOverlay`, the `cdkConnectedOverlay` directive takes the place of `ngComboboxPopupContainer`. + * + * ```html + *
      + * + * + * + *
      + * @for (option of filteredOptions(); track option) { + *
      + * {{option}} + *
      + * } + *
      + *
      + *
      + * ``` + * + * @developerPreview 21.0 + * + * @see [Combobox](guide/aria/combobox) + * @see [Select](guide/aria/select) + * @see [Multiselect](guide/aria/multiselect) + * @see [Autocomplete](guide/aria/autocomplete) + */ @Directive({ selector: '[ngCombobox]', exportAs: 'ngCombobox', @@ -37,52 +67,62 @@ import {toSignal} from '@angular/core/rxjs-interop'; }, ], host: { - '[attr.data-expanded]': 'pattern.expanded()', - '(input)': 'pattern.onInput($event)', - '(keydown)': 'pattern.onKeydown($event)', - '(pointerup)': 'pattern.onPointerup($event)', - '(focusin)': 'pattern.onFocusIn()', - '(focusout)': 'pattern.onFocusOut($event)', + '[attr.data-expanded]': 'expanded()', + '(input)': '_pattern.onInput($event)', + '(keydown)': '_pattern.onKeydown($event)', + '(click)': '_pattern.onClick($event)', + '(focusin)': '_pattern.onFocusIn()', + '(focusout)': '_pattern.onFocusOut($event)', }, + providers: [{provide: COMBOBOX, useExisting: Combobox}], }) export class Combobox { - /** The directionality (LTR / RTL) context for the application (or a subtree of it). */ - private readonly _directionality = inject(Directionality); - /** A signal wrapper for directionality. */ - protected textDirection = toSignal(this._directionality.change, { - initialValue: this._directionality.value, - }); + protected textDirection = inject(Directionality).valueSignal.asReadonly(); /** The element that the combobox is attached to. */ private readonly _elementRef = inject(ElementRef); + /** A reference to the combobox element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + /** The DeferredContentAware host directive. */ private readonly _deferredContentAware = inject(DeferredContentAware, {optional: true}); /** The combobox popup. */ readonly popup = contentChild>(ComboboxPopup); - /** The filter mode for the combobox. */ + /** + * The filter mode for the combobox. + * - `manual`: The consumer is responsible for filtering the options. + * - `auto-select`: The combobox automatically selects the first matching option. + * - `highlight`: The combobox highlights matching text in the options without changing selection. + */ filterMode = input<'manual' | 'auto-select' | 'highlight'>('manual'); - /** Whether the combobox is focused. */ - readonly isFocused = signal(false); - - /** Whether the listbox has received focus yet. */ - private _hasBeenFocused = signal(false); - /** Whether the combobox is disabled. */ - readonly disabled = input(false); + readonly disabled = input(false, {transform: booleanAttribute}); /** Whether the combobox is read-only. */ - readonly readonly = input(false); + readonly readonly = input(false, {transform: booleanAttribute}); /** The value of the first matching item in the popup. */ readonly firstMatch = input(undefined); + /** Whether the combobox is expanded. */ + readonly expanded = computed(() => this.alwaysExpanded() || this._pattern.expanded()); + + // TODO: Maybe make expanded a signal that can be passed in? + // Or an "always expanded" option? + + /** Whether the combobox popup should always be expanded, regardless of user interaction. */ + readonly alwaysExpanded = input(false, {transform: booleanAttribute}); + + /** Input element connected to the combobox, if any. */ + readonly inputElement = computed(() => this._pattern.inputs.inputEl()); + /** The combobox ui pattern. */ - readonly pattern = new ComboboxPattern({ + readonly _pattern = new ComboboxPattern({ ...this, textDirection: this.textDirection, disabled: this.disabled, @@ -90,78 +130,33 @@ export class Combobox { inputValue: signal(''), inputEl: signal(undefined), containerEl: () => this._elementRef.nativeElement, - popupControls: () => this.popup()?.controls(), + popupControls: () => this.popup()?._controls(), }); constructor() { afterRenderEffect(() => { - if (!this._deferredContentAware?.contentVisible() && this.pattern.isFocused()) { - this._deferredContentAware?.contentVisible.set(true); + if (this.alwaysExpanded()) { + this._pattern.expanded.set(true); } }); afterRenderEffect(() => { - if (!this._hasBeenFocused() && this.pattern.isFocused()) { - this._hasBeenFocused.set(true); + if ( + !this._deferredContentAware?.contentVisible() && + (this._pattern.isFocused() || this.alwaysExpanded()) + ) { + this._deferredContentAware?.contentVisible.set(true); } }); } -} -@Directive({ - selector: 'input[ngComboboxInput]', - exportAs: 'ngComboboxInput', - host: { - 'role': 'combobox', - '[value]': 'value()', - '[attr.aria-expanded]': 'combobox.pattern.expanded()', - '[attr.aria-activedescendant]': 'combobox.pattern.activedescendant()', - '[attr.aria-controls]': 'combobox.pattern.popupId()', - '[attr.aria-haspopup]': 'combobox.pattern.hasPopup()', - '[attr.aria-autocomplete]': 'combobox.pattern.autocomplete()', - }, -}) -export class ComboboxInput { - /** The element that the combobox is attached to. */ - private readonly _elementRef = inject>(ElementRef); - - /** The combobox that the input belongs to. */ - readonly combobox = inject(Combobox); - - /** The value of the input. */ - value = model(''); - - constructor() { - (this.combobox.pattern.inputs.inputEl as WritableSignal).set( - this._elementRef.nativeElement, - ); - this.combobox.pattern.inputs.inputValue = this.value; - - /** Focuses & selects the first item in the combobox if the user changes the input value. */ - afterRenderEffect(() => { - this.combobox.popup()?.controls()?.items(); - untracked(() => this.combobox.pattern.onFilter()); - }); + /** Opens the combobox to the selected item. */ + open() { + this._pattern.open({selected: true}); } -} -@Directive({ - selector: 'ng-template[ngComboboxPopupContainer]', - exportAs: 'ngComboboxPopupContainer', - hostDirectives: [DeferredContent], -}) -export class ComboboxPopupContainer {} - -@Directive({ - selector: '[ngComboboxPopup]', - exportAs: 'ngComboboxPopup', -}) -export class ComboboxPopup { - /** The combobox that the popup belongs to. */ - readonly combobox = inject>(Combobox, {optional: true}); - - /** The controls the popup exposes to the combobox. */ - readonly controls = signal< - ComboboxListboxControls | ComboboxTreeControls | undefined - >(undefined); + /** Closes the combobox. */ + close() { + this._pattern.close(); + } } diff --git a/src/aria/combobox/index.ts b/src/aria/combobox/index.ts index c859f6cc01de..52b3c7a5156f 100644 --- a/src/aria/combobox/index.ts +++ b/src/aria/combobox/index.ts @@ -6,4 +6,4 @@ * found in the LICENSE file at https://angular.dev/license */ -export {Combobox, ComboboxInput, ComboboxPopup, ComboboxPopupContainer} from './combobox'; +export * from './public-api'; diff --git a/src/aria/combobox/public-api.ts b/src/aria/combobox/public-api.ts new file mode 100644 index 000000000000..b8ea7ceefa50 --- /dev/null +++ b/src/aria/combobox/public-api.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +export {Combobox} from './combobox'; +export {ComboboxDialog} from './combobox-dialog'; +export {ComboboxInput} from './combobox-input'; +export {ComboboxPopup} from './combobox-popup'; +export {ComboboxPopupContainer} from './combobox-popup-container'; + +// This needs to be re-exported, because it's used by the combobox components. +// See: https://github.com/angular/components/issues/30663. +export { + DeferredContent as ɵɵDeferredContent, + DeferredContentAware as ɵɵDeferredContentAware, +} from '../private'; diff --git a/src/aria/config.bzl b/src/aria/config.bzl index 8c41015f75d4..291412b5a3fb 100644 --- a/src/aria/config.bzl +++ b/src/aria/config.bzl @@ -2,15 +2,13 @@ ARIA_ENTRYPOINTS = [ "accordion", "combobox", - "deferred-content", "grid", "listbox", "menu", - "radio-group", "tabs", "toolbar", "tree", - "ui-patterns", + "private", ] # List of all entry-point targets of the Angular Aria package. diff --git a/src/aria/grid/BUILD.bazel b/src/aria/grid/BUILD.bazel index 2d33b4879ba6..c03e388e1e9e 100644 --- a/src/aria/grid/BUILD.bazel +++ b/src/aria/grid/BUILD.bazel @@ -1,18 +1,37 @@ -load("//tools:defaults.bzl", "ng_project") +load("//tools:defaults.bzl", "extract_api_to_json", "ng_project") package(default_visibility = ["//visibility:public"]) ng_project( name = "grid", - srcs = [ - "grid.ts", - "index.ts", - ], + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), deps = [ "//:node_modules/@angular/core", - "//src/aria/deferred-content", - "//src/aria/ui-patterns", + "//src/aria/private", "//src/cdk/a11y", "//src/cdk/bidi", ], ) + +filegroup( + name = "source-files", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), +) + +extract_api_to_json( + name = "json_api", + srcs = [ + ":source-files", + ], + entry_point = ":index.ts", + module_name = "@angular/aria/grid", + output_name = "aria-grid.json", + private_modules = [""], + repo = "angular/components", +) diff --git a/src/aria/grid/grid-cell-widget.ts b/src/aria/grid/grid-cell-widget.ts new file mode 100644 index 000000000000..96d7a1957540 --- /dev/null +++ b/src/aria/grid/grid-cell-widget.ts @@ -0,0 +1,136 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {_IdGenerator} from '@angular/cdk/a11y'; +import { + afterRenderEffect, + booleanAttribute, + computed, + Directive, + ElementRef, + inject, + input, + output, + Signal, +} from '@angular/core'; +import {GridCellWidgetPattern} from '../private'; +import {GRID_CELL} from './grid-tokens'; + +/** + * Represents an interactive element inside a `GridCell`. It allows for pausing grid navigation to + * interact with the widget. + * + * When the user interacts with the widget (e.g., by typing in an input or opening a menu), grid + * navigation is temporarily suspended to allow the widget to handle keyboard + * events. + * + * ```html + * + * + * + * ``` + * + * @developerPreview 21.0 + * + * @see [Grid](guide/aria/grid) + */ +@Directive({ + selector: '[ngGridCellWidget]', + exportAs: 'ngGridCellWidget', + host: { + '[attr.data-active]': 'active()', + '[attr.data-active-control]': 'isActivated() ? "widget" : "cell"', + '[tabindex]': '_tabIndex()', + }, +}) +export class GridCellWidget { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** Whether the widget is currently active (focused). */ + readonly active = computed(() => this._pattern.active()); + + /** The parent cell. */ + private readonly _cell = inject(GRID_CELL); + + /** A unique identifier for the widget. */ + readonly id = input(inject(_IdGenerator).getId('ng-grid-cell-widget-', true)); + + /** The type of widget, which determines how it is activated. */ + readonly widgetType = input<'simple' | 'complex' | 'editable'>('simple'); + + /** Whether the widget is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** The target that will receive focus instead of the widget. */ + readonly focusTarget = input(); + + /** Emits when the widget is activated. */ + readonly onActivate = output(); + + /** Emits when the widget is deactivated. */ + readonly onDeactivate = output(); + + /** The tabindex override. */ + readonly tabindex = input(); + + /** + * The tabindex value set to the element. + * If a focus target exists then return -1. Unless an override. + */ + protected readonly _tabIndex: Signal = computed( + () => this.tabindex() ?? (this.focusTarget() ? -1 : this._pattern.tabIndex()), + ); + + /** The UI pattern for the grid cell widget. */ + readonly _pattern = new GridCellWidgetPattern({ + ...this, + element: () => this.element, + cell: () => this._cell._pattern, + focusTarget: computed(() => { + if (this.focusTarget() instanceof ElementRef) { + return (this.focusTarget() as ElementRef).nativeElement; + } + return this.focusTarget(); + }), + }); + + /** Whether the widget is activated. */ + get isActivated(): Signal { + return computed(() => this._pattern.isActivated()); + } + + constructor() { + afterRenderEffect(() => { + const activateEvent = this._pattern.lastActivateEvent(); + if (activateEvent) { + this.onActivate.emit(activateEvent); + } + }); + + afterRenderEffect(() => { + const deactivateEvent = this._pattern.lastDeactivateEvent(); + if (deactivateEvent) { + this.onDeactivate.emit(deactivateEvent); + } + }); + } + + /** Activates the widget. */ + activate(): void { + this._pattern.activate(); + } + + /** Deactivates the widget. */ + deactivate(): void { + this._pattern.deactivate(); + } +} diff --git a/src/aria/grid/grid-cell.ts b/src/aria/grid/grid-cell.ts new file mode 100644 index 000000000000..7235fd8b7495 --- /dev/null +++ b/src/aria/grid/grid-cell.ts @@ -0,0 +1,156 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {_IdGenerator} from '@angular/cdk/a11y'; +import { + booleanAttribute, + computed, + contentChildren, + Directive, + ElementRef, + inject, + input, + model, + Signal, +} from '@angular/core'; +import {Directionality} from '@angular/cdk/bidi'; +import {GridCellPattern} from '../private'; +import {GridCellWidget} from './grid-cell-widget'; +import {GRID_CELL, GRID_ROW} from './grid-tokens'; + +/** + * Represents a cell within a grid row. It is the primary focusable element + * within the grid. It can be disabled and can have its selection state managed + * through the `selected` input. + * + * ```html + * + * Cell Content + * + * ``` + * + * @developerPreview 21.0 + * + * @see [Grid](guide/aria/grid) + */ +@Directive({ + selector: '[ngGridCell]', + exportAs: 'ngGridCell', + host: { + '[attr.role]': 'role()', + '[attr.id]': '_pattern.id()', + '[attr.rowspan]': '_pattern.rowSpan()', + '[attr.colspan]': '_pattern.colSpan()', + '[attr.data-active]': 'active()', + '[attr.data-anchor]': '_pattern.anchor()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.aria-rowspan]': '_pattern.rowSpan()', + '[attr.aria-colspan]': '_pattern.colSpan()', + '[attr.aria-rowindex]': '_pattern.ariaRowIndex()', + '[attr.aria-colindex]': '_pattern.ariaColIndex()', + '[attr.aria-selected]': '_pattern.ariaSelected()', + '[tabindex]': '_tabIndex()', + }, + providers: [{provide: GRID_CELL, useExisting: GridCell}], +}) +export class GridCell { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** Whether the cell is currently active (focused). */ + readonly active = computed(() => this._pattern.active()); + + /** The widgets contained within this cell, if any. */ + private readonly _widgets = contentChildren(GridCellWidget, {descendants: true}); + + /** The UI pattern for the widget in this cell. */ + private readonly _widgetPatterns: Signal = computed(() => + this._widgets().map(w => w._pattern), + ); + + /** The parent row. */ + private readonly _row = inject(GRID_ROW); + + /** Text direction. */ + readonly textDirection = inject(Directionality).valueSignal; + + /** A unique identifier for the cell. */ + readonly id = input(inject(_IdGenerator).getId('ng-grid-cell-', true)); + + /** The ARIA role for the cell. */ + readonly role = input<'gridcell' | 'columnheader' | 'rowheader'>('gridcell'); + + /** The number of rows the cell should span. */ + readonly rowSpan = input(1); + + /** The number of columns the cell should span. */ + readonly colSpan = input(1); + + /** The index of this cell's row within the grid. */ + readonly rowIndex = input(); + + /** The index of this cell's column within the grid. */ + readonly colIndex = input(); + + /** Whether the cell is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** Whether the cell is selected. */ + readonly selected = model(false); + + /** Whether the cell is selectable. */ + readonly selectable = input(true); + + /** Orientation of the widgets in the cell. */ + readonly orientation = input<'vertical' | 'horizontal'>('horizontal'); + + /** Whether widgets navigation wraps. */ + readonly wrap = input(true, {transform: booleanAttribute}); + + /** The tabindex override. */ + readonly tabindex = input(); + + /** + * The tabindex value set to the element. + * If a focus target exists then return -1. Unless an override. + */ + protected readonly _tabIndex: Signal = computed( + () => this.tabindex() ?? this._pattern.tabIndex(), + ); + + /** The UI pattern for the grid cell. */ + readonly _pattern = new GridCellPattern({ + ...this, + grid: this._row._gridPattern, + row: () => this._row._pattern, + widgets: this._widgetPatterns, + getWidget: e => this._getWidget(e), + element: () => this.element, + }); + + constructor() {} + + /** Gets the cell widget pattern for a given element. */ + private _getWidget(element: Element | null | undefined): any | undefined { + let target = element; + + while (target) { + const pattern = this._widgetPatterns().find(w => w.element() === target); + if (pattern) { + return pattern; + } + + target = target.parentElement?.closest('[ngGridCellWidget]'); + } + + return undefined; + } +} diff --git a/src/aria/grid/grid-row.ts b/src/aria/grid/grid-row.ts new file mode 100644 index 000000000000..07c9753acd4a --- /dev/null +++ b/src/aria/grid/grid-row.ts @@ -0,0 +1,74 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + computed, + contentChildren, + Directive, + ElementRef, + inject, + input, + Signal, +} from '@angular/core'; +import {GridRowPattern} from '../private'; +import {Grid} from './grid'; +import {GRID_CELL, GRID_ROW} from './grid-tokens'; + +/** + * Represents a row within a grid. It is a container for `ngGridCell` directives. + * + * ```html + * + * + * + * ``` + * + * @developerPreview 21.0 + * + * @see [Grid](guide/aria/grid) + */ +@Directive({ + selector: '[ngGridRow]', + exportAs: 'ngGridRow', + host: { + 'role': 'row', + '[attr.aria-rowindex]': '_pattern.rowIndex()', + }, + providers: [{provide: GRID_ROW, useExisting: GridRow}], +}) +export class GridRow { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The cells that make up this row. */ + private readonly _cells = contentChildren(GRID_CELL, {descendants: true}); + + /** The UI patterns for the cells in this row. */ + private readonly _cellPatterns: Signal = computed(() => + this._cells().map(c => c._pattern), + ); + + /** The parent grid. */ + private readonly _grid = inject(Grid); + + /** The parent grid UI pattern. */ + readonly _gridPattern = computed(() => this._grid._pattern); + + /** The index of this row within the grid. */ + readonly rowIndex = input(); + + /** The UI pattern for the grid row. */ + readonly _pattern = new GridRowPattern({ + ...this, + cells: this._cellPatterns, + grid: this._gridPattern, + }); +} diff --git a/src/aria/grid/grid-tokens.ts b/src/aria/grid/grid-tokens.ts new file mode 100644 index 000000000000..3e70c18a6f79 --- /dev/null +++ b/src/aria/grid/grid-tokens.ts @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {InjectionToken} from '@angular/core'; +import type {GridCell} from './grid-cell'; +import type {GridRow} from './grid-row'; + +/** Token used to expose a `GridCell`. */ +export const GRID_CELL = new InjectionToken('GRID_CELL'); + +/** Token used to expose a `GridRow`. */ +export const GRID_ROW = new InjectionToken('GRID_ROW'); diff --git a/src/aria/grid/grid.ts b/src/aria/grid/grid.ts index 72adc8c974a4..f3e8633a48f8 100644 --- a/src/aria/grid/grid.ts +++ b/src/aria/grid/grid.ts @@ -6,54 +6,75 @@ * found in the LICENSE file at https://angular.dev/license */ -import {_IdGenerator} from '@angular/cdk/a11y'; import { afterRenderEffect, booleanAttribute, computed, - contentChild, contentChildren, Directive, ElementRef, inject, input, - model, Signal, } from '@angular/core'; -import {GridPattern, GridRowPattern, GridCellPattern, GridCellWidgetPattern} from '../ui-patterns'; +import {Directionality} from '@angular/cdk/bidi'; +import {GridPattern, GridCellPattern} from '../private'; +import {GRID_ROW} from './grid-tokens'; -/** A directive that provides grid-based navigation and selection behavior. */ +/** + * The container for a grid. It provides keyboard navigation and focus management for the grid's + * rows and cells. It manages the overall behavior of the grid, including focus + * wrapping, selection, and disabled states. + * + * ```html + * + * @for (row of gridData; track row) { + * + * @for (cell of row; track cell) { + * + * } + * + * } + *
      + * {{cell.value}} + *
      + * ``` + * + * @developerPreview 21.0 + * + * @see [Grid](guide/aria/grid) + */ @Directive({ selector: '[ngGrid]', exportAs: 'ngGrid', host: { - 'class': 'grid', 'role': 'grid', - '[tabindex]': 'pattern.tabIndex()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[attr.aria-activedescendant]': 'pattern.activeDescendant()', - '(keydown)': 'pattern.onKeydown($event)', - '(pointerdown)': 'pattern.onPointerdown($event)', - '(pointermove)': 'pattern.onPointermove($event)', - '(pointerup)': 'pattern.onPointerup($event)', - '(focusin)': 'pattern.onFocusIn($event)', - '(focusout)': 'pattern.onFocusOut($event)', + '[tabindex]': '_pattern.tabIndex()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.aria-activedescendant]': '_pattern.activeDescendant()', + '(keydown)': '_pattern.onKeydown($event)', + '(pointerdown)': '_pattern.onPointerdown($event)', + '(pointermove)': '_pattern.onPointermove($event)', + '(pointerup)': '_pattern.onPointerup($event)', + '(focusin)': '_pattern.onFocusIn($event)', + '(focusout)': '_pattern.onFocusOut($event)', }, }) export class Grid { /** A reference to the host element. */ private readonly _elementRef = inject(ElementRef); + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + /** The rows that make up the grid. */ - private readonly _rows = contentChildren(GridRow); + private readonly _rows = contentChildren(GRID_ROW, {descendants: true}); /** The UI patterns for the rows in the grid. */ - private readonly _rowPatterns: Signal = computed(() => - this._rows().map(r => r.pattern), - ); + private readonly _rowPatterns: Signal = computed(() => this._rows().map(r => r._pattern)); - /** The host native element. */ - readonly element = computed(() => this._elementRef.nativeElement); + /** Text direction. */ + readonly textDirection = inject(Directionality).valueSignal; /** Whether selection is enabled for the grid. */ readonly enableSelection = input(false, {transform: booleanAttribute}); @@ -61,199 +82,80 @@ export class Grid { /** Whether the grid is disabled. */ readonly disabled = input(false, {transform: booleanAttribute}); - /** Whether to skip disabled items during navigation. */ - readonly skipDisabled = input(true, {transform: booleanAttribute}); - - /** The focus strategy used by the grid. */ + /** + * Whether to allow disabled items to receive focus. When `true`, disabled items are + * focusable but not interactive. When `false`, disabled items are skipped during navigation. + */ + readonly softDisabled = input(true, {transform: booleanAttribute}); + + /** + * The focus strategy used by the grid. + * - `roving`: Focus is moved to the active cell using `tabindex`. + * - `activedescendant`: Focus remains on the grid container, and `aria-activedescendant` is used to indicate the active cell. + */ readonly focusMode = input<'roving' | 'activedescendant'>('roving'); - /** The wrapping behavior for keyboard navigation along the row axis. */ + /** + * The wrapping behavior for keyboard navigation along the row axis. + * - `continuous`: Navigation wraps from the last row to the first, and vice-versa. + * - `loop`: Navigation wraps within the current row. + * - `nowrap`: Navigation stops at the first/last item in the row. + */ readonly rowWrap = input<'continuous' | 'loop' | 'nowrap'>('loop'); - /** The wrapping behavior for keyboard navigation along the column axis. */ + /** + * The wrapping behavior for keyboard navigation along the column axis. + * - `continuous`: Navigation wraps from the last column to the first, and vice-versa. + * - `loop`: Navigation wraps within the current column. + * - `nowrap`: Navigation stops at the first/last item in the column. + */ readonly colWrap = input<'continuous' | 'loop' | 'nowrap'>('loop'); + /** Whether multiple cells in the grid can be selected. */ + readonly multi = input(false, {transform: booleanAttribute}); + + /** + * The selection strategy used by the grid. + * - `follow`: The focused cell is automatically selected. + * - `explicit`: Cells are selected explicitly by the user (e.g., via click or spacebar). + */ + readonly selectionMode = input<'follow' | 'explicit'>('follow'); + + /** Whether enable range selections (with modifier keys or dragging). */ + readonly enableRangeSelection = input(false, {transform: booleanAttribute}); + /** The UI pattern for the grid. */ - readonly pattern = new GridPattern({ + readonly _pattern = new GridPattern({ ...this, rows: this._rowPatterns, getCell: e => this._getCell(e), + element: () => this.element, }); constructor() { - afterRenderEffect(() => this.pattern.resetStateEffect()); - afterRenderEffect(() => this.pattern.focusEffect()); + afterRenderEffect(() => this._pattern.setDefaultStateEffect()); + afterRenderEffect(() => this._pattern.resetStateEffect()); + afterRenderEffect(() => this._pattern.resetFocusEffect()); + afterRenderEffect(() => this._pattern.restoreFocusEffect()); + afterRenderEffect(() => this._pattern.focusEffect()); } /** Gets the cell pattern for a given element. */ - private _getCell(element: Element): GridCellPattern | undefined { - const cellElement = element.closest('[ngGridCell]'); - if (cellElement === undefined) return; - - const widgetElement = element.closest('[ngGridCellWidget]'); - for (const row of this._rowPatterns()) { - for (const cell of row.inputs.cells()) { - if ( - cell.element() === cellElement || - (widgetElement !== undefined && cell.element() === widgetElement) - ) { - return cell; + private _getCell(element: Element | null | undefined): GridCellPattern | undefined { + let target = element; + + while (target) { + for (const row of this._rowPatterns()) { + for (const cell of row.inputs.cells()) { + if (cell.element() === target) { + return cell; + } } } - } - return; - } -} - -/** A directive that represents a row in a grid. */ -@Directive({ - selector: '[ngGridRow]', - exportAs: 'ngGridRow', - host: { - 'class': 'grid-row', - '[attr.role]': 'role()', - }, -}) -export class GridRow { - /** A reference to the host element. */ - private readonly _elementRef = inject(ElementRef); - - /** The cells that make up this row. */ - private readonly _cells = contentChildren(GridCell); - - /** The UI patterns for the cells in this row. */ - private readonly _cellPatterns: Signal = computed(() => - this._cells().map(c => c.pattern), - ); - - /** The parent grid. */ - private readonly _grid = inject(Grid); - - /** The parent grid UI pattern. */ - readonly grid = computed(() => this._grid.pattern); - - /** The host native element. */ - readonly element = computed(() => this._elementRef.nativeElement); - /** The ARIA role for the row. */ - readonly role = input<'row' | 'rowheader'>('row'); - - /** The index of this row within the grid. */ - readonly rowIndex = input(); - - /** The UI pattern for the grid row. */ - readonly pattern = new GridRowPattern({ - ...this, - cells: this._cellPatterns, - }); -} - -/** A directive that represents a cell in a grid. */ -@Directive({ - selector: '[ngGridCell]', - exportAs: 'ngGridCell', - host: { - 'class': 'grid-cell', - '[attr.role]': 'role()', - '[attr.id]': 'pattern.id()', - '[attr.rowspan]': 'pattern.rowSpan()', - '[attr.colspan]': 'pattern.colSpan()', - '[attr.data-active]': 'pattern.active()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[attr.aria-rowspan]': 'pattern.rowSpan()', - '[attr.aria-colspan]': 'pattern.colSpan()', - '[attr.aria-rowindex]': 'pattern.ariaRowIndex()', - '[attr.aria-colindex]': 'pattern.ariaColIndex()', - '[attr.aria-selected]': 'pattern.ariaSelected()', - '[tabindex]': 'pattern.tabIndex()', - }, -}) -export class GridCell { - /** A reference to the host element. */ - private readonly _elementRef = inject(ElementRef); - - /** The widget contained within this cell, if any. */ - private readonly _widgets = contentChild(GridCellWidget); - - /** The UI pattern for the widget in this cell. */ - private readonly _widgetPattern: Signal = computed( - () => this._widgets()?.pattern, - ); - - /** The parent row. */ - private readonly _row = inject(GridRow); - - /** A unique identifier for the cell. */ - private readonly _id = inject(_IdGenerator).getId('ng-grid-cell-'); - - /** The host native element. */ - readonly element = computed(() => this._elementRef.nativeElement); - - /** The ARIA role for the cell. */ - readonly role = input<'gridcell' | 'columnheader'>('gridcell'); - - /** The number of rows the cell should span. */ - readonly rowSpan = input(1); - - /** The number of columns the cell should span. */ - readonly colSpan = input(1); - - /** The index of this cell's row within the grid. */ - readonly rowIndex = input(); - - /** The index of this cell's column within the grid. */ - readonly colIndex = input(); - - /** Whether the cell is disabled. */ - readonly disabled = input(false, {transform: booleanAttribute}); - - /** Whether the cell is selected. */ - readonly selected = model(false); - - /** Whether the cell is selectable. */ - readonly selectable = input(true); - - /** The UI pattern for the grid cell. */ - readonly pattern = new GridCellPattern({ - ...this, - id: () => this._id, - grid: this._row.grid, - row: () => this._row.pattern, - widget: this._widgetPattern, - }); -} - -/** A directive that represents a widget inside a grid cell. */ -@Directive({ - selector: '[ngGridCellWidget]', - exportAs: 'ngGridCellWidget', - host: { - 'class': 'grid-cell-widget', - '[attr.data-active]': 'pattern.active()', - '[tabindex]': 'pattern.tabIndex()', - }, -}) -export class GridCellWidget { - /** A reference to the host element. */ - private readonly _elementRef = inject(ElementRef); - - /** The parent cell. */ - private readonly _cell = inject(GridCell); - - /** The host native element. */ - readonly element = computed(() => this._elementRef.nativeElement); - - /** Whether the widget is activated and the grid navigation should be paused. */ - readonly activate = model(false); - - /** The UI pattern for the grid cell widget. */ - readonly pattern = new GridCellWidgetPattern({ - ...this, - cell: () => this._cell.pattern, - }); + target = target.parentElement?.closest('[ngGridCell]'); + } - /** Focuses the widget. */ - focus(): void { - this.element().focus(); + return undefined; } } diff --git a/src/aria/grid/index.ts b/src/aria/grid/index.ts index 94bcd871b881..05e171a92d47 100644 --- a/src/aria/grid/index.ts +++ b/src/aria/grid/index.ts @@ -6,4 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -export * from './grid'; +export {Grid} from './grid'; +export {GridCell} from './grid-cell'; +export {GridRow} from './grid-row'; +export {GridCellWidget} from './grid-cell-widget'; diff --git a/docs/src/app/pages/system-variables/index.ts b/src/aria/grid/public-api.ts similarity index 56% rename from docs/src/app/pages/system-variables/index.ts rename to src/aria/grid/public-api.ts index cd7ebb8992f0..05e171a92d47 100644 --- a/docs/src/app/pages/system-variables/index.ts +++ b/src/aria/grid/public-api.ts @@ -6,4 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -export * from './system-variables'; +export {Grid} from './grid'; +export {GridCell} from './grid-cell'; +export {GridRow} from './grid-row'; +export {GridCellWidget} from './grid-cell-widget'; diff --git a/src/aria/listbox/BUILD.bazel b/src/aria/listbox/BUILD.bazel index 62c65c2faac8..4ba1e872d6eb 100644 --- a/src/aria/listbox/BUILD.bazel +++ b/src/aria/listbox/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite") +load("//tools:defaults.bzl", "extract_api_to_json", "ng_project", "ng_web_test_suite") package(default_visibility = ["//visibility:public"]) @@ -11,7 +11,7 @@ ng_project( deps = [ "//:node_modules/@angular/core", "//src/aria/combobox", - "//src/aria/ui-patterns", + "//src/aria/private", "//src/cdk/a11y", "//src/cdk/bidi", ], @@ -37,3 +37,23 @@ ng_web_test_suite( name = "unit_tests", deps = [":unit_test_sources"], ) + +filegroup( + name = "source-files", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), +) + +extract_api_to_json( + name = "json_api", + srcs = [ + ":source-files", + ], + entry_point = ":index.ts", + module_name = "@angular/aria/listbox", + output_name = "aria-listbox.json", + private_modules = [""], + repo = "angular/components", +) diff --git a/src/aria/listbox/index.ts b/src/aria/listbox/index.ts index a21d11c2d475..52b3c7a5156f 100644 --- a/src/aria/listbox/index.ts +++ b/src/aria/listbox/index.ts @@ -6,4 +6,4 @@ * found in the LICENSE file at https://angular.dev/license */ -export {Listbox, Option} from './listbox'; +export * from './public-api'; diff --git a/src/aria/listbox/listbox.spec.ts b/src/aria/listbox/listbox.spec.ts index 6241478357f3..caa6e3f24e7a 100644 --- a/src/aria/listbox/listbox.spec.ts +++ b/src/aria/listbox/listbox.spec.ts @@ -1,6 +1,7 @@ import {Component, DebugElement, signal} from '@angular/core'; -import {Listbox, Option} from './listbox'; -import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {Listbox} from './listbox'; +import {Option} from './option'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Direction} from '@angular/cdk/bidi'; import {provideFakeDirectionality, runAccessibilityChecks} from '@angular/cdk/testing/private'; @@ -52,8 +53,8 @@ describe('Listbox', () => { orientation?: 'horizontal' | 'vertical'; disabled?: boolean; readonly?: boolean; - value?: number[]; - skipDisabled?: boolean; + values?: number[]; + softDisabled?: boolean; focusMode?: 'roving' | 'activedescendant'; multi?: boolean; wrap?: boolean; @@ -73,8 +74,8 @@ describe('Listbox', () => { if (opts?.orientation !== undefined) testComponent.orientation = opts.orientation; if (opts?.disabled !== undefined) testComponent.disabled = opts.disabled; if (opts?.readonly !== undefined) testComponent.readonly = opts.readonly; - if (opts?.value !== undefined) testComponent.value = opts.value; - if (opts?.skipDisabled !== undefined) testComponent.skipDisabled = opts.skipDisabled; + if (opts?.values !== undefined) testComponent.values = opts.values; + if (opts?.softDisabled !== undefined) testComponent.softDisabled = opts.softDisabled; if (opts?.focusMode !== undefined) testComponent.focusMode = opts.focusMode; if (opts?.multi !== undefined) testComponent.multi = opts.multi; if (opts?.wrap !== undefined) testComponent.wrap = opts.wrap; @@ -173,7 +174,7 @@ describe('Listbox', () => { }); it('should set aria-selected to "true" for selected options', () => { - setupListbox({multi: true, value: [1, 3]}); + setupListbox({multi: true, values: [1, 3]}); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); expect(optionElements[2].getAttribute('aria-selected')).toBe('false'); @@ -200,7 +201,7 @@ describe('Listbox', () => { expect(listboxElement.getAttribute('tabindex')).toBe('0'); }); - it('should set initial focus (tabindex="0") on the first non-disabled option if no value is set', () => { + it('should set initial focus (tabindex="0") on the first non-disabled option if no values are set', () => { setupListbox({focusMode: 'roving'}); expect(optionElements[0].getAttribute('tabindex')).toBe('0'); expect(optionElements[1].getAttribute('tabindex')).toBe('-1'); @@ -210,7 +211,7 @@ describe('Listbox', () => { }); it('should set initial focus (tabindex="0") on the first selected option', () => { - setupListbox({focusMode: 'roving', value: [2]}); + setupListbox({focusMode: 'roving', values: [2]}); expect(optionElements[0].getAttribute('tabindex')).toBe('-1'); expect(optionElements[1].getAttribute('tabindex')).toBe('-1'); expect(optionElements[2].getAttribute('tabindex')).toBe('0'); @@ -218,8 +219,23 @@ describe('Listbox', () => { expect(optionElements[4].getAttribute('tabindex')).toBe('-1'); }); - it('should set initial focus (tabindex="0") on the first non-disabled option if selected option is disabled', () => { - setupListbox({focusMode: 'roving', value: [1], disabledOptions: [1]}); + it('should set initial focus (tabindex="0") on the first non-disabled option if selected option is disabled when softDisabled is false', () => { + setupListbox({ + focusMode: 'roving', + values: [1], + disabledOptions: [0], + softDisabled: false, + }); + expect(optionElements[0].getAttribute('tabindex')).toBe('-1'); + expect(optionElements[1].getAttribute('tabindex')).toBe('0'); + }); + + it('should set initial focus (tabindex="0") on the first option if selected option is disabled', () => { + setupListbox({ + focusMode: 'roving', + values: [0], + disabledOptions: [0], + }); expect(optionElements[0].getAttribute('tabindex')).toBe('0'); expect(optionElements[1].getAttribute('tabindex')).toBe('-1'); }); @@ -242,15 +258,25 @@ describe('Listbox', () => { }); it('should set aria-activedescendant to the ID of the first selected option', () => { - setupListbox({focusMode: 'activedescendant', value: [2]}); + setupListbox({focusMode: 'activedescendant', values: [2]}); expect(listboxElement.getAttribute('aria-activedescendant')).toBe(optionElements[2].id); }); it('should set aria-activedescendant to the ID of the first non-disabled option if selected option is disabled', () => { - setupListbox({focusMode: 'activedescendant', value: [1], disabledOptions: [1]}); + setupListbox({focusMode: 'activedescendant', values: [0], disabledOptions: [0]}); expect(listboxElement.getAttribute('aria-activedescendant')).toBe(optionElements[0].id); }); + it('should set aria-activedescendant to the ID of the first non-disabled option if selected option is disabled when softDisabled is false', () => { + setupListbox({ + focusMode: 'activedescendant', + values: [1], + disabledOptions: [0], + softDisabled: false, + }); + expect(listboxElement.getAttribute('aria-activedescendant')).toBe(optionElements[1].id); + }); + it('should set tabindex="-1" for all options', () => { setupListbox({focusMode: 'activedescendant'}); expect(optionElements[0].getAttribute('tabindex')).toBe('-1'); @@ -264,28 +290,28 @@ describe('Listbox', () => { describe('value and selection', () => { it('should select the options corresponding to the value input', () => { - setupListbox({multi: true, value: [1, 3]}); + setupListbox({multi: true, values: [1, 3]}); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); expect(optionElements[3].getAttribute('aria-selected')).toBe('true'); - expect(listboxInstance.value()).toEqual([1, 3]); + expect(listboxInstance.values()).toEqual([1, 3]); }); it('should update the value model when an option is selected via UI (single select)', () => { setupListbox({multi: false}); click(1); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); click(2); - expect(listboxInstance.value()).toEqual([2]); + expect(listboxInstance.values()).toEqual([2]); }); it('should update the value model when options are selected via UI (multi select)', () => { setupListbox({multi: true}); click(1); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); click(3); - expect(listboxInstance.value()).toEqual([1, 3]); + expect(listboxInstance.values()).toEqual([1, 3]); click(1); - expect(listboxInstance.value()).toEqual([3]); + expect(listboxInstance.values()).toEqual([3]); }); describe('pointer interactions', () => { @@ -293,14 +319,14 @@ describe('Listbox', () => { it('should select an option on click', () => { setupListbox({multi: false}); click(1); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); it('should select a new option and deselect the old one on click', () => { - setupListbox({multi: false, value: [0]}); + setupListbox({multi: false, values: [0]}); click(1); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); @@ -309,30 +335,30 @@ describe('Listbox', () => { describe('multi select', () => { describe('selection follows focus', () => { it('should select only the clicked option with a simple click', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); click(1); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); it('should toggle the selected state of an option with ctrl + click', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); click(1, {ctrlKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1]); + expect(listboxInstance.values().sort()).toEqual([0, 1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('true'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); click(0, {ctrlKey: true}); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); it('should select a range starting from the first option on shift + click', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); click(2, {shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2]); expect(optionElements[0].getAttribute('aria-selected')).toBe('true'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); expect(optionElements[2].getAttribute('aria-selected')).toBe('true'); @@ -342,46 +368,46 @@ describe('Listbox', () => { setupListbox({multi: true, selectionMode: 'follow'}); click(1); click(3, {shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([1, 2, 3]); + expect(listboxInstance.values().sort()).toEqual([1, 2, 3]); }); it('should not select disabled options on shift + click', () => { setupListbox({multi: true, selectionMode: 'follow', disabledOptions: [1]}); click(2, {shiftKey: true}); - expect(listboxInstance.value()).toEqual([0, 2]); + expect(listboxInstance.values()).toEqual([0, 2]); }); }); describe('explicit selection', () => { it('should toggle selection of the clicked option with a simple click', () => { - setupListbox({multi: true, selectionMode: 'explicit', value: [0]}); + setupListbox({multi: true, selectionMode: 'explicit', values: [0]}); click(1); - expect(listboxInstance.value().sort()).toEqual([0, 1]); + expect(listboxInstance.values().sort()).toEqual([0, 1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('true'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); click(0); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); }); it('should select a range starting from the first option on shift + click', () => { - setupListbox({multi: true, selectionMode: 'explicit', value: [0]}); + setupListbox({multi: true, selectionMode: 'explicit', values: [0]}); click(2, {shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2]); }); it('should select a range starting from the current active option on shift + click', () => { setupListbox({multi: true, selectionMode: 'explicit'}); click(1); click(3, {shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([1, 2, 3]); + expect(listboxInstance.values().sort()).toEqual([1, 2, 3]); }); it('should not select disabled options on shift + click', () => { setupListbox({multi: true, selectionMode: 'follow', disabledOptions: [1]}); click(2, {shiftKey: true}); - expect(listboxInstance.value()).toEqual([0, 2]); + expect(listboxInstance.values()).toEqual([0, 2]); }); }); }); @@ -393,30 +419,30 @@ describe('Listbox', () => { it('should select the next option on ArrowDown', () => { setupListbox({multi: false, selectionMode: 'follow'}); down(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); down(); - expect(listboxInstance.value()).toEqual([2]); + expect(listboxInstance.values()).toEqual([2]); expect(optionElements[2].getAttribute('aria-selected')).toBe('true'); }); it('should select the previous option on ArrowUp', () => { - setupListbox({multi: false, selectionMode: 'follow', value: [2]}); + setupListbox({multi: false, selectionMode: 'follow', values: [2]}); up(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); it('should select the first option on Home', () => { - setupListbox({multi: false, selectionMode: 'follow', value: [2]}); + setupListbox({multi: false, selectionMode: 'follow', values: [2]}); home(); - expect(listboxInstance.value()).toEqual([0]); + expect(listboxInstance.values()).toEqual([0]); }); it('should select the last option on End', () => { - setupListbox({multi: false, selectionMode: 'follow', value: [2]}); + setupListbox({multi: false, selectionMode: 'follow', values: [2]}); end(); - expect(listboxInstance.value()).toEqual([4]); + expect(listboxInstance.values()).toEqual([4]); }); }); @@ -427,7 +453,7 @@ describe('Listbox', () => { up(); home(); end(); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); expect(optionElements[1].getAttribute('aria-selected')).toBe('false'); }); @@ -435,12 +461,12 @@ describe('Listbox', () => { setupListbox({multi: false, selectionMode: 'explicit'}); down(); space(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); down(); down(); space(); - expect(listboxInstance.value()).toEqual([3]); + expect(listboxInstance.values()).toEqual([3]); expect(optionElements[1].getAttribute('aria-selected')).toBe('false'); expect(optionElements[3].getAttribute('aria-selected')).toBe('true'); }); @@ -449,7 +475,7 @@ describe('Listbox', () => { setupListbox({multi: false, selectionMode: 'explicit'}); down(); enter(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); }); @@ -458,46 +484,46 @@ describe('Listbox', () => { describe('multi select', () => { describe('selection follows focus', () => { it('should select only the focused option on ArrowDown (no modifier)', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); down(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); expect(optionElements[0].getAttribute('aria-selected')).toBe('false'); expect(optionElements[1].getAttribute('aria-selected')).toBe('true'); }); it('should move focus but not change selection on ctrl + ArrowDown, then toggle with ctrl + Space', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); down({ctrlKey: true}); - expect(listboxInstance.value()).toEqual([0]); + expect(listboxInstance.values()).toEqual([0]); space({ctrlKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1]); + expect(listboxInstance.values().sort()).toEqual([0, 1]); }); it('should toggle selection of the focused item on ctrl + Space', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); space({ctrlKey: true}); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); down(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); space({ctrlKey: true}); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); }); it('should extend selection on shift + ArrowDown', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); down({shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1]); + expect(listboxInstance.values().sort()).toEqual([0, 1]); down({shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2]); }); it('should select all on Ctrl+A, then select active on second Ctrl+A', () => { - setupListbox({multi: true, selectionMode: 'follow', value: [0]}); + setupListbox({multi: true, selectionMode: 'follow', values: [0]}); keydown('A', {ctrlKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2, 3, 4]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2, 3, 4]); keydown('A', {ctrlKey: true}); - expect(listboxInstance.value()).toEqual([0]); + expect(listboxInstance.values()).toEqual([0]); }); }); @@ -505,43 +531,43 @@ describe('Listbox', () => { it('should move focus but not select on ArrowDown', () => { setupListbox({multi: true, selectionMode: 'explicit'}); down(); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); }); it('should toggle selection of the focused item on Space', () => { setupListbox({multi: true, selectionMode: 'explicit'}); down(); space(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); down(); space(); - expect(listboxInstance.value().sort()).toEqual([1, 2]); + expect(listboxInstance.values().sort()).toEqual([1, 2]); space(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); }); it('should toggle selection of the focused item on Enter', () => { setupListbox({multi: true, selectionMode: 'explicit'}); down(); enter(); - expect(listboxInstance.value()).toEqual([1]); + expect(listboxInstance.values()).toEqual([1]); }); it('should extend selection on Shift+ArrowDown', () => { setupListbox({multi: true, selectionMode: 'explicit'}); down({shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1]); + expect(listboxInstance.values().sort()).toEqual([0, 1]); down({shiftKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2]); }); it('should toggle selection of all options on Ctrl+A', () => { - setupListbox({multi: true, selectionMode: 'explicit', value: [0]}); + setupListbox({multi: true, selectionMode: 'explicit', values: [0]}); keydown('A', {ctrlKey: true}); - expect(listboxInstance.value().sort()).toEqual([0, 1, 2, 3, 4]); + expect(listboxInstance.values().sort()).toEqual([0, 1, 2, 3, 4]); keydown('A', {ctrlKey: true}); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); }); }); }); @@ -553,17 +579,17 @@ describe('Listbox', () => { isFocused: (index: number) => boolean, ) { describe(`keyboard navigation (focusMode="${focusMode}")`, () => { - it('should move focus to the last enabled option on End', () => { + it('should move focus to the last focusable option on End', () => { setupListbox({focusMode, disabledOptions: [4]}); end(); - expect(isFocused(3)).toBe(true); + expect(isFocused(4)).toBe(true); }); - it('should move focus to the first enabled option on Home', () => { + it('should move focus to the first focusable option on Home', () => { setupListbox({focusMode, disabledOptions: [0]}); end(); home(); - expect(isFocused(1)).toBe(true); + expect(isFocused(0)).toBe(true); }); it('should allow keyboard navigation if the group is readonly', () => { @@ -593,27 +619,39 @@ describe('Listbox', () => { expect(isFocused(1)).toBe(true); }); - it('should skip disabled options with ArrowDown (skipDisabled="true")', () => { + it('should skip disabled options with ArrowDown (softDisabled="false")', () => { setupListbox({ focusMode, orientation: 'vertical', - skipDisabled: true, + softDisabled: false, disabledOptions: [1, 2], }); down(); expect(isFocused(3)).toBe(true); }); - it('should not skip disabled options with ArrowDown (skipDisabled="false")', () => { + it('should not skip disabled options with ArrowDown (softDisabled="true")', () => { setupListbox({ focusMode, orientation: 'vertical', - skipDisabled: false, + softDisabled: true, disabledOptions: [1, 2], }); down(); expect(isFocused(1)).toBe(true); }); + + it('should not be focusable ArrowDown when completely disabled', () => { + setupListbox({ + focusMode, + orientation: 'vertical', + softDisabled: true, + disabled: true, + }); + + down(); + expect(isFocused(0)).toBe(false); + }); }); describe('horizontal orientation', () => { @@ -641,7 +679,7 @@ describe('Listbox', () => { }); it('should move focus to the clicked disabled option', () => { - setupListbox({focusMode, disabledOptions: [2], skipDisabled: false}); + setupListbox({focusMode, disabledOptions: [2], softDisabled: true}); click(2); expect(isFocused(2)).toBe(true); }); @@ -674,7 +712,7 @@ describe('Listbox', () => { setupListbox({options: getOptions(), focusMode, selectionMode: 'follow'}); type('O'); expect(isFocused(4)).toBe(true); - expect(listboxInstance.value()).toEqual([4]); + expect(listboxInstance.values()).toEqual([4]); expect(optionElements[4].getAttribute('aria-selected')).toBe('true'); }); @@ -682,28 +720,29 @@ describe('Listbox', () => { setupListbox({options: getOptions(), focusMode, selectionMode: 'explicit'}); type('O'); expect(isFocused(4)).toBe(true); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); expect(optionElements[4].getAttribute('aria-selected')).toBe('false'); }); - it('should reset search term after typeaheadDelay', fakeAsync(() => { - setupListbox({options: getOptions(), focusMode, typeaheadDelay: 0.1}); + it('should reset search term after typeaheadDelay', async () => { + setupListbox({options: getOptions(), focusMode, typeaheadDelay: 100}); type('A'); expect(isFocused(1)).toBe(true); - tick(100); + await new Promise(resolve => setTimeout(resolve, 100)); + type('A'); expect(isFocused(0)).toBe(true); - })); + }); - it('should skip disabled options with typeahead (skipDisabled=true)', () => { - setupListbox({options: getOptions(), focusMode, disabledOptions: [2], skipDisabled: true}); + it('should skip disabled options with typeahead (softDisabled=false)', () => { + setupListbox({options: getOptions(), focusMode, disabledOptions: [2], softDisabled: false}); type('B'); expect(isFocused(3)).toBe(true); }); - it('should focus disabled options with typeahead if skipDisabled=false', () => { - setupListbox({options: getOptions(), focusMode, disabledOptions: [2], skipDisabled: false}); + it('should focus disabled options with typeahead if softDisabled=true', () => { + setupListbox({options: getOptions(), focusMode, disabledOptions: [2], softDisabled: true}); type('B'); expect(isFocused(2)).toBe(true); }); @@ -728,7 +767,7 @@ describe('Listbox', () => { expect(optionElements.length).toBe(0); expect(() => down()).not.toThrow(); expect(() => space()).not.toThrow(); - expect(listboxInstance.value()).toEqual([]); + expect(listboxInstance.values()).toEqual([]); }); }); }); @@ -744,12 +783,12 @@ interface TestOption {
        - *
      • Item 1
      • - *
      • Item 2
      • - *
      • Item 3
      • + *
          + * @for (item of items; track item.id) { + *
        • + * {{item.name}} + *
        • + * } *
        * ``` + * + * @developerPreview 21.0 + * + * @see [Listbox](guide/aria/listbox) + * @see [Autocomplete](guide/aria/autocomplete) + * @see [Select](guide/aria/select) + * @see [Multiselect](guide/aria/multiselect) */ @Directive({ selector: '[ngListbox]', exportAs: 'ngListbox', host: { 'role': 'listbox', - 'class': 'ng-listbox', '[attr.id]': 'id()', - '[attr.tabindex]': 'pattern.tabindex()', - '[attr.aria-readonly]': 'pattern.readonly()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[attr.aria-orientation]': 'pattern.orientation()', - '[attr.aria-multiselectable]': 'pattern.multi()', - '[attr.aria-activedescendant]': 'pattern.activedescendant()', - '(keydown)': 'pattern.onKeydown($event)', - '(pointerdown)': 'pattern.onPointerdown($event)', - '(focusin)': 'onFocus()', + '[attr.tabindex]': '_pattern.tabIndex()', + '[attr.aria-readonly]': '_pattern.readonly()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.aria-orientation]': '_pattern.orientation()', + '[attr.aria-multiselectable]': '_pattern.multi()', + '[attr.aria-activedescendant]': '_pattern.activeDescendant()', + '(keydown)': '_pattern.onKeydown($event)', + '(pointerdown)': '_pattern.onPointerdown($event)', + '(focusin)': '_onFocus()', }, - hostDirectives: [{directive: ComboboxPopup}], + hostDirectives: [ComboboxPopup], + providers: [{provide: LISTBOX, useExisting: Listbox}], }) export class Listbox { /** A unique identifier for the listbox. */ - private readonly _generatedId = inject(_IdGenerator).getId('ng-listbox-'); - - // TODO(wagnermaciel): https://github.com/angular/components/pull/30495#discussion_r1972601144. - /** A unique identifier for the listbox. */ - protected id = computed(() => this._generatedId); + readonly id = input(inject(_IdGenerator).getId('ng-listbox-', true)); /** A reference to the parent combobox popup, if one exists. */ private readonly _popup = inject>(ComboboxPopup, { optional: true, }); - /** A reference to the listbox element. */ + /** A reference to the host element. */ private readonly _elementRef = inject(ElementRef); - /** The directionality (LTR / RTL) context for the application (or a subtree of it). */ - private readonly _directionality = inject(Directionality); + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; /** The Options nested inside of the Listbox. */ private readonly _options = contentChildren(Option, {descendants: true}); /** A signal wrapper for directionality. */ - protected textDirection = toSignal(this._directionality.change, { - initialValue: this._directionality.value, - }); + protected textDirection = inject(Directionality).valueSignal.asReadonly(); /** The Option UIPatterns of the child Options. */ - protected items = computed(() => this._options().map(option => option.pattern)); + protected items = computed(() => this._options().map(option => option._pattern)); /** Whether the list is vertically or horizontally oriented. */ orientation = input<'vertical' | 'horizontal'>('vertical'); @@ -97,17 +102,28 @@ export class Listbox { /** Whether focus should wrap when navigating. */ wrap = input(true, {transform: booleanAttribute}); - /** Whether disabled items in the list should be skipped when navigating. */ - skipDisabled = input(true, {transform: booleanAttribute}); - - /** The focus strategy used by the list. */ + /** + * Whether to allow disabled items to receive focus. When `true`, disabled items are + * focusable but not interactive. When `false`, disabled items are skipped during navigation. + */ + softDisabled = input(true, {transform: booleanAttribute}); + + /** + * The focus strategy used by the list. + * - `roving`: Focus is moved to the active item using `tabindex`. + * - `activedescendant`: Focus remains on the listbox container, and `aria-activedescendant` is used to indicate the active item. + */ focusMode = input<'roving' | 'activedescendant'>('roving'); - /** The selection strategy used by the list. */ + /** + * The selection strategy used by the list. + * - `follow`: The focused item is automatically selected. + * - `explicit`: Items are selected explicitly by the user (e.g., via click or spacebar). + */ selectionMode = input<'follow' | 'explicit'>('follow'); /** The amount of time before the typeahead search is reset. */ - typeaheadDelay = input(0.5); // Picked arbitrarily. + typeaheadDelay = input(500); // Picked arbitrarily. /** Whether the listbox is disabled. */ disabled = input(false, {transform: booleanAttribute}); @@ -115,11 +131,11 @@ export class Listbox { /** Whether the listbox is readonly. */ readonly = input(false, {transform: booleanAttribute}); - /** The values of the current selected items. */ - value = model([]); + /** The values of the currently selected items. */ + values = model([]); /** The Listbox UIPattern. */ - pattern: ListboxPattern; + readonly _pattern: ListboxPattern; /** Whether the listbox has received focus yet. */ private _hasFocused = signal(false); @@ -132,20 +148,20 @@ export class Listbox { activeItem: signal(undefined), textDirection: this.textDirection, element: () => this._elementRef.nativeElement, - combobox: () => this._popup?.combobox?.pattern, + combobox: () => this._popup?.combobox?._pattern, }; - this.pattern = this._popup?.combobox + this._pattern = this._popup?.combobox ? new ComboboxListboxPattern(inputs) : new ListboxPattern(inputs); if (this._popup) { - this._popup.controls.set(this.pattern as ComboboxListboxPattern); + this._popup._controls.set(this._pattern as ComboboxListboxPattern); } afterRenderEffect(() => { if (typeof ngDevMode === 'undefined' || ngDevMode) { - const violations = this.pattern.validate(); + const violations = this._pattern.validate(); for (const violation of violations) { console.error(violation); } @@ -154,7 +170,7 @@ export class Listbox { afterRenderEffect(() => { if (!this._hasFocused()) { - this.pattern.setDefaultState(); + this._pattern.setDefaultState(); } }); @@ -165,81 +181,31 @@ export class Listbox { const activeItem = untracked(() => inputs.activeItem()); if (!items.some(i => i === activeItem) && activeItem) { - this.pattern.listBehavior.unfocus(); + this._pattern.listBehavior.unfocus(); } }); - // Ensure that the value is always in sync with the available options. + // Ensure that the values are always in sync with the available options. afterRenderEffect(() => { const items = inputs.items(); - const value = untracked(() => this.value()); + const values = untracked(() => this.values()); - if (items && value.some(v => !items.some(i => i.value() === v))) { - this.value.set(value.filter(v => items.some(i => i.value() === v))); + if (items && values.some(v => !items.some(i => i.value() === v))) { + this.values.set(values.filter(v => items.some(i => i.value() === v))); } }); } - onFocus() { + _onFocus() { this._hasFocused.set(true); } -} - -/** A selectable option in a Listbox. */ -@Directive({ - selector: '[ngOption]', - exportAs: 'ngOption', - host: { - 'role': 'option', - 'class': 'ng-option', - '[attr.data-active]': 'pattern.active()', - '[attr.id]': 'pattern.id()', - '[attr.tabindex]': 'pattern.tabindex()', - '[attr.aria-selected]': 'pattern.selected()', - '[attr.aria-disabled]': 'pattern.disabled()', - }, -}) -export class Option { - /** A reference to the option element. */ - private readonly _elementRef = inject(ElementRef); - - /** The parent Listbox. */ - private readonly _listbox = inject(Listbox); - - /** A unique identifier for the option. */ - private readonly _generatedId = inject(_IdGenerator).getId('ng-option-'); - - // TODO(wagnermaciel): https://github.com/angular/components/pull/30495#discussion_r1972601144. - /** A unique identifier for the option. */ - protected id = computed(() => this._generatedId); - - // TODO(wagnermaciel): See if we want to change how we handle this since textContent is not - // reactive. See https://github.com/angular/components/pull/30495#discussion_r1961260216. - /** The text used by the typeahead search. */ - protected searchTerm = computed(() => this.label() ?? this.element().textContent); - - /** The parent Listbox UIPattern. */ - protected listbox = computed(() => this._listbox.pattern); - /** A reference to the option element to be focused on navigation. */ - protected element = computed(() => this._elementRef.nativeElement); - - /** The value of the option. */ - value = input.required(); - - /** Whether an item is disabled. */ - disabled = input(false, {transform: booleanAttribute}); + scrollActiveItemIntoView(options: ScrollIntoViewOptions = {block: 'nearest'}) { + this._pattern.inputs.activeItem()?.element()?.scrollIntoView(options); + } - /** The text used by the typeahead search. */ - label = input(); - - /** The Option UIPattern. */ - pattern = new OptionPattern({ - ...this, - id: this.id, - value: this.value, - listbox: this.listbox, - element: this.element, - searchTerm: this.searchTerm, - }); + /** Navigates to the first item in the listbox. */ + gotoFirst() { + this._pattern.listBehavior.first(); + } } diff --git a/src/aria/listbox/option.ts b/src/aria/listbox/option.ts new file mode 100644 index 000000000000..b14205678fe9 --- /dev/null +++ b/src/aria/listbox/option.ts @@ -0,0 +1,88 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {booleanAttribute, computed, Directive, ElementRef, inject, input} from '@angular/core'; +import {_IdGenerator} from '@angular/cdk/a11y'; +import {OptionPattern} from '../private'; +import {LISTBOX} from './tokens'; + +/** + * A selectable option in an `ngListbox`. + * + * This directive should be applied to an element (e.g., `
      • `, `
        `) within an + * `ngListbox`. The `value` input is used to identify the option, and the `label` input provides + * the accessible name for the option. + * + * ```html + *
      • + * Item Name + *
      • + * ``` + * + * @developerPreview 21.0 + * + * @see [Listbox](guide/aria/listbox) + * @see [Autocomplete](guide/aria/autocomplete) + * @see [Select](guide/aria/select) + * @see [Multiselect](guide/aria/multiselect) + */ +@Directive({ + selector: '[ngOption]', + exportAs: 'ngOption', + host: { + 'role': 'option', + '[attr.data-active]': 'active()', + '[attr.id]': '_pattern.id()', + '[attr.tabindex]': '_pattern.tabIndex()', + '[attr.aria-selected]': '_pattern.selected()', + '[attr.aria-disabled]': '_pattern.disabled()', + }, +}) +export class Option { + /** A reference to the host element. */ + readonly element = inject(ElementRef).nativeElement as HTMLElement; + + /** Whether the option is currently active (focused). */ + active = computed(() => this._pattern.active()); + + /** The parent Listbox. */ + private readonly _listbox = inject(LISTBOX); + + /** A unique identifier for the option. */ + readonly id = input(inject(_IdGenerator).getId('ng-option-', true)); + + // TODO(wagnermaciel): See if we want to change how we handle this since textContent is not + // reactive. See https://github.com/angular/components/pull/30495#discussion_r1961260216. + /** The text used by the typeahead search. */ + protected searchTerm = computed(() => this.label() ?? this.element.textContent); + + /** The parent Listbox UIPattern. */ + private readonly _listboxPattern = computed(() => this._listbox._pattern); + + /** The value of the option. */ + value = input.required(); + + /** Whether an item is disabled. */ + disabled = input(false, {transform: booleanAttribute}); + + /** The text used by the typeahead search. */ + label = input(); + + /** Whether the option is selected. */ + readonly selected = computed(() => this._pattern.selected()); + + /** The Option UIPattern. */ + readonly _pattern = new OptionPattern({ + ...this, + id: this.id, + value: this.value, + listbox: this._listboxPattern, + element: () => this.element, + searchTerm: () => this.searchTerm() ?? '', + }); +} diff --git a/src/aria/listbox/public-api.ts b/src/aria/listbox/public-api.ts new file mode 100644 index 000000000000..b91aa4aeb6be --- /dev/null +++ b/src/aria/listbox/public-api.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +export {Listbox} from './listbox'; +export {Option} from './option'; + +// This needs to be re-exported, because it's used by the listbox components. +// See: https://github.com/angular/components/issues/30663. +export { + Combobox as ɵɵCombobox, + ComboboxDialog as ɵɵComboboxDialog, + ComboboxInput as ɵɵComboboxInput, + ComboboxPopup as ɵɵComboboxPopup, + ComboboxPopupContainer as ɵɵComboboxPopupContainer, +} from '../combobox'; diff --git a/src/aria/listbox/tokens.ts b/src/aria/listbox/tokens.ts new file mode 100644 index 000000000000..0caf8ad6d1aa --- /dev/null +++ b/src/aria/listbox/tokens.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {InjectionToken} from '@angular/core'; +import type {Listbox} from './listbox'; + +export const LISTBOX = new InjectionToken>('LISTBOX'); diff --git a/src/aria/menu/BUILD.bazel b/src/aria/menu/BUILD.bazel index 10c8ec376f4e..5a70236fb388 100644 --- a/src/aria/menu/BUILD.bazel +++ b/src/aria/menu/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite") +load("//tools:defaults.bzl", "extract_api_to_json", "ng_project", "ng_web_test_suite") package(default_visibility = ["//visibility:public"]) @@ -10,7 +10,7 @@ ng_project( ), deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns", + "//src/aria/private", "//src/cdk/a11y", "//src/cdk/bidi", ], @@ -36,3 +36,23 @@ ng_web_test_suite( name = "unit_tests", deps = [":unit_test_sources"], ) + +filegroup( + name = "source-files", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), +) + +extract_api_to_json( + name = "json_api", + srcs = [ + ":source-files", + ], + entry_point = ":index.ts", + module_name = "@angular/aria/menu", + output_name = "aria-menu.json", + private_modules = [""], + repo = "angular/components", +) diff --git a/src/aria/menu/index.ts b/src/aria/menu/index.ts index 135a0a300210..52b3c7a5156f 100644 --- a/src/aria/menu/index.ts +++ b/src/aria/menu/index.ts @@ -6,4 +6,4 @@ * found in the LICENSE file at https://angular.dev/license */ -export {Menu, MenuBar, MenuItem, MenuTrigger} from './menu'; +export * from './public-api'; diff --git a/src/aria/menu/menu-bar.ts b/src/aria/menu/menu-bar.ts new file mode 100644 index 000000000000..cd3662f19e68 --- /dev/null +++ b/src/aria/menu/menu-bar.ts @@ -0,0 +1,141 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + afterRenderEffect, + booleanAttribute, + computed, + contentChildren, + Directive, + ElementRef, + inject, + input, + model, + output, + signal, +} from '@angular/core'; +import {SignalLike, MenuBarPattern} from '../private'; +import {Directionality} from '@angular/cdk/bidi'; +import {MenuItem} from './menu-item'; +import {MENU_COMPONENT} from './menu-tokens'; + +/** + * A menu bar of menu items. + * + * Like the `ngMenu`, a `ngMenuBar` is used to offer a list of menu item choices to users. + * However, a menubar is used to display a persistent, top-level, always-visible set of + * menu item choices, typically found at the top of an application window. + * + * ```html + *
        + * + * + *
        + * + *
        + *
        New
        + *
        Open
        + *
        + * + *
        + *
        Cut
        + *
        Copy
        + *
        + * ``` + * + * @developerPreview 21.0 + * + * @see [Menu](guide/aria/menu) + * @see [MenuBar](guide/aria/menubar) + */ +@Directive({ + selector: '[ngMenuBar]', + exportAs: 'ngMenuBar', + host: { + 'role': 'menubar', + '[attr.disabled]': '!softDisabled() && _pattern.disabled() ? true : null', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.tabindex]': '_pattern.tabIndex()', + '(keydown)': '_pattern.onKeydown($event)', + '(mouseover)': '_pattern.onMouseOver($event)', + '(click)': '_pattern.onClick($event)', + '(focusin)': '_pattern.onFocusIn()', + '(focusout)': '_pattern.onFocusOut($event)', + }, + providers: [{provide: MENU_COMPONENT, useExisting: MenuBar}], +}) +export class MenuBar { + /** The menu items contained in the menubar. */ + readonly _allItems = contentChildren>(MenuItem, {descendants: true}); + + readonly _items: SignalLike[]> = () => + this._allItems().filter(i => i.parent === this); + + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** Whether the menubar is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** Whether the menubar is soft disabled. */ + readonly softDisabled = input(true, {transform: booleanAttribute}); + + /** The directionality (LTR / RTL) context for the application (or a subtree of it). */ + readonly textDirection = inject(Directionality).valueSignal; + + /** The values of the currently selected menu items. */ + readonly values = model([]); + + /** Whether the menu should wrap its items. */ + readonly wrap = input(true, {transform: booleanAttribute}); + + /** The delay in milliseconds before the typeahead buffer is cleared. */ + readonly typeaheadDelay = input(500); + + /** The menu ui pattern instance. */ + readonly _pattern: MenuBarPattern; + + /** The menu items as a writable signal. */ + private readonly _itemPatterns = signal([]); + + /** A callback function triggered when a menu item is selected. */ + onSelect = output(); + + constructor() { + this._pattern = new MenuBarPattern({ + ...this, + items: this._itemPatterns, + multi: () => false, + softDisabled: () => true, + focusMode: () => 'roving', + orientation: () => 'horizontal', + selectionMode: () => 'explicit', + onSelect: (value: V) => this.onSelect.emit(value), + activeItem: signal(undefined), + element: computed(() => this._elementRef.nativeElement), + }); + + afterRenderEffect(() => { + this._itemPatterns.set(this._items().map(i => i._pattern)); + }); + + afterRenderEffect(() => { + if (!this._pattern.hasBeenFocused()) { + this._pattern.setDefaultState(); + } + }); + } + + /** Closes the menubar. */ + close() { + this._pattern.close(); + } +} diff --git a/src/aria/menu/menu-content.ts b/src/aria/menu/menu-content.ts new file mode 100644 index 000000000000..fa241646c56c --- /dev/null +++ b/src/aria/menu/menu-content.ts @@ -0,0 +1,37 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Directive} from '@angular/core'; +import {DeferredContent} from '../private'; + +/** + * Defers the rendering of the menu content. + * + * This structural directive should be applied to an `ng-template` within a `ngMenu` + * or `ngMenuBar` to lazily render its content only when the menu is opened. + * + * ```html + *
        + * + *
        Lazy Item 1
        + *
        Lazy Item 2
        + *
        + *
        + * ``` + * + * @developerPreview 21.0 + * + * @see [Menu](guide/aria/menu) + * @see [MenuBar](guide/aria/menubar) + */ +@Directive({ + selector: 'ng-template[ngMenuContent]', + exportAs: 'ngMenuContent', + hostDirectives: [DeferredContent], +}) +export class MenuContent {} diff --git a/src/aria/menu/menu-item.ts b/src/aria/menu/menu-item.ts new file mode 100644 index 000000000000..7fb9a83bf1ab --- /dev/null +++ b/src/aria/menu/menu-item.ts @@ -0,0 +1,107 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {computed, Directive, effect, ElementRef, inject, input, model} from '@angular/core'; +import {MenuItemPattern} from '../private'; +import {_IdGenerator} from '@angular/cdk/a11y'; +import {MENU_COMPONENT} from './menu-tokens'; +import type {Menu} from './menu'; +import type {MenuBar} from './menu-bar'; + +/** + * An item in a Menu. + * + * `ngMenuItem` directives can be used in `ngMenu` and `ngMenuBar` to represent a choice + * or action a user can take. They can also act as triggers for sub-menus. + * + * ```html + *
        Action Item
        + * + *
        Submenu Trigger
        + * ``` + * + * @developerPreview 21.0 + * + * @see [Menu](guide/aria/menu) + * @see [MenuBar](guide/aria/menubar) + */ +@Directive({ + selector: '[ngMenuItem]', + exportAs: 'ngMenuItem', + host: { + 'role': 'menuitem', + '(focusin)': '_pattern.onFocusIn()', + '[attr.tabindex]': '_pattern.tabIndex()', + '[attr.data-active]': 'active()', + '[attr.aria-haspopup]': 'hasPopup()', + '[attr.aria-expanded]': 'expanded()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.aria-controls]': '_pattern.submenu()?.id()', + }, +}) +export class MenuItem { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The unique ID of the menu item. */ + readonly id = input(inject(_IdGenerator).getId('ng-menu-item-', true)); + + /** The value of the menu item. */ + readonly value = input.required(); + + /** Whether the menu item is disabled. */ + readonly disabled = input(false); + + // TODO(wagnermaciel): Discuss whether all inputs should be models. + + /** The search term associated with the menu item. */ + readonly searchTerm = model(''); + + /** A reference to the parent menu or menubar. */ + readonly parent = inject | MenuBar>(MENU_COMPONENT, {optional: true}); + + /** The submenu associated with the menu item. */ + readonly submenu = input | undefined>(undefined); + + /** Whether the menu item is active. */ + readonly active = computed(() => this._pattern.active()); + + /** Whether the menu is expanded. */ + readonly expanded = computed(() => this._pattern.expanded()); + + /** Whether the menu item has a popup. */ + readonly hasPopup = computed(() => this._pattern.hasPopup()); + + /** The menu item ui pattern instance. */ + readonly _pattern: MenuItemPattern = new MenuItemPattern({ + id: this.id, + value: this.value, + element: computed(() => this._elementRef.nativeElement), + disabled: this.disabled, + searchTerm: this.searchTerm, + parent: computed(() => this.parent?._pattern), + submenu: computed(() => this.submenu()?._pattern), + }); + + constructor() { + effect(() => this.submenu()?.parent.set(this)); + } + + /** Opens the submenu focusing on the first menu item. */ + open() { + this._pattern.open({first: true}); + } + + /** Closes the submenu. */ + close() { + this._pattern.close(); + } +} diff --git a/src/aria/menu/menu-tokens.ts b/src/aria/menu/menu-tokens.ts new file mode 100644 index 000000000000..6709a3db8883 --- /dev/null +++ b/src/aria/menu/menu-tokens.ts @@ -0,0 +1,14 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {InjectionToken} from '@angular/core'; +import type {Menu} from './menu'; +import type {MenuBar} from './menu-bar'; + +/** Token used to expose menus to their child components. */ +export const MENU_COMPONENT = new InjectionToken | MenuBar>('MENU_COMPONENT'); diff --git a/src/aria/menu/menu-trigger.ts b/src/aria/menu/menu-trigger.ts new file mode 100644 index 000000000000..44bdd91b6d03 --- /dev/null +++ b/src/aria/menu/menu-trigger.ts @@ -0,0 +1,105 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + booleanAttribute, + computed, + Directive, + effect, + ElementRef, + inject, + input, +} from '@angular/core'; +import {MenuTriggerPattern} from '../private'; +import {Directionality} from '@angular/cdk/bidi'; +import type {Menu} from './menu'; + +/** + * A trigger for a menu. + * + * The `ngMenuTrigger` directive is used to open and close menus. It can be applied to + * any interactive element (e.g., a button) to associate it with a `ngMenu` instance. + * It also supports linking to sub-menus when applied to a `ngMenuItem`. + * + * ```html + * + * + *
        + *
        Item 1
        + *
        Item 2
        + *
        + * ``` + * + * @developerPreview 21.0 + * + * @see [Menu](guide/aria/menu) + * @see [MenuBar](guide/aria/menubar) + */ +@Directive({ + selector: 'button[ngMenuTrigger]', + exportAs: 'ngMenuTrigger', + host: { + '[attr.tabindex]': '_pattern.tabIndex()', + '[attr.disabled]': '!softDisabled() && _pattern.disabled() ? true : null', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.aria-haspopup]': 'hasPopup()', + '[attr.aria-expanded]': 'expanded()', + '[attr.aria-controls]': '_pattern.menu()?.id()', + '(click)': '_pattern.onClick()', + '(keydown)': '_pattern.onKeydown($event)', + '(focusout)': '_pattern.onFocusOut($event)', + '(focusin)': '_pattern.onFocusIn()', + }, +}) +export class MenuTrigger { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The directionality (LTR / RTL) context for the application (or a subtree of it). */ + readonly textDirection = inject(Directionality).valueSignal; + + /** The menu associated with the trigger. */ + menu = input | undefined>(undefined); + + /** Whether the menu is expanded. */ + readonly expanded = computed(() => this._pattern.expanded()); + + /** Whether the menu trigger has a popup. */ + readonly hasPopup = computed(() => this._pattern.hasPopup()); + + /** Whether the menu trigger is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** Whether the menu trigger is soft disabled. */ + readonly softDisabled = input(true, {transform: booleanAttribute}); + + /** The menu trigger ui pattern instance. */ + _pattern: MenuTriggerPattern = new MenuTriggerPattern({ + textDirection: this.textDirection, + element: computed(() => this._elementRef.nativeElement), + menu: computed(() => this.menu()?._pattern), + disabled: () => this.disabled(), + }); + + constructor() { + effect(() => this.menu()?.parent.set(this)); + } + + /** Opens the menu focusing on the first menu item. */ + open() { + this._pattern.open({first: true}); + } + + /** Closes the menu. */ + close() { + this._pattern.close(); + } +} diff --git a/src/aria/menu/menu.spec.ts b/src/aria/menu/menu.spec.ts index 9ed1e34e958f..cb7a7c55cec2 100644 --- a/src/aria/menu/menu.spec.ts +++ b/src/aria/menu/menu.spec.ts @@ -1,7 +1,12 @@ import {Component, DebugElement} from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {Menu, MenuBar, MenuItem, MenuTrigger} from './menu'; +import {provideFakeDirectionality} from '@angular/cdk/testing/private'; +import {Menu} from './menu'; +import {MenuBar} from './menu-bar'; +import {MenuContent} from './menu-content'; +import {MenuItem} from './menu-item'; +import {MenuTrigger} from './menu-trigger'; describe('Standalone Menu Pattern', () => { let fixture: ComponentFixture; @@ -17,8 +22,9 @@ describe('Standalone Menu Pattern', () => { fixture.detectChanges(); }; - const mouseover = (element: Element) => { + const mouseover = async (element: Element) => { element.dispatchEvent(new MouseEvent('mouseover', {bubbles: true})); + await new Promise(resolve => setTimeout(resolve, 0)); fixture.detectChanges(); }; @@ -37,8 +43,10 @@ describe('Standalone Menu Pattern', () => { fixture.detectChanges(); }; - function setupMenu() { - TestBed.configureTestingModule({}); + function setupMenu(opts?: {textDirection: 'ltr' | 'rtl'}) { + TestBed.configureTestingModule({ + providers: [provideFakeDirectionality(opts?.textDirection ?? 'ltr')], + }); fixture = TestBed.createComponent(StandaloneMenuExample); fixture.detectChanges(); getItem('Apple')?.focus(); @@ -102,15 +110,15 @@ describe('Standalone Menu Pattern', () => { }); describe('Typeahead', () => { - it('should move the active item to the next item that starts with the typed character', fakeAsync(() => { + it('should move the active item to the next item that starts with the typed character', () => { const apple = getItem('Apple'); const banana = getItem('Banana'); keydown(apple!, 'b'); expect(document.activeElement).toBe(banana); - })); + }); - it('should support multi-character typeahead', fakeAsync(() => { + it('should support multi-character typeahead', () => { const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); @@ -118,13 +126,11 @@ describe('Standalone Menu Pattern', () => { keydown(apple!, 'b'); expect(document.activeElement).toBe(banana); - tick(100); keydown(document.activeElement!, 'e'); - expect(document.activeElement).toBe(berries); - })); + }); - it('should wrap when reaching the end of the list during typeahead', fakeAsync(() => { + it('should wrap when reaching the end of the list during typeahead', () => { const apple = getItem('Apple'); const cherry = getItem('Cherry'); @@ -135,14 +141,14 @@ describe('Standalone Menu Pattern', () => { // Type 'a', which should wrap to 'Apple' keydown(document.activeElement!, 'a'); expect(document.activeElement).toBe(apple); - })); + }); - it('should not move the active item if no item matches the typed character', fakeAsync(() => { + it('should not move the active item if no item matches the typed character', () => { const apple = getItem('Apple'); keydown(apple!, 'z'); expect(document.activeElement).toBe(apple); - })); + }); }); }); @@ -151,49 +157,49 @@ describe('Standalone Menu Pattern', () => { it('should select an item on click', () => { const banana = getItem('Banana'); - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); click(banana!); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Banana'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Banana'); }); it('should select an item on enter', () => { const banana = getItem('Banana'); - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); keydown(document.activeElement!, 'ArrowDown'); // Move focus to Banana expect(document.activeElement).toBe(banana); keydown(banana!, 'Enter'); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Banana'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Banana'); }); it('should select an item on space', () => { const banana = getItem('Banana'); - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); keydown(document.activeElement!, 'ArrowDown'); // Move focus to Banana expect(document.activeElement).toBe(banana); keydown(banana!, ' '); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Banana'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Banana'); }); it('should not select a disabled item', () => { const cherry = getItem('Cherry'); - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); click(cherry!); - expect(fixture.componentInstance.onSubmit).not.toHaveBeenCalled(); + expect(fixture.componentInstance.onSelect).not.toHaveBeenCalled(); keydown(document.activeElement!, 'End'); expect(document.activeElement).toBe(cherry); keydown(cherry!, 'Enter'); - expect(fixture.componentInstance.onSubmit).not.toHaveBeenCalled(); + expect(fixture.componentInstance.onSelect).not.toHaveBeenCalled(); keydown(cherry!, ' '); - expect(fixture.componentInstance.onSubmit).not.toHaveBeenCalled(); + expect(fixture.componentInstance.onSelect).not.toHaveBeenCalled(); }); }); @@ -225,25 +231,24 @@ describe('Standalone Menu Pattern', () => { const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); - const blueberry = getItem('Blueberry'); keydown(apple!, 'ArrowDown'); keydown(banana!, 'ArrowDown'); keydown(berries!, 'ArrowRight'); expect(isSubmenuExpanded()).toBe(true); - expect(document.activeElement).toBe(blueberry); + expect(document.activeElement).toBe(getItem('Blueberry')); }); it('should close submenu on arrow left', () => { const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); - const blueberry = getItem('Blueberry'); keydown(apple!, 'ArrowDown'); keydown(banana!, 'ArrowDown'); keydown(berries!, 'ArrowRight'); + const blueberry = getItem('Blueberry'); keydown(blueberry!, 'ArrowLeft'); expect(isSubmenuExpanded()).toBe(false); @@ -252,12 +257,11 @@ describe('Standalone Menu Pattern', () => { it('should close submenu on click outside', () => { const berries = getItem('Berries'); - const blueberry = getItem('Blueberry'); click(berries!); expect(isSubmenuExpanded()).toBe(true); - focusout(blueberry!, document.body); + focusout(getItem('Blueberry')!, document.body); expect(isSubmenuExpanded()).toBe(false); }); @@ -265,41 +269,39 @@ describe('Standalone Menu Pattern', () => { const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); - const blueberry = getItem('Blueberry'); keydown(apple!, 'ArrowDown'); keydown(banana!, 'ArrowDown'); keydown(berries!, 'Enter'); expect(isSubmenuExpanded()).toBe(true); - expect(document.activeElement).toBe(blueberry); + expect(document.activeElement).toBe(getItem('Blueberry')); }); it('should expand submenu on space', () => { const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); - const blueberry = getItem('Blueberry'); keydown(apple!, 'ArrowDown'); keydown(banana!, 'ArrowDown'); keydown(berries!, ' '); expect(isSubmenuExpanded()).toBe(true); - expect(document.activeElement).toBe(blueberry); + expect(document.activeElement).toBe(getItem('Blueberry')); }); it('should close submenu on escape', () => { const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); - const blueberry = getItem('Blueberry'); keydown(apple!, 'ArrowDown'); keydown(banana!, 'ArrowDown'); keydown(berries!, 'ArrowRight'); expect(isSubmenuExpanded()).toBe(true); + const blueberry = getItem('Blueberry'); expect(document.activeElement).toBe(blueberry); keydown(blueberry!, 'Escape'); @@ -308,59 +310,58 @@ describe('Standalone Menu Pattern', () => { expect(document.activeElement).toBe(berries); }); - it('should open submenu on mouseover', fakeAsync(() => { + it('should open submenu on mouseover', async () => { const berries = getItem('Berries'); - mouseover(berries!); - tick(); + await mouseover(berries!); expect(isSubmenuExpanded()).toBe(true); - })); + }); it('should close on selecting an item on click', () => { - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); click(getItem('Berries')!); // open submenu expect(isSubmenuExpanded()).toBe(true); click(getItem('Blueberry')!); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Blueberry'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Blueberry'); expect(isSubmenuExpanded()).toBe(false); }); it('should close on selecting an item on enter', () => { - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); - const blueberry = getItem('Blueberry'); keydown(apple!, 'ArrowDown'); keydown(banana!, 'ArrowDown'); keydown(berries!, 'Enter'); // open submenu + const blueberry = getItem('Blueberry'); expect(document.activeElement).toBe(blueberry); keydown(blueberry!, 'Enter'); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Blueberry'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Blueberry'); expect(isSubmenuExpanded()).toBe(false); }); it('should close on selecting an item on space', () => { - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); - const blueberry = getItem('Blueberry'); keydown(apple!, 'ArrowDown'); keydown(banana!, 'ArrowDown'); keydown(berries!, ' '); // open submenu + const blueberry = getItem('Blueberry'); expect(document.activeElement).toBe(blueberry); keydown(blueberry!, ' '); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Blueberry'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Blueberry'); expect(isSubmenuExpanded()).toBe(false); }); @@ -368,12 +369,12 @@ describe('Standalone Menu Pattern', () => { const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); - const blueberry = getItem('Blueberry'); keydown(apple!, 'ArrowDown'); keydown(banana!, 'ArrowDown'); keydown(berries!, 'ArrowRight'); expect(isSubmenuExpanded()).toBe(true); + const blueberry = getItem('Blueberry'); expect(document.activeElement).toBe(blueberry); const externalElement = document.createElement('button'); @@ -385,41 +386,90 @@ describe('Standalone Menu Pattern', () => { externalElement.remove(); }); - it('should close an unfocused submenu on mouse out', fakeAsync(() => { + it('should close an unfocused submenu on mouse out', async () => { const berries = getItem('Berries'); const submenu = getSubmenu(); - mouseover(berries!); - tick(); + await mouseover(berries!); expect(isSubmenuExpanded()).toBe(true); mouseout(berries!); mouseout(submenu!); - tick(500); expect(isSubmenuExpanded()).toBe(false); - })); + }); - it('should not close an unfocused submenu on mouse out if the parent menu is hovered', fakeAsync(() => { + it('should not close an unfocused submenu on mouse out if the parent menu is hovered', async () => { const berries = getItem('Berries'); const submenu = getSubmenu(); - mouseover(berries!); - tick(); + await mouseover(berries!); expect(isSubmenuExpanded()).toBe(true); mouseout(berries!); mouseover(submenu!); - tick(500); expect(isSubmenuExpanded()).toBe(true); - })); + }); + }); + + describe('RTL', () => { + function isSubmenuExpanded(): boolean { + const berries = getItem('Berries'); + return berries?.getAttribute('aria-expanded') === 'true'; + } + + beforeEach(() => setupMenu({textDirection: 'rtl'})); + + it('should open submenu on arrow left', () => { + const apple = getItem('Apple'); + const banana = getItem('Banana'); + const berries = getItem('Berries'); + + keydown(apple!, 'ArrowDown'); + keydown(banana!, 'ArrowDown'); + keydown(berries!, 'ArrowLeft'); + + expect(isSubmenuExpanded()).toBe(true); + expect(document.activeElement).toBe(getItem('Blueberry')); + }); + + it('should close submenu on arrow right', () => { + const apple = getItem('Apple'); + const banana = getItem('Banana'); + const berries = getItem('Berries'); + + keydown(apple!, 'ArrowDown'); + keydown(banana!, 'ArrowDown'); + keydown(berries!, 'ArrowLeft'); + const blueberry = getItem('Blueberry'); + keydown(blueberry!, 'ArrowRight'); + + expect(isSubmenuExpanded()).toBe(false); + expect(document.activeElement).toBe(berries); + }); + }); + + it('should not reset default state on hover triggers expansion', async () => { + TestBed.configureTestingModule({}); + fixture = TestBed.createComponent(StandaloneMenuExample); + fixture.detectChanges(); + + const berries = getItem('Berries'); + await mouseover(berries!); + expect(berries?.getAttribute('data-active')).toBe('true'); }); }); describe('Menu Trigger Pattern', () => { let fixture: ComponentFixture; + const focusin = (element: Element) => { + element.dispatchEvent(new FocusEvent('focusin', {bubbles: true})); + fixture.detectChanges(); + }; + const keydown = (element: Element, key: string, modifierKeys: {} = {}) => { + focusin(element); element.dispatchEvent( new KeyboardEvent('keydown', { key, @@ -431,6 +481,7 @@ describe('Menu Trigger Pattern', () => { }; const click = (element: Element, eventInit?: PointerEventInit) => { + focusin(element); element.dispatchEvent(new PointerEvent('click', {bubbles: true, ...eventInit})); fixture.detectChanges(); }; @@ -441,10 +492,8 @@ describe('Menu Trigger Pattern', () => { }; function setupMenu() { - TestBed.configureTestingModule({}); fixture = TestBed.createComponent(MenuTriggerExample); fixture.detectChanges(); - getItem('Apple')?.focus(); } function getTrigger(): HTMLElement { @@ -563,7 +612,7 @@ describe('Menu Trigger Pattern', () => { expect(isExpanded()).toBe(false); }); - it('should close on selecting an item on space', () => { + it('should close on selecting an item on space', async () => { click(getTrigger()); keydown(getItem('Apple')!, ' '); expect(isExpanded()).toBe(false); @@ -608,8 +657,10 @@ describe('Menu Bar Pattern', () => { fixture.detectChanges(); }; - function setupMenu() { - TestBed.configureTestingModule({}); + function setupMenu(opts?: {textDirection: 'ltr' | 'rtl'}) { + TestBed.configureTestingModule({ + providers: [provideFakeDirectionality(opts?.textDirection ?? 'ltr')], + }); fixture = TestBed.createComponent(MenuBarExample); fixture.detectChanges(); getMenuBarItem('File')?.focus(); @@ -641,10 +692,7 @@ describe('Menu Bar Pattern', () => { } describe('Navigation', () => { - beforeEach(() => { - setupMenu(); - getMenuBarItem('File')?.focus(); - }); + beforeEach(() => setupMenu()); it('should navigate to the first item on arrow down', () => { const file = getMenuBarItem('File'); @@ -873,49 +921,91 @@ describe('Menu Bar Pattern', () => { expect(isExpanded('Edit')).toBe(true); }); }); + + describe('RTL', () => { + beforeEach(() => setupMenu({textDirection: 'rtl'})); + + it('should focus the first item of the next menubar item on arrow left', () => { + const edit = getMenuBarItem('Edit'); + const file = getMenuBarItem('File'); + const view = getMenuBarItem('View'); + const documentation = getMenuBarItem('Documentation'); + const zoomIn = getMenuItem('Zoom In'); + + keydown(file!, 'ArrowLeft'); + keydown(edit!, 'ArrowLeft'); + keydown(view!, 'ArrowDown'); + + keydown(zoomIn!, 'ArrowLeft'); + expect(document.activeElement).toBe(documentation); + }); + + it('should focus the first item of the previous menubar item on arrow right', () => { + const edit = getMenuBarItem('Edit'); + const file = getMenuBarItem('File'); + const view = getMenuBarItem('View'); + const undo = getMenuItem('Undo'); + const zoomIn = getMenuItem('Zoom In'); + + keydown(file!, 'ArrowLeft'); + keydown(edit!, 'ArrowLeft'); + keydown(view!, 'ArrowDown'); + + keydown(zoomIn!, 'ArrowRight'); + expect(document.activeElement).toBe(undo); + }); + }); }); @Component({ template: ` -
        -
        Apple
        -
        Banana
        -
        Berries
        - -
        -
        Blueberry
        -
        Blackberry
        -
        Strawberry
        -
        - -
        Cherry
        +
        + +
        Apple
        +
        Banana
        +
        Berries
        + +
        + +
        Blueberry
        +
        Blackberry
        +
        Strawberry
        +
        +
        + +
        Cherry
        +
        `, - imports: [Menu, MenuItem], + imports: [Menu, MenuItem, MenuContent], }) class StandaloneMenuExample { - onSubmit(value: string) {} + onSelect(value: string) {} } @Component({ template: ` - - -
        -
        Apple
        -
        Banana
        -
        Berries
        - -
        -
        Blueberry
        -
        Blackberry
        -
        Strawberry
        -
        - -
        Cherry
        + + +
        + +
        Apple
        +
        Banana
        +
        Berries
        + +
        + +
        Blueberry
        +
        Blackberry
        +
        Strawberry
        +
        +
        + +
        Cherry
        +
        `, - imports: [Menu, MenuItem, MenuTrigger], + imports: [Menu, MenuItem, MenuTrigger, MenuContent], }) class MenuTriggerExample {} @@ -923,29 +1013,35 @@ class MenuTriggerExample {} template: `
        File
        -
        Edit
        +
        Edit
        -
        -
        Undo
        -
        Redo
        +
        + +
        Undo
        +
        Redo
        +
        -
        View
        +
        View
        -
        -
        Zoom In
        -
        Zoom Out
        -
        Full Screen
        +
        + +
        Zoom In
        +
        Zoom Out
        +
        Full Screen
        +
        -
        Help
        +
        Help
        -
        -
        Documentation
        -
        About
        +
        + +
        Documentation
        +
        About
        +
        `, - imports: [Menu, MenuBar, MenuItem], + imports: [Menu, MenuBar, MenuItem, MenuContent], }) class MenuBarExample {} diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index 1e5b0090db60..aae13874e837 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -8,104 +8,81 @@ import { afterRenderEffect, + booleanAttribute, computed, contentChildren, Directive, ElementRef, inject, input, - model, output, Signal, signal, untracked, } from '@angular/core'; -import { - SignalLike, - MenuBarPattern, - MenuItemPattern, - MenuPattern, - MenuTriggerPattern, -} from '@angular/aria/ui-patterns'; -import {toSignal} from '@angular/core/rxjs-interop'; +import {MenuPattern, DeferredContentAware} from '../private'; +import {_IdGenerator} from '@angular/cdk/a11y'; import {Directionality} from '@angular/cdk/bidi'; - -/** - * A trigger for a menu. - * - * The menu trigger is used to open and close menus, and can be placed on menu items to connect - * sub-menus. - */ -@Directive({ - selector: 'button[ngMenuTrigger]', - exportAs: 'ngMenuTrigger', - host: { - 'class': 'ng-menu-trigger', - '[attr.tabindex]': 'uiPattern.tabindex()', - '[attr.aria-haspopup]': 'uiPattern.hasPopup()', - '[attr.aria-expanded]': 'uiPattern.expanded()', - '[attr.aria-controls]': 'uiPattern.submenu()?.id()', - '(click)': 'uiPattern.onClick()', - '(keydown)': 'uiPattern.onKeydown($event)', - '(focusout)': 'uiPattern.onFocusOut($event)', - }, -}) -export class MenuTrigger { - /** A reference to the menu trigger element. */ - private readonly _elementRef = inject(ElementRef); - - /** A reference to the menu element. */ - readonly element: HTMLButtonElement = this._elementRef.nativeElement; - - // TODO(wagnermaciel): See we can remove the need to pass in a submenu. - - /** The submenu associated with the menu trigger. */ - submenu = input | undefined>(undefined); - - /** A callback function triggered when a menu item is selected. */ - onSubmit = output(); - - /** The menu trigger ui pattern instance. */ - uiPattern: MenuTriggerPattern = new MenuTriggerPattern({ - onSubmit: (value: V) => this.onSubmit.emit(value), - element: computed(() => this._elementRef.nativeElement), - submenu: computed(() => this.submenu()?.uiPattern), - }); -} +import {MenuTrigger} from './menu-trigger'; +import {MenuItem} from './menu-item'; +import {MenuBar} from './menu-bar'; +import {MENU_COMPONENT} from './menu-tokens'; /** * A list of menu items. * - * A menu is used to offer a list of menu item choices to users. Menus can be nested within other - * menus to create sub-menus. + * A `ngMenu` is used to offer a list of menu item choices to users. Menus can be nested + * within other menus to create sub-menus. It works in conjunction with `ngMenuTrigger` + * and `ngMenuItem` directives. * * ```html - * + * * - *
        + *
        *
        Star
        *
        Edit
        - *
        Delete
        + *
        More
        + *
        + * + *
        + *
        Sub Item 1
        + *
        Sub Item 2
        *
        * ``` + * + * @developerPreview 21.0 + * + * @see [Menu](guide/aria/menu) + * @see [MenuBar](guide/aria/menubar) */ @Directive({ selector: '[ngMenu]', exportAs: 'ngMenu', host: { 'role': 'menu', - 'class': 'ng-menu', - '[attr.id]': 'uiPattern.id()', - '[attr.data-visible]': 'uiPattern.isVisible()', - '(keydown)': 'uiPattern.onKeydown($event)', - '(mouseover)': 'uiPattern.onMouseOver($event)', - '(mouseout)': 'uiPattern.onMouseOut($event)', - '(focusout)': 'uiPattern.onFocusOut($event)', - '(focusin)': 'uiPattern.onFocusIn()', - '(click)': 'uiPattern.onClick($event)', + '[attr.id]': '_pattern.id()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.tabindex]': 'tabIndex()', + '[attr.data-visible]': 'visible()', + '(keydown)': '_pattern.onKeydown($event)', + '(mouseover)': '_pattern.onMouseOver($event)', + '(mouseout)': '_pattern.onMouseOut($event)', + '(focusout)': '_pattern.onFocusOut($event)', + '(focusin)': '_pattern.onFocusIn()', + '(click)': '_pattern.onClick($event)', }, + hostDirectives: [ + { + directive: DeferredContentAware, + inputs: ['preserveContent'], + }, + ], + providers: [{provide: MENU_COMPONENT, useExisting: Menu}], }) export class Menu { + /** The DeferredContentAware host directive. */ + private readonly _deferredContentAware = inject(DeferredContentAware, {optional: true}); + /** The menu items contained in the menu. */ readonly _allItems = contentChildren>(MenuItem, {descendants: true}); @@ -114,37 +91,32 @@ export class Menu { this._allItems().filter(i => i.parent === this), ); - /** A reference to the menu element. */ + /** A reference to the host element. */ private readonly _elementRef = inject(ElementRef); - /** A reference to the menu element. */ - readonly element: HTMLElement = this._elementRef.nativeElement; + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; /** The directionality (LTR / RTL) context for the application (or a subtree of it). */ - private readonly _directionality = inject(Directionality); - - /** A signal wrapper for directionality. */ - readonly textDirection = toSignal(this._directionality.change, { - initialValue: this._directionality.value, - }); - - /** The submenu associated with the menu. */ - readonly submenu = input | undefined>(undefined); + readonly textDirection = inject(Directionality).valueSignal; /** The unique ID of the menu. */ - readonly id = input(Math.random().toString(36).substring(2, 10)); + readonly id = input(inject(_IdGenerator).getId('ng-menu-', true)); /** Whether the menu should wrap its items. */ - readonly wrap = input(true); + readonly wrap = input(true, {transform: booleanAttribute}); + + /** The delay in milliseconds before the typeahead buffer is cleared. */ + readonly typeaheadDelay = input(500); // Picked arbitrarily. - /** The delay in seconds before the typeahead buffer is cleared. */ - readonly typeaheadDelay = input(0.5); // Picked arbitrarily. + /** Whether the menu is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); /** A reference to the parent menu item or menu trigger. */ - readonly parent = input | MenuItem>(); + readonly parent = signal | MenuItem | undefined>(undefined); /** The menu ui pattern instance. */ - readonly uiPattern: MenuPattern; + readonly _pattern: MenuPattern; /** * The menu items as a writable signal. @@ -153,26 +125,44 @@ export class Menu { * sometimes the items array is empty. The bug can be reproduced by switching this to use a * computed and then quickly opening and closing menus in the dev app. */ - readonly items = () => this._items().map(i => i.uiPattern); + private readonly _itemPatterns = () => this._items().map(i => i._pattern); /** Whether the menu is visible. */ - isVisible = computed(() => this.uiPattern.isVisible()); + readonly visible = computed(() => this._pattern.visible()); + + /** The tab index of the menu. */ + readonly tabIndex = computed(() => this._pattern.tabIndex()); /** A callback function triggered when a menu item is selected. */ - onSubmit = output(); + onSelect = output(); + + /** The delay in milliseconds before expanding sub-menus on hover. */ + readonly expansionDelay = input(100); // Arbitrarily chosen. constructor() { - this.uiPattern = new MenuPattern({ + this._pattern = new MenuPattern({ ...this, - parent: computed(() => this.parent()?.uiPattern), + parent: computed(() => this.parent()?._pattern), + items: this._itemPatterns, multi: () => false, - skipDisabled: () => false, + softDisabled: () => true, focusMode: () => 'roving', orientation: () => 'vertical', selectionMode: () => 'explicit', activeItem: signal(undefined), element: computed(() => this._elementRef.nativeElement), - onSubmit: (value: V) => this.onSubmit.emit(value), + onSelect: (value: V) => this.onSelect.emit(value), + }); + + afterRenderEffect(() => { + const parent = this.parent(); + if (parent instanceof MenuItem && parent.parent instanceof MenuBar) { + this._deferredContentAware?.contentVisible.set(true); + } else { + this._deferredContentAware?.contentVisible.set( + this._pattern.visible() || !!this.parent()?._pattern.hasBeenFocused(), + ); + } }); // TODO(wagnermaciel): This is a redundancy needed for if the user uses display: none to hide @@ -180,184 +170,25 @@ export class Menu { // update the display property. The result is focus() being called on an element that is not // focusable. This simply retries focusing the element after render. afterRenderEffect(() => { - if (this.uiPattern.isVisible()) { - const activeItem = untracked(() => this.uiPattern.inputs.activeItem()); - this.uiPattern.listBehavior.goto(activeItem!); + if (this._pattern.visible()) { + const activeItem = untracked(() => this._pattern.inputs.activeItem()); + this._pattern.listBehavior.goto(activeItem!); } }); afterRenderEffect(() => { - if (!this.uiPattern.hasBeenFocused()) { - this.uiPattern.setDefaultState(); + if ( + !this._pattern.hasBeenFocused() && + !this._pattern.hasBeenHovered() && + this._items().length + ) { + untracked(() => this._pattern.setDefaultState()); } }); } - // TODO(wagnermaciel): Author close, closeAll, and open methods for each directive. - /** Closes the menu. */ - close(opts?: {refocus?: boolean}) { - this.uiPattern.inputs.parent()?.close(opts); - } - - /** Closes all parent menus. */ - closeAll(opts?: {refocus?: boolean}) { - const root = this.uiPattern.root(); - - if (root instanceof MenuTriggerPattern) { - root.close(opts); - } - - if (root instanceof MenuPattern || root instanceof MenuBarPattern) { - root.inputs.activeItem()?.close(opts); - } - } -} - -/** - * A menu bar of menu items. - * - * Like the menu, a menubar is used to offer a list of menu item choices to users. However, a - * menubar is used to display a persistent, top-level, - * always-visible set of menu item choices. - */ -@Directive({ - selector: '[ngMenuBar]', - exportAs: 'ngMenuBar', - host: { - 'role': 'menubar', - 'class': 'ng-menu-bar', - '(keydown)': 'uiPattern.onKeydown($event)', - '(mouseover)': 'uiPattern.onMouseOver($event)', - '(click)': 'uiPattern.onClick($event)', - '(focusin)': 'uiPattern.onFocusIn()', - '(focusout)': 'uiPattern.onFocusOut($event)', - }, -}) -export class MenuBar { - /** The menu items contained in the menubar. */ - readonly _allItems = contentChildren>(MenuItem, {descendants: true}); - - readonly _items: SignalLike[]> = () => - this._allItems().filter(i => i.parent === this); - - /** A reference to the menu element. */ - private readonly _elementRef = inject(ElementRef); - - /** A reference to the menubar element. */ - readonly element: HTMLElement = this._elementRef.nativeElement; - - /** The directionality (LTR / RTL) context for the application (or a subtree of it). */ - private readonly _directionality = inject(Directionality); - - /** A signal wrapper for directionality. */ - readonly textDirection = toSignal(this._directionality.change, { - initialValue: this._directionality.value, - }); - - /** The value of the menu. */ - readonly value = model([]); - - /** Whether the menu should wrap its items. */ - readonly wrap = input(true); - - /** The delay in seconds before the typeahead buffer is cleared. */ - readonly typeaheadDelay = input(0.5); - - /** The menu ui pattern instance. */ - readonly uiPattern: MenuBarPattern; - - /** The menu items as a writable signal. */ - readonly items = signal[]>([]); - - /** A callback function triggered when a menu item is selected. */ - onSubmit = output(); - - constructor() { - this.uiPattern = new MenuBarPattern({ - ...this, - multi: () => false, - skipDisabled: () => false, - focusMode: () => 'roving', - orientation: () => 'horizontal', - selectionMode: () => 'explicit', - onSubmit: (value: V) => this.onSubmit.emit(value), - activeItem: signal(undefined), - element: computed(() => this._elementRef.nativeElement), - }); - - afterRenderEffect(() => { - this.items.set(this._items().map(i => i.uiPattern)); - }); - - afterRenderEffect(() => { - if (!this.uiPattern.hasBeenFocused()) { - this.uiPattern.setDefaultState(); - } - }); + close() { + this._pattern.close(); } } - -/** - * An item in a Menu. - * - * Menu items can be used in menus and menubars to represent a choice or action a user can take. - */ -@Directive({ - selector: '[ngMenuItem]', - exportAs: 'ngMenuItem', - host: { - 'role': 'menuitem', - 'class': 'ng-menu-item', - '[attr.tabindex]': 'uiPattern.tabindex()', - '[attr.data-active]': 'uiPattern.isActive()', - '[attr.aria-haspopup]': 'uiPattern.hasPopup()', - '[attr.aria-expanded]': 'uiPattern.expanded()', - '[attr.aria-disabled]': 'uiPattern.disabled()', - '[attr.aria-controls]': 'uiPattern.submenu()?.id()', - }, -}) -export class MenuItem { - /** A reference to the menu item element. */ - private readonly _elementRef = inject(ElementRef); - - /** A reference to the menu element. */ - readonly element: HTMLElement = this._elementRef.nativeElement; - - /** The unique ID of the menu item. */ - readonly id = input(Math.random().toString(36).substring(2, 10)); - - /** The value of the menu item. */ - readonly value = input.required(); - - /** Whether the menu item is disabled. */ - readonly disabled = input(false); - - // TODO(wagnermaciel): Discuss whether all inputs should be models. - - /** The search term associated with the menu item. */ - readonly searchTerm = model(''); - - /** A reference to the parent menu. */ - private readonly _menu = inject>(Menu, {optional: true}); - - /** A reference to the parent menu bar. */ - private readonly _menuBar = inject>(MenuBar, {optional: true}); - - /** A reference to the parent menu or menubar. */ - readonly parent = this._menu ?? this._menuBar; - - /** The submenu associated with the menu item. */ - readonly submenu = input | undefined>(undefined); - - /** The menu item ui pattern instance. */ - readonly uiPattern: MenuItemPattern = new MenuItemPattern({ - id: this.id, - value: this.value, - element: computed(() => this._elementRef.nativeElement), - disabled: this.disabled, - searchTerm: this.searchTerm, - parent: computed(() => this.parent?.uiPattern), - submenu: computed(() => this.submenu()?.uiPattern), - }); -} diff --git a/src/aria/menu/public-api.ts b/src/aria/menu/public-api.ts new file mode 100644 index 000000000000..98239182ce61 --- /dev/null +++ b/src/aria/menu/public-api.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +export {MenuTrigger} from './menu-trigger'; +export {Menu} from './menu'; +export {MenuBar} from './menu-bar'; +export {MenuItem} from './menu-item'; +export {MenuContent} from './menu-content'; + +// This needs to be re-exported, because it's used by the menu components. +// See: https://github.com/angular/components/issues/30663. +export { + DeferredContent as ɵɵDeferredContent, + DeferredContentAware as ɵɵDeferredContentAware, +} from '../private'; diff --git a/src/aria/private/BUILD.bazel b/src/aria/private/BUILD.bazel new file mode 100644 index 000000000000..f688ab1b20e1 --- /dev/null +++ b/src/aria/private/BUILD.bazel @@ -0,0 +1,24 @@ +load("//tools:defaults.bzl", "ts_project") + +package(default_visibility = ["//visibility:public"]) + +ts_project( + name = "private", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), + deps = [ + "//:node_modules/@angular/core", + "//src/aria/private/accordion", + "//src/aria/private/behaviors/signal-like", + "//src/aria/private/combobox", + "//src/aria/private/deferred-content", + "//src/aria/private/grid", + "//src/aria/private/listbox", + "//src/aria/private/menu", + "//src/aria/private/tabs", + "//src/aria/private/toolbar", + "//src/aria/private/tree", + ], +) diff --git a/src/aria/ui-patterns/accordion/BUILD.bazel b/src/aria/private/accordion/BUILD.bazel similarity index 53% rename from src/aria/ui-patterns/accordion/BUILD.bazel rename to src/aria/private/accordion/BUILD.bazel index eb6bae9dcd69..50e04123df05 100644 --- a/src/aria/ui-patterns/accordion/BUILD.bazel +++ b/src/aria/private/accordion/BUILD.bazel @@ -8,13 +8,12 @@ ts_project( "accordion.ts", ], deps = [ - "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/event-manager", - "//src/aria/ui-patterns/behaviors/expansion", - "//src/aria/ui-patterns/behaviors/list-focus", - "//src/aria/ui-patterns/behaviors/list-navigation", - "//src/aria/ui-patterns/behaviors/list-selection", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/event-manager", + "//src/aria/private/behaviors/expansion", + "//src/aria/private/behaviors/list-focus", + "//src/aria/private/behaviors/list-navigation", + "//src/aria/private/behaviors/list-selection", + "//src/aria/private/behaviors/signal-like", ], ) @@ -26,8 +25,7 @@ ng_project( ], deps = [ ":accordion", - "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/signal-like", "//src/cdk/keycodes", "//src/cdk/testing/private", ], diff --git a/src/aria/ui-patterns/accordion/accordion.spec.ts b/src/aria/private/accordion/accordion.spec.ts similarity index 81% rename from src/aria/ui-patterns/accordion/accordion.spec.ts rename to src/aria/private/accordion/accordion.spec.ts index ccbb5181ceb0..8364a21c70bc 100644 --- a/src/aria/ui-patterns/accordion/accordion.spec.ts +++ b/src/aria/private/accordion/accordion.spec.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.dev/license */ -import {signal} from '@angular/core'; import { AccordionGroupInputs, AccordionGroupPattern, @@ -15,7 +14,7 @@ import { AccordionTriggerInputs, AccordionTriggerPattern, } from './accordion'; -import {SignalLike, WritableSignalLike} from '../behaviors/signal-like/signal-like'; +import {signal, SignalLike, WritableSignalLike} from '../behaviors/signal-like/signal-like'; import {createKeyboardEvent} from '@angular/cdk/testing/private'; import {ModifierKeys} from '@angular/cdk/testing'; @@ -65,10 +64,10 @@ describe('Accordion Pattern', () => { disabled: signal(false), multiExpandable: signal(true), items: signal([]), - expandedIds: signal([]), - skipDisabled: signal(true), + softDisabled: signal(true), wrap: signal(true), element: signal(document.createElement('div')), + getItem: e => triggerPatterns.find(i => i.element() === e), }; groupPattern = new AccordionGroupPattern(groupInputs); @@ -80,7 +79,8 @@ describe('Accordion Pattern', () => { id: signal('trigger-1-id'), element: signal(createAccordionTriggerElement()), disabled: signal(false), - value: signal('panel-1'), // Value should match the panel it controls + panelId: signal('panel-1'), // Value should match the panel it controls + expanded: signal(false), }, { accordionGroup: signal(groupPattern), @@ -88,7 +88,8 @@ describe('Accordion Pattern', () => { id: signal('trigger-2-id'), element: signal(createAccordionTriggerElement()), disabled: signal(false), - value: signal('panel-2'), + panelId: signal('panel-2'), + expanded: signal(false), }, { accordionGroup: signal(groupPattern), @@ -96,7 +97,8 @@ describe('Accordion Pattern', () => { id: signal('trigger-3-id'), element: signal(createAccordionTriggerElement()), disabled: signal(false), - value: signal('panel-3'), + panelId: signal('panel-3'), + expanded: signal(false), }, ]; triggerPatterns = [ @@ -111,17 +113,17 @@ describe('Accordion Pattern', () => { panelInputs = [ { id: signal('panel-1-id'), - value: signal('panel-1'), + panelId: signal('panel-1'), accordionTrigger: signal(undefined), }, { id: signal('panel-2-id'), - value: signal('panel-2'), + panelId: signal('panel-2'), accordionTrigger: signal(undefined), }, { id: signal('panel-3-id'), - value: signal('panel-3'), + panelId: signal('panel-3'), accordionTrigger: signal(undefined), }, ]; @@ -141,12 +143,6 @@ describe('Accordion Pattern', () => { groupInputs.items.set(triggerPatterns); }); - it('expands a panel by setting `value`.', () => { - expect(triggerPatterns[0].expanded()).toBeFalse(); - groupInputs.expandedIds.set(['panel-1']); - expect(triggerPatterns[0].expanded()).toBeTrue(); - }); - it('gets a controlled panel id from a trigger.', () => { expect(panelPatterns[0].id()).toBe('panel-1-id'); expect(triggerPatterns[0].controls()).toBe('panel-1-id'); @@ -159,47 +155,49 @@ describe('Accordion Pattern', () => { describe('Keyboard Navigation', () => { it('does not handle keyboard event if an accordion group is disabled.', () => { groupInputs.disabled.set(true); - triggerPatterns[0].onKeydown(space()); + groupInputs.activeItem.set(triggerPatterns[0]); + groupPattern.onKeydown(space()); expect(panelPatterns[0].hidden()).toBeTrue(); }); it('does not handle keyboard event if an accordion trigger is disabled.', () => { triggerInputs[0].disabled.set(true); - triggerPatterns[0].onKeydown(space()); + groupInputs.activeItem.set(triggerPatterns[0]); + groupPattern.onKeydown(space()); expect(panelPatterns[0].hidden()).toBeTrue(); }); it('navigates to first accordion trigger with home key.', () => { - groupInputs.activeItem.set(groupInputs.items()[2]); + groupInputs.activeItem.set(triggerPatterns[2]); expect(triggerPatterns[2].active()).toBeTrue(); - triggerPatterns[2].onKeydown(home()); + groupPattern.onKeydown(home()); expect(triggerPatterns[2].active()).toBeFalse(); expect(triggerPatterns[0].active()).toBeTrue(); }); it('navigates to last accordion trigger with end key.', () => { - groupInputs.activeItem.set(groupInputs.items()[0]); + groupInputs.activeItem.set(triggerPatterns[0]); expect(triggerPatterns[0].active()).toBeTrue(); - triggerPatterns[0].onKeydown(end()); + groupPattern.onKeydown(end()); expect(triggerPatterns[0].active()).toBeFalse(); expect(triggerPatterns[2].active()).toBeTrue(); }); describe('Vertical Orientation (orientation=vertical)', () => { it('navigates to the next trigger with down key.', () => { - groupInputs.activeItem.set(groupInputs.items()[0]); + groupInputs.activeItem.set(triggerPatterns[0]); expect(triggerPatterns[0].active()).toBeTrue(); expect(triggerPatterns[1].active()).toBeFalse(); - triggerPatterns[0].onKeydown(down()); + groupPattern.onKeydown(down()); expect(triggerPatterns[0].active()).toBeFalse(); expect(triggerPatterns[1].active()).toBeTrue(); }); it('navigates to the previous trigger with up key.', () => { - groupInputs.activeItem.set(groupInputs.items()[1]); + groupInputs.activeItem.set(triggerPatterns[1]); expect(triggerPatterns[0].active()).toBeFalse(); expect(triggerPatterns[1].active()).toBeTrue(); - triggerPatterns[1].onKeydown(up()); + groupPattern.onKeydown(up()); expect(triggerPatterns[1].active()).toBeFalse(); expect(triggerPatterns[0].active()).toBeTrue(); }); @@ -210,19 +208,19 @@ describe('Accordion Pattern', () => { }); it('navigates to the last trigger with up key from first trigger.', () => { - groupInputs.activeItem.set(groupInputs.items()[0]); + groupInputs.activeItem.set(triggerPatterns[0]); expect(triggerPatterns[0].active()).toBeTrue(); expect(triggerPatterns[2].active()).toBeFalse(); - triggerPatterns[0].onKeydown(up()); + groupPattern.onKeydown(up()); expect(triggerPatterns[0].active()).toBeFalse(); expect(triggerPatterns[2].active()).toBeTrue(); }); it('navigates to the first trigger with down key from last trigger.', () => { - groupInputs.activeItem.set(groupInputs.items()[2]); + groupInputs.activeItem.set(triggerPatterns[2]); expect(triggerPatterns[0].active()).toBeFalse(); expect(triggerPatterns[2].active()).toBeTrue(); - triggerPatterns[2].onKeydown(down()); + groupPattern.onKeydown(down()); expect(triggerPatterns[0].active()).toBeTrue(); expect(triggerPatterns[2].active()).toBeFalse(); }); @@ -234,16 +232,16 @@ describe('Accordion Pattern', () => { }); it('stays on the first trigger with up key from first trigger.', () => { - groupInputs.activeItem.set(groupInputs.items()[0]); + groupInputs.activeItem.set(triggerPatterns[0]); expect(triggerPatterns[0].active()).toBeTrue(); - triggerPatterns[0].onKeydown(up()); + groupPattern.onKeydown(up()); expect(triggerPatterns[0].active()).toBeTrue(); }); it('stays on the last trigger with down key from last trigger.', () => { - groupInputs.activeItem.set(groupInputs.items()[2]); + groupInputs.activeItem.set(triggerPatterns[2]); expect(triggerPatterns[2].active()).toBeTrue(); - triggerPatterns[2].onKeydown(down()); + groupPattern.onKeydown(down()); expect(triggerPatterns[2].active()).toBeTrue(); }); }); @@ -255,19 +253,19 @@ describe('Accordion Pattern', () => { }); it('navigates to the next trigger with right key.', () => { - groupInputs.activeItem.set(groupInputs.items()[0]); + groupInputs.activeItem.set(triggerPatterns[0]); expect(triggerPatterns[0].active()).toBeTrue(); expect(triggerPatterns[1].active()).toBeFalse(); - triggerPatterns[0].onKeydown(right()); + groupPattern.onKeydown(right()); expect(triggerPatterns[0].active()).toBeFalse(); expect(triggerPatterns[1].active()).toBeTrue(); }); it('navigates to the previous trigger with left key.', () => { - groupInputs.activeItem.set(groupInputs.items()[1]); + groupInputs.activeItem.set(triggerPatterns[1]); expect(triggerPatterns[0].active()).toBeFalse(); expect(triggerPatterns[1].active()).toBeTrue(); - triggerPatterns[1].onKeydown(left()); + groupPattern.onKeydown(left()); expect(triggerPatterns[1].active()).toBeFalse(); expect(triggerPatterns[0].active()).toBeTrue(); }); @@ -278,19 +276,19 @@ describe('Accordion Pattern', () => { }); it('navigates to the last trigger with left key from first trigger.', () => { - groupInputs.activeItem.set(groupInputs.items()[0]); + groupInputs.activeItem.set(triggerPatterns[0]); expect(triggerPatterns[0].active()).toBeTrue(); expect(triggerPatterns[2].active()).toBeFalse(); - triggerPatterns[0].onKeydown(left()); + groupPattern.onKeydown(left()); expect(triggerPatterns[0].active()).toBeFalse(); expect(triggerPatterns[2].active()).toBeTrue(); }); it('navigates to the first trigger with right key from last trigger.', () => { - groupInputs.activeItem.set(groupInputs.items()[2]); + groupInputs.activeItem.set(triggerPatterns[2]); expect(triggerPatterns[2].active()).toBeTrue(); expect(triggerPatterns[0].active()).toBeFalse(); - triggerPatterns[2].onKeydown(right()); + groupPattern.onKeydown(right()); expect(triggerPatterns[2].active()).toBeFalse(); expect(triggerPatterns[0].active()).toBeTrue(); }); @@ -302,16 +300,16 @@ describe('Accordion Pattern', () => { }); it('stays on the first trigger with left key from first trigger.', () => { - groupInputs.activeItem.set(groupInputs.items()[0]); + groupInputs.activeItem.set(triggerPatterns[0]); expect(triggerPatterns[0].active()).toBeTrue(); - triggerPatterns[0].onKeydown(left()); + groupPattern.onKeydown(left()); expect(triggerPatterns[0].active()).toBeTrue(); }); it('stays on the last trigger with right key from last trigger.', () => { - groupInputs.activeItem.set(groupInputs.items()[2]); + groupInputs.activeItem.set(triggerPatterns[2]); expect(triggerPatterns[2].active()).toBeTrue(); - triggerPatterns[2].onKeydown(right()); + groupPattern.onKeydown(right()); expect(triggerPatterns[2].active()).toBeTrue(); }); }); @@ -323,21 +321,21 @@ describe('Accordion Pattern', () => { }); it('expands a panel and collapses others with space key.', () => { - groupInputs.expandedIds.set(['panel-2']); + triggerPatterns[1].expanded.set(true); expect(panelPatterns[0].hidden()).toBeTrue(); expect(panelPatterns[1].hidden()).toBeFalse(); - triggerPatterns[0].onKeydown(space()); + groupPattern.onKeydown(space()); expect(panelPatterns[0].hidden()).toBeFalse(); expect(panelPatterns[1].hidden()).toBeTrue(); }); it('expands a panel and collapses others with enter key.', () => { - groupInputs.expandedIds.set(['panel-2']); + triggerPatterns[1].expanded.set(true); expect(panelPatterns[0].hidden()).toBeTrue(); expect(panelPatterns[1].hidden()).toBeFalse(); - triggerPatterns[0].onKeydown(space()); + groupPattern.onKeydown(space()); expect(panelPatterns[0].hidden()).toBeFalse(); expect(panelPatterns[1].hidden()).toBeTrue(); }); @@ -349,21 +347,22 @@ describe('Accordion Pattern', () => { }); it('expands a panel without affecting other panels.', () => { - groupInputs.expandedIds.set(['panel-2']); + triggerPatterns[1].expanded.set(true); expect(panelPatterns[0].hidden()).toBeTrue(); expect(panelPatterns[1].hidden()).toBeFalse(); - triggerPatterns[0].onKeydown(space()); + groupPattern.onKeydown(space()); expect(panelPatterns[0].hidden()).toBeFalse(); expect(panelPatterns[1].hidden()).toBeFalse(); }); it('collapses a panel without affecting other panels.', () => { - groupInputs.expandedIds.set(['panel-1', 'panel-2']); + triggerPatterns[0].expanded.set(true); + triggerPatterns[1].expanded.set(true); expect(panelPatterns[0].hidden()).toBeFalse(); expect(panelPatterns[1].hidden()).toBeFalse(); - triggerPatterns[0].onKeydown(enter()); + groupPattern.onKeydown(enter()); expect(panelPatterns[0].hidden()).toBeTrue(); expect(panelPatterns[1].hidden()).toBeFalse(); }); diff --git a/src/aria/private/accordion/accordion.ts b/src/aria/private/accordion/accordion.ts new file mode 100644 index 000000000000..16cba8c90b5e --- /dev/null +++ b/src/aria/private/accordion/accordion.ts @@ -0,0 +1,222 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {KeyboardEventManager, PointerEventManager} from '../behaviors/event-manager'; +import {ExpansionItem, ListExpansion, ListExpansionInputs} from '../behaviors/expansion/expansion'; +import {ListFocus, ListFocusInputs, ListFocusItem} from '../behaviors/list-focus/list-focus'; +import { + ListNavigation, + ListNavigationInputs, + ListNavigationItem, +} from '../behaviors/list-navigation/list-navigation'; +import {computed, SignalLike, WritableSignalLike} from '../behaviors/signal-like/signal-like'; + +/** Inputs of the AccordionGroupPattern. */ +export interface AccordionGroupInputs extends Omit< + ListNavigationInputs & + ListFocusInputs & + Omit, + 'focusMode' +> { + /** A function that returns the trigger associated with a given element. */ + getItem: (e: Element | null | undefined) => AccordionTriggerPattern | undefined; +} + +const focusMode = () => 'roving' as const; + +/** A pattern controls the nested Accordions. */ +export class AccordionGroupPattern { + /** Controls navigation for the group. */ + readonly navigationBehavior: ListNavigation; + + /** Controls focus for the group. */ + readonly focusBehavior: ListFocus; + + /** Controls expansion for the group. */ + readonly expansionBehavior: ListExpansion; + + constructor(readonly inputs: AccordionGroupInputs) { + this.focusBehavior = new ListFocus({ + ...inputs, + focusMode, + }); + this.navigationBehavior = new ListNavigation({ + ...inputs, + focusMode, + focusManager: this.focusBehavior, + }); + this.expansionBehavior = new ListExpansion({ + ...inputs, + }); + } + + /** The key used to navigate to the previous accordion trigger. */ + prevKey = computed(() => { + if (this.inputs.orientation() === 'vertical') { + return 'ArrowUp'; + } + return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; + }); + + /** The key used to navigate to the next accordion trigger. */ + nextKey = computed(() => { + if (this.inputs.orientation() === 'vertical') { + return 'ArrowDown'; + } + return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; + }); + + /** The keydown event manager for the accordion trigger. */ + keydown = computed(() => { + return new KeyboardEventManager() + .on(this.prevKey, () => this.navigationBehavior.prev()) + .on(this.nextKey, () => this.navigationBehavior.next()) + .on('Home', () => this.navigationBehavior.first()) + .on('End', () => this.navigationBehavior.last()) + .on(' ', () => this.toggle()) + .on('Enter', () => this.toggle()); + }); + + /** The pointerdown event manager for the accordion trigger. */ + pointerdown = computed(() => { + return new PointerEventManager().on(e => { + const item = this.inputs.getItem(e.target as Element); + if (!item) return; + + this.navigationBehavior.goto(item); + this.expansionBehavior.toggle(item); + }); + }); + + /** Handles keydown events on the trigger, delegating to the group if not disabled. */ + onKeydown(event: KeyboardEvent): void { + this.keydown().handle(event); + } + + /** Handles pointerdown events on the trigger, delegating to the group if not disabled. */ + onPointerdown(event: PointerEvent): void { + this.pointerdown().handle(event); + } + + /** Handles focus events on the trigger. This ensures the tabbing changes the active index. */ + onFocus(event: FocusEvent): void { + const item = this.inputs.getItem(event.target as Element); + if (!item) return; + if (!this.focusBehavior.isFocusable(item)) return; + + this.focusBehavior.focus(item); + } + + /** Toggles the expansion state of the active accordion item. */ + toggle() { + const activeItem = this.inputs.activeItem(); + if (activeItem === undefined) return; + this.expansionBehavior.toggle(activeItem); + } +} + +/** Inputs for the AccordionTriggerPattern. */ +export interface AccordionTriggerInputs + extends Omit, Omit { + /** A local unique identifier for the trigger's corresponding panel. */ + panelId: SignalLike; + + /** The parent accordion group that controls this trigger. */ + accordionGroup: SignalLike; + + /** The accordion panel controlled by this trigger. */ + accordionPanel: SignalLike; +} + +/** A pattern controls the expansion state of an accordion. */ +export class AccordionTriggerPattern implements ListNavigationItem, ListFocusItem, ExpansionItem { + /** A unique identifier for this trigger. */ + readonly id: SignalLike = () => this.inputs.id(); + + /** A reference to the trigger element. */ + readonly element: SignalLike = () => this.inputs.element()!; + + /** Whether this trigger has expandable panel. */ + readonly expandable: SignalLike = () => true; + + /** Whether the corresponding panel is expanded. */ + readonly expanded: WritableSignalLike; + + /** Whether the trigger is active. */ + readonly active = computed(() => this.inputs.accordionGroup().inputs.activeItem() === this); + + /** Id of the accordion panel controlled by the trigger. */ + readonly controls = computed(() => this.inputs.accordionPanel()?.inputs.id()); + + /** The tabindex of the trigger. */ + readonly tabIndex = computed(() => + this.inputs.accordionGroup().focusBehavior.isFocusable(this) ? 0 : -1, + ); + + /** Whether the trigger is disabled. Disabling an accordion group disables all the triggers. */ + readonly disabled = computed( + () => this.inputs.disabled() || this.inputs.accordionGroup().inputs.disabled(), + ); + + /** Whether the trigger is hard disabled. */ + readonly hardDisabled = computed( + () => this.disabled() && !this.inputs.accordionGroup().inputs.softDisabled(), + ); + + /** The index of the trigger within its accordion group. */ + readonly index = computed(() => this.inputs.accordionGroup().inputs.items().indexOf(this)); + + constructor(readonly inputs: AccordionTriggerInputs) { + this.expanded = inputs.expanded; + } + + /** Opens the accordion panel. */ + open(): void { + this.inputs.accordionGroup().expansionBehavior.open(this); + } + + /** Closes the accordion panel. */ + close(): void { + this.inputs.accordionGroup().expansionBehavior.close(this); + } + + /** Toggles the accordion panel. */ + toggle(): void { + this.inputs.accordionGroup().expansionBehavior.toggle(this); + } +} + +/** Represents the required inputs for the AccordionPanelPattern. */ +export interface AccordionPanelInputs { + /** A global unique identifier for the panel. */ + id: SignalLike; + + /** A local unique identifier for the panel, matching its trigger's panelId. */ + panelId: SignalLike; + + /** The parent accordion trigger that controls this panel. */ + accordionTrigger: SignalLike; +} + +/** Represents an accordion panel. */ +export class AccordionPanelPattern { + /** A global unique identifier for the panel. */ + id: SignalLike; + + /** The parent accordion trigger that controls this panel. */ + accordionTrigger: SignalLike; + + /** Whether the accordion panel is hidden. True if the associated trigger is not expanded. */ + hidden: SignalLike; + + constructor(readonly inputs: AccordionPanelInputs) { + this.id = inputs.id; + this.accordionTrigger = inputs.accordionTrigger; + this.hidden = computed(() => inputs.accordionTrigger()?.expanded() === false); + } +} diff --git a/src/aria/ui-patterns/behaviors/event-manager/BUILD.bazel b/src/aria/private/behaviors/event-manager/BUILD.bazel similarity index 81% rename from src/aria/ui-patterns/behaviors/event-manager/BUILD.bazel rename to src/aria/private/behaviors/event-manager/BUILD.bazel index 623be008f858..a744602f4526 100644 --- a/src/aria/ui-patterns/behaviors/event-manager/BUILD.bazel +++ b/src/aria/private/behaviors/event-manager/BUILD.bazel @@ -9,6 +9,6 @@ ts_project( exclude = ["**/*.spec.ts"], ), deps = [ - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/ui-patterns/behaviors/event-manager/event-manager.ts b/src/aria/private/behaviors/event-manager/event-manager.ts similarity index 100% rename from src/aria/ui-patterns/behaviors/event-manager/event-manager.ts rename to src/aria/private/behaviors/event-manager/event-manager.ts diff --git a/src/aria/ui-patterns/behaviors/event-manager/index.ts b/src/aria/private/behaviors/event-manager/index.ts similarity index 100% rename from src/aria/ui-patterns/behaviors/event-manager/index.ts rename to src/aria/private/behaviors/event-manager/index.ts diff --git a/src/aria/ui-patterns/behaviors/event-manager/keyboard-event-manager.ts b/src/aria/private/behaviors/event-manager/keyboard-event-manager.ts similarity index 73% rename from src/aria/ui-patterns/behaviors/event-manager/keyboard-event-manager.ts rename to src/aria/private/behaviors/event-manager/keyboard-event-manager.ts index 86cf3329ade5..a088f744dda3 100644 --- a/src/aria/ui-patterns/behaviors/event-manager/keyboard-event-manager.ts +++ b/src/aria/private/behaviors/event-manager/keyboard-event-manager.ts @@ -35,32 +35,41 @@ export class KeyboardEventManager extends EventManager< }; /** Configures this event manager to handle events with a specific key and no modifiers. */ - on(key: KeyCode, handler: EventHandler): this; + on(key: KeyCode, handler: EventHandler, options?: Partial): this; /** Configures this event manager to handle events with a specific modifer and key combination. */ - on(modifiers: ModifierInputs, key: KeyCode, handler: EventHandler): this; + on( + modifiers: ModifierInputs, + key: KeyCode, + handler: EventHandler, + options?: Partial, + ): this; on(...args: any[]) { - const {modifiers, key, handler} = this._normalizeInputs(...args); + const {modifiers, key, handler, options} = this._normalizeInputs(...args); this.configs.push({ handler: handler, matcher: event => this._isMatch(event, key, modifiers), ...this.options, + ...options, }); return this; } private _normalizeInputs(...args: any[]) { - const key = args.length === 3 ? args[1] : args[0]; - const handler = args.length === 3 ? args[2] : args[1]; - const modifiers = args.length === 3 ? args[0] : Modifier.None; + const withModifiers = Array.isArray(args[0]) || args[0] in Modifier; + const modifiers = withModifiers ? args[0] : Modifier.None; + const key = withModifiers ? args[1] : args[0]; + const handler = withModifiers ? args[2] : args[1]; + const options = withModifiers ? args[3] : args[2]; return { key: key as KeyCode, handler: handler as EventHandler, modifiers: modifiers as ModifierInputs, + options: (options ?? {}) as Partial, }; } diff --git a/src/aria/ui-patterns/behaviors/event-manager/pointer-event-manager.ts b/src/aria/private/behaviors/event-manager/pointer-event-manager.ts similarity index 100% rename from src/aria/ui-patterns/behaviors/event-manager/pointer-event-manager.ts rename to src/aria/private/behaviors/event-manager/pointer-event-manager.ts diff --git a/src/aria/ui-patterns/behaviors/expansion/BUILD.bazel b/src/aria/private/behaviors/expansion/BUILD.bazel similarity index 71% rename from src/aria/ui-patterns/behaviors/expansion/BUILD.bazel rename to src/aria/private/behaviors/expansion/BUILD.bazel index db36a1efad80..afcc7ac6be94 100644 --- a/src/aria/ui-patterns/behaviors/expansion/BUILD.bazel +++ b/src/aria/private/behaviors/expansion/BUILD.bazel @@ -9,8 +9,8 @@ ts_project( ], deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/list-focus", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/list-focus", + "//src/aria/private/behaviors/signal-like", ], ) @@ -23,7 +23,8 @@ ng_project( deps = [ ":expansion", "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/list-focus:unit_test_sources", + "//src/aria/private/behaviors/list-focus:unit_test_sources", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/ui-patterns/behaviors/expansion/expansion.spec.ts b/src/aria/private/behaviors/expansion/expansion.spec.ts similarity index 76% rename from src/aria/ui-patterns/behaviors/expansion/expansion.spec.ts rename to src/aria/private/behaviors/expansion/expansion.spec.ts index f1029267fcbe..ffe18762e2bb 100644 --- a/src/aria/ui-patterns/behaviors/expansion/expansion.spec.ts +++ b/src/aria/private/behaviors/expansion/expansion.spec.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.dev/license */ -import {WritableSignal, signal} from '@angular/core'; +import {WritableSignalLike, signal} from '../signal-like/signal-like'; import {ListExpansion, ListExpansionInputs, ExpansionItem} from './expansion'; type TestItem = ExpansionItem & { - id: WritableSignal; - disabled: WritableSignal; - expandable: WritableSignal; - expansionId: WritableSignal; + id: WritableSignalLike; + disabled: WritableSignalLike; + expanded: WritableSignalLike; + expandable: WritableSignalLike; }; type TestInputs = Partial> & { @@ -22,15 +22,15 @@ type TestInputs = Partial> & { expansionDisabled?: boolean; }; -function createItems(length: number): WritableSignal { +function createItems(length: number): WritableSignalLike { return signal( Array.from({length}).map((_, i) => { const itemId = `item-${i}`; return { id: signal(itemId), disabled: signal(false), + expanded: signal(false), expandable: signal(true), - expansionId: signal(itemId), }; }), ); @@ -43,20 +43,25 @@ function getExpansion(inputs: TestInputs = {}): { const numItems = inputs.numItems ?? 3; const items = createItems(numItems); + for (const id of inputs.initialExpandedIds ?? []) { + items() + .find(i => i.id() === id) + ?.expanded.set(true); + } + const expansion = new ListExpansion({ items: items, disabled: signal(inputs.expansionDisabled ?? false), multiExpandable: signal(inputs.multiExpandable?.() ?? false), - expandedIds: signal([]), }); - if (inputs.initialExpandedIds) { - expansion.expandedIds.set(inputs.initialExpandedIds); - } - return {expansion, items: items()}; } +function getExpandedIds(items: TestItem[]): string[] { + return items.filter(i => i.expanded()).map(i => i.id()); +} + describe('Expansion', () => { describe('#open', () => { it('should open only one item at a time when multiExpandable is false', () => { @@ -65,10 +70,10 @@ describe('Expansion', () => { }); expansion.open(items[0]); - expect(expansion.expandedIds()).toEqual(['item-0']); + expect(getExpandedIds(items)).toEqual(['item-0']); expansion.open(items[1]); - expect(expansion.expandedIds()).toEqual(['item-1']); + expect(getExpandedIds(items)).toEqual(['item-1']); }); it('should open multiple items when multiExpandable is true', () => { @@ -77,24 +82,24 @@ describe('Expansion', () => { }); expansion.open(items[0]); - expect(expansion.expandedIds()).toEqual(['item-0']); + expect(getExpandedIds(items)).toEqual(['item-0']); expansion.open(items[1]); - expect(expansion.expandedIds()).toEqual(['item-0', 'item-1']); + expect(getExpandedIds(items)).toEqual(['item-0', 'item-1']); }); it('should not open an item if it is not expandable (expandable is false)', () => { const {expansion, items} = getExpansion(); items[1].expandable.set(false); expansion.open(items[1]); - expect(expansion.expandedIds()).toEqual([]); + expect(getExpandedIds(items)).toEqual([]); }); it('should not open an item if it is disabled', () => { const {expansion, items} = getExpansion(); items[1].disabled.set(true); expansion.open(items[1]); - expect(expansion.expandedIds()).toEqual([]); + expect(getExpandedIds(items)).toEqual([]); }); }); @@ -102,21 +107,21 @@ describe('Expansion', () => { it('should close the specified item', () => { const {expansion, items} = getExpansion({initialExpandedIds: ['item-0', 'item-1']}); expansion.close(items[0]); - expect(expansion.expandedIds()).toEqual(['item-1']); + expect(getExpandedIds(items)).toEqual(['item-1']); }); it('should not close an item if it is not expandable', () => { const {expansion, items} = getExpansion({initialExpandedIds: ['item-0']}); items[0].expandable.set(false); expansion.close(items[0]); - expect(expansion.expandedIds()).toEqual(['item-0']); + expect(getExpandedIds(items)).toEqual(['item-0']); }); it('should not close an item if it is disabled', () => { const {expansion, items} = getExpansion({initialExpandedIds: ['item-0']}); items[0].disabled.set(true); expansion.close(items[0]); - expect(expansion.expandedIds()).toEqual(['item-0']); + expect(getExpandedIds(items)).toEqual(['item-0']); }); }); @@ -124,7 +129,7 @@ describe('Expansion', () => { it('should open a closed item', () => { const {expansion, items} = getExpansion(); expansion.toggle(items[0]); - expect(expansion.expandedIds()).toEqual(['item-0']); + expect(getExpandedIds(items)).toEqual(['item-0']); }); it('should close an opened item', () => { @@ -132,18 +137,18 @@ describe('Expansion', () => { initialExpandedIds: ['item-0'], }); expansion.toggle(items[0]); - expect(expansion.expandedIds()).toEqual([]); + expect(getExpandedIds(items)).toEqual([]); }); }); describe('#openAll', () => { it('should open all focusable and expandable items when multiExpandable is true', () => { - const {expansion} = getExpansion({ + const {expansion, items} = getExpansion({ numItems: 3, multiExpandable: signal(true), }); expansion.openAll(); - expect(expansion.expandedIds()).toEqual(['item-0', 'item-1', 'item-2']); + expect(getExpandedIds(items)).toEqual(['item-0', 'item-1', 'item-2']); }); it('should not expand items that are not expandable', () => { @@ -153,7 +158,7 @@ describe('Expansion', () => { }); items[1].expandable.set(false); expansion.openAll(); - expect(expansion.expandedIds()).toEqual(['item-0', 'item-2']); + expect(getExpandedIds(items)).toEqual(['item-0', 'item-2']); }); it('should not expand items that are disabled', () => { @@ -163,16 +168,16 @@ describe('Expansion', () => { }); items[1].disabled.set(true); expansion.openAll(); - expect(expansion.expandedIds()).toEqual(['item-0', 'item-2']); + expect(getExpandedIds(items)).toEqual(['item-0', 'item-2']); }); it('should do nothing when multiExpandable is false', () => { - const {expansion} = getExpansion({ + const {expansion, items} = getExpansion({ numItems: 3, multiExpandable: signal(false), }); expansion.openAll(); - expect(expansion.expandedIds()).toEqual([]); + expect(getExpandedIds(items)).toEqual([]); }); }); @@ -184,7 +189,7 @@ describe('Expansion', () => { }); items[1].expandable.set(false); expansion.closeAll(); - expect(expansion.expandedIds()).toEqual([]); + expect(getExpandedIds(items)).toEqual([]); }); it('should not close items that are not expandable', () => { @@ -194,7 +199,7 @@ describe('Expansion', () => { }); items[1].expandable.set(false); expansion.closeAll(); - expect(expansion.expandedIds()).toEqual(['item-1']); + expect(getExpandedIds(items)).toEqual(['item-1']); }); it('should not close items that are disabled', () => { @@ -204,7 +209,7 @@ describe('Expansion', () => { }); items[1].disabled.set(true); expansion.closeAll(); - expect(expansion.expandedIds()).toEqual(['item-1']); + expect(getExpandedIds(items)).toEqual(['item-1']); }); }); @@ -236,13 +241,13 @@ describe('Expansion', () => { describe('#isExpanded', () => { it('should return true if item ID is in expandedIds', () => { - const {expansion, items} = getExpansion({initialExpandedIds: ['item-0']}); - expect(expansion.isExpanded(items[0])).toBeTrue(); + const {items} = getExpansion({initialExpandedIds: ['item-0']}); + expect(items[0].expanded()).toBeTrue(); }); it('should return false if item ID is not in expandedIds', () => { - const {expansion, items} = getExpansion(); - expect(expansion.isExpanded(items[0])).toBeFalse(); + const {items} = getExpansion(); + expect(items[0].expanded()).toBeFalse(); }); }); }); diff --git a/src/aria/private/behaviors/expansion/expansion.ts b/src/aria/private/behaviors/expansion/expansion.ts new file mode 100644 index 000000000000..9a9caebd61e0 --- /dev/null +++ b/src/aria/private/behaviors/expansion/expansion.ts @@ -0,0 +1,82 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ +import {SignalLike, WritableSignalLike} from '../signal-like/signal-like'; + +/** Represents an item that can be expanded or collapsed. */ +export interface ExpansionItem { + /** Whether the item is expandable. */ + expandable: SignalLike; + + /** Whether the item is expanded. */ + expanded: WritableSignalLike; + + /** Whether the expansion is disabled. */ + disabled: SignalLike; +} + +/** Represents the required inputs for an expansion behavior. */ +export interface ListExpansionInputs { + /** Whether multiple items can be expanded at once. */ + multiExpandable: SignalLike; + + /** An array of expansion items. */ + items: SignalLike; + + /** Whether all expansions are disabled. */ + disabled: SignalLike; +} + +/** Manages the expansion state of a list of items. */ +export class ListExpansion { + constructor(readonly inputs: ListExpansionInputs) {} + + /** Opens the specified item. */ + open(item: ExpansionItem): boolean { + if (!this.isExpandable(item)) return false; + if (item.expanded()) return false; + if (!this.inputs.multiExpandable()) { + this.closeAll(); + } + item.expanded.set(true); + return true; + } + + /** Closes the specified item. */ + close(item: ExpansionItem): boolean { + if (!this.isExpandable(item)) return false; + + item.expanded.set(false); + return true; + } + + /** Toggles the expansion state of the specified item. */ + toggle(item: ExpansionItem): boolean { + return item.expanded() ? this.close(item) : this.open(item); + } + + /** Opens all focusable items in the list. */ + openAll(): void { + if (this.inputs.multiExpandable()) { + for (const item of this.inputs.items()) { + this.open(item); + } + } + } + + /** Closes all focusable items in the list. */ + closeAll(): void { + for (const item of this.inputs.items()) { + this.close(item); + } + } + + /** Checks whether the specified item is expandable / collapsible. */ + isExpandable(item: ExpansionItem) { + return !this.inputs.disabled() && !item.disabled() && item.expandable(); + } +} diff --git a/src/aria/ui-patterns/behaviors/grid-focus/BUILD.bazel b/src/aria/private/behaviors/grid-focus/BUILD.bazel similarity index 83% rename from src/aria/ui-patterns/behaviors/grid-focus/BUILD.bazel rename to src/aria/private/behaviors/grid-focus/BUILD.bazel index 966ffc20f9df..eb4f60a59a92 100644 --- a/src/aria/ui-patterns/behaviors/grid-focus/BUILD.bazel +++ b/src/aria/private/behaviors/grid-focus/BUILD.bazel @@ -7,7 +7,7 @@ ts_project( srcs = ["grid-focus.ts"], deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/signal-like", ], ) @@ -18,6 +18,7 @@ ng_project( deps = [ ":grid-focus", "//:node_modules/@angular/core", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/ui-patterns/behaviors/grid-focus/grid-focus.spec.ts b/src/aria/private/behaviors/grid-focus/grid-focus.spec.ts similarity index 89% rename from src/aria/ui-patterns/behaviors/grid-focus/grid-focus.spec.ts rename to src/aria/private/behaviors/grid-focus/grid-focus.spec.ts index 70f661556a21..3fc7c3141b88 100644 --- a/src/aria/ui-patterns/behaviors/grid-focus/grid-focus.spec.ts +++ b/src/aria/private/behaviors/grid-focus/grid-focus.spec.ts @@ -6,30 +6,30 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed, Signal, signal, WritableSignal} from '@angular/core'; +import {computed, SignalLike, signal, WritableSignalLike} from '../signal-like/signal-like'; import {GridFocus, GridFocusInputs, GridFocusCell, RowCol} from './grid-focus'; // Helper type for test cells, extending GridFocusCell interface TestGridCell extends GridFocusCell { - id: WritableSignal; - element: WritableSignal; - disabled: WritableSignal; + id: WritableSignalLike; + element: WritableSignalLike; + disabled: WritableSignalLike; } // Helper type for configuring GridFocus inputs in tests type TestSetupInputs = Partial> & { numRows?: number; numCols?: number; - gridFocus?: WritableSignal | undefined>; + gridFocus?: WritableSignalLike | undefined>; }; export function createTestCell( - gridFocus: Signal | undefined>, + gridFocus: SignalLike | undefined>, opts: {id: string; rowspan?: number; colspan?: number}, ): TestGridCell { const el = document.createElement('div'); spyOn(el, 'focus').and.callThrough(); - let coordinates: Signal = signal({row: -1, col: -1}); + let coordinates: SignalLike = signal({row: -1, col: -1}); const cell: TestGridCell = { id: signal(opts.id), element: signal(el as HTMLElement), @@ -46,10 +46,10 @@ export function createTestCell( } export function createTestCells( - gridFocus: Signal | undefined>, + gridFocus: SignalLike | undefined>, numRows: number, numCols: number, -): WritableSignal { +): WritableSignalLike { return signal( Array.from({length: numRows}).map((_, r) => Array.from({length: numCols}).map((_, c) => { @@ -75,7 +75,7 @@ export function setupGridFocus(inputs: TestSetupInputs = {}): { inputs.focusMode ? inputs.focusMode() : 'roving', ); const disabled = signal(inputs.disabled ? inputs.disabled() : false); - const skipDisabled = signal(inputs.skipDisabled ? inputs.skipDisabled() : true); + const softDisabled = signal(inputs.softDisabled ? inputs.softDisabled() : false); gridFocus.set( new GridFocus({ @@ -83,7 +83,7 @@ export function setupGridFocus(inputs: TestSetupInputs = {}): { activeCoords: activeCoords, focusMode: focusMode, disabled: disabled, - skipDisabled: skipDisabled, + softDisabled: softDisabled, }), ); @@ -231,17 +231,17 @@ describe('GridFocus', () => { describe('getGridTabindex', () => { it('should return 0 if grid is disabled', () => { const {gridFocus} = setupGridFocus({disabled: signal(true)}); - expect(gridFocus.getGridTabindex()).toBe(0); + expect(gridFocus.getGridTabIndex()).toBe(0); }); it('should return -1 if focusMode is "roving" and grid is not disabled', () => { const {gridFocus} = setupGridFocus({focusMode: signal('roving')}); - expect(gridFocus.getGridTabindex()).toBe(-1); + expect(gridFocus.getGridTabIndex()).toBe(-1); }); it('should return 0 if focusMode is "activedescendant" and grid is not disabled', () => { const {gridFocus} = setupGridFocus({focusMode: signal('activedescendant')}); - expect(gridFocus.getGridTabindex()).toBe(0); + expect(gridFocus.getGridTabIndex()).toBe(0); }); }); @@ -252,9 +252,9 @@ describe('GridFocus', () => { numCols: 3, disabled: signal(true), }); - expect(gridFocus.getCellTabindex(cells[0][0])).toBe(-1); - expect(gridFocus.getCellTabindex(cells[0][1])).toBe(-1); - expect(gridFocus.getCellTabindex(cells[0][2])).toBe(-1); + expect(gridFocus.getCellTabIndex(cells[0][0])).toBe(-1); + expect(gridFocus.getCellTabIndex(cells[0][1])).toBe(-1); + expect(gridFocus.getCellTabIndex(cells[0][2])).toBe(-1); }); it('should return -1 if focusMode is "activedescendant"', () => { @@ -263,9 +263,9 @@ describe('GridFocus', () => { numCols: 3, focusMode: signal('activedescendant'), }); - expect(gridFocus.getCellTabindex(cells[0][0])).toBe(-1); - expect(gridFocus.getCellTabindex(cells[0][1])).toBe(-1); - expect(gridFocus.getCellTabindex(cells[0][2])).toBe(-1); + expect(gridFocus.getCellTabIndex(cells[0][0])).toBe(-1); + expect(gridFocus.getCellTabIndex(cells[0][1])).toBe(-1); + expect(gridFocus.getCellTabIndex(cells[0][2])).toBe(-1); }); it('should return 0 if focusMode is "roving" and cell is the activeCell', () => { @@ -275,9 +275,9 @@ describe('GridFocus', () => { focusMode: signal('roving'), }); - expect(gridFocus.getCellTabindex(cells[0][0])).toBe(0); - expect(gridFocus.getCellTabindex(cells[0][1])).toBe(-1); - expect(gridFocus.getCellTabindex(cells[0][2])).toBe(-1); + expect(gridFocus.getCellTabIndex(cells[0][0])).toBe(0); + expect(gridFocus.getCellTabIndex(cells[0][1])).toBe(-1); + expect(gridFocus.getCellTabIndex(cells[0][2])).toBe(-1); }); }); @@ -292,11 +292,11 @@ describe('GridFocus', () => { expect(gridFocus.isFocusable(cells[0][2])).toBeTrue(); }); - it('should return false if cell is disabled and skipDisabled is true', () => { + it('should return false if cell is disabled and softDisabled is false', () => { const {gridFocus, cells} = setupGridFocus({ numRows: 1, numCols: 3, - skipDisabled: signal(true), + softDisabled: signal(false), }); cells[0][1].disabled.set(true); expect(gridFocus.isFocusable(cells[0][0])).toBeTrue(); @@ -304,11 +304,11 @@ describe('GridFocus', () => { expect(gridFocus.isFocusable(cells[0][2])).toBeTrue(); }); - it('should return true if cell is disabled but skipDisabled is false', () => { + it('should return true if cell is disabled but softDisabled is true', () => { const {gridFocus, cells} = setupGridFocus({ numRows: 1, numCols: 3, - skipDisabled: signal(false), + softDisabled: signal(true), }); cells[0][1].disabled.set(true); expect(gridFocus.isFocusable(cells[0][0])).toBeTrue(); diff --git a/src/aria/ui-patterns/behaviors/grid-focus/grid-focus.ts b/src/aria/private/behaviors/grid-focus/grid-focus.ts similarity index 94% rename from src/aria/ui-patterns/behaviors/grid-focus/grid-focus.ts rename to src/aria/private/behaviors/grid-focus/grid-focus.ts index bacb2b5d9daa..508026eb9726 100644 --- a/src/aria/ui-patterns/behaviors/grid-focus/grid-focus.ts +++ b/src/aria/private/behaviors/grid-focus/grid-focus.ts @@ -47,8 +47,8 @@ export interface GridFocusInputs { /** The coordinates (row and column) of the current active cell. */ activeCoords: WritableSignalLike; - /** Whether disabled cells in the grid should be skipped when navigating. */ - skipDisabled: SignalLike; + /** Whether disabled cells in the grid should be focusable. */ + softDisabled: SignalLike; } /** Represents coordinates in a grid. */ @@ -96,16 +96,16 @@ export class GridFocus { return gridCells.length === 0 || gridCells.every(row => row.every(cell => cell.disabled())); } - /** The tabindex for the grid container. */ - getGridTabindex(): -1 | 0 { + /** The tab index for the grid container. */ + getGridTabIndex(): -1 | 0 { if (this.isGridDisabled()) { return 0; } return this.inputs.focusMode() === 'activedescendant' ? 0 : -1; } - /** Returns the tabindex for the given grid cell cell. */ - getCellTabindex(cell: T): -1 | 0 { + /** Returns the tab index for the given grid cell cell. */ + getCellTabIndex(cell: T): -1 | 0 { if (this.isGridDisabled()) { return -1; } @@ -163,7 +163,7 @@ export class GridFocus { /** Returns true if the given cell can be navigated to. */ isFocusable(cell: T): boolean { - return !cell.disabled() || !this.inputs.skipDisabled(); + return !cell.disabled() || this.inputs.softDisabled(); } /** Finds the top-left anchor coordinates of a given cell instance in the grid. */ diff --git a/src/aria/ui-patterns/behaviors/grid-navigation/BUILD.bazel b/src/aria/private/behaviors/grid-navigation/BUILD.bazel similarity index 72% rename from src/aria/ui-patterns/behaviors/grid-navigation/BUILD.bazel rename to src/aria/private/behaviors/grid-navigation/BUILD.bazel index cc87a01c3228..eb67f76f4e6d 100644 --- a/src/aria/ui-patterns/behaviors/grid-navigation/BUILD.bazel +++ b/src/aria/private/behaviors/grid-navigation/BUILD.bazel @@ -7,8 +7,8 @@ ts_project( srcs = ["grid-navigation.ts"], deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/grid-focus", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/grid-focus", + "//src/aria/private/behaviors/signal-like", ], ) @@ -19,7 +19,8 @@ ng_project( deps = [ ":grid-navigation", "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/grid-focus", + "//src/aria/private/behaviors/grid-focus", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/ui-patterns/behaviors/grid-navigation/grid-navigation.spec.ts b/src/aria/private/behaviors/grid-navigation/grid-navigation.spec.ts similarity index 93% rename from src/aria/ui-patterns/behaviors/grid-navigation/grid-navigation.spec.ts rename to src/aria/private/behaviors/grid-navigation/grid-navigation.spec.ts index 6d48f217d17f..ddbd297fca6c 100644 --- a/src/aria/ui-patterns/behaviors/grid-navigation/grid-navigation.spec.ts +++ b/src/aria/private/behaviors/grid-navigation/grid-navigation.spec.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed, signal, WritableSignal} from '@angular/core'; +import {computed, signal, WritableSignalLike} from '../../behaviors/signal-like/signal-like'; import {GridFocus} from '../grid-focus/grid-focus'; import {GridNavigation, GridNavigationCell, GridNavigationInputs} from './grid-navigation'; type TestGridNav = GridNavigation; interface TestCell extends GridNavigationCell { - disabled: WritableSignal; + disabled: WritableSignalLike; } interface TestCellInputs { @@ -42,7 +42,7 @@ type TestGridNavInputs = Partial> & function createGridNav(config: TestGridNavInputs): {gridNav: TestGridNav; cells: TestCell[][]} { const wrap = signal(true); const disabled = signal(false); - const skipDisabled = signal(false); + const softDisabled = signal(true); const focusMode = signal('roving' as const); const activeCoords = signal({row: 0, col: 0}); const wrapBehavior = signal('continuous' as const); @@ -51,7 +51,7 @@ function createGridNav(config: TestGridNavInputs): {gridNav: TestGridNav; cells: disabled, focusMode, activeCoords, - skipDisabled, + softDisabled, ...config, }); @@ -60,7 +60,7 @@ function createGridNav(config: TestGridNavInputs): {gridNav: TestGridNav; cells: disabled, focusMode, activeCoords, - skipDisabled, + softDisabled, wrapBehavior, gridFocus, ...config, @@ -179,10 +179,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 0, col: 1}); }); - it('(skip disabled: false) should be able to navigate through disabled cells', () => { + it('(soft disabled: true) should be able to navigate through disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, - skipDisabled: signal(false), + softDisabled: signal(true), activeCoords: signal({row: 1, col: 1}), }); cells[0][1].disabled.set(true); @@ -190,10 +190,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 0, col: 1}); }); - it('(skip disabled: true) should skip disabled cells', () => { + it('(soft disabled: false) should skip disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 2, col: 1}), }); cells[1][1].disabled.set(true); @@ -201,11 +201,11 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 0, col: 1}); }); - it('(wrap: false) (skip disabled: true) should not navigate through disabled cells', () => { + it('(wrap: false) (soft disabled: false) should not navigate through disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(false), - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 1, col: 1}), }); cells[0][1].disabled.set(true); @@ -241,7 +241,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('loop'), activeCoords: signal({row: 0, col: 1}), }); @@ -254,7 +254,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('loop'), activeCoords: signal({row: 0, col: 1}), }); @@ -293,7 +293,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('continuous'), activeCoords: signal({row: 0, col: 1}), }); @@ -316,7 +316,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('continuous'), activeCoords: signal({row: 0, col: 1}), }); @@ -340,7 +340,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('continuous'), activeCoords: signal({row: 1, col: 1}), }); @@ -396,10 +396,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 1, col: 0}); }); - it('(skip disabled: true) should skip disabled cells', () => { + it('(soft disabled: false) should skip disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridB, - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 2, col: 2}), }); cells[0][2].disabled.set(true); @@ -458,10 +458,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 2, col: 3}); }); - it('(skip disabled: true) should skip disabled cells', () => { + it('(soft disabled: false) should skip disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridC, - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 1, col: 2}), }); cells[0][0].disabled.set(true); @@ -513,10 +513,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 3, col: 3}); }); - it('(skip disabled: true) should skip disabled cells', () => { + it('(soft disabled: false) should skip disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridD, - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 3, col: 3}), }); @@ -558,10 +558,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 2, col: 1}); }); - it('(skip disabled: false) should be able to navigate through disabled cells', () => { + it('(soft disabled: true) should be able to navigate through disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, - skipDisabled: signal(false), + softDisabled: signal(true), activeCoords: signal({row: 1, col: 1}), }); cells[2][1].disabled.set(true); @@ -569,10 +569,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 2, col: 1}); }); - it('(skip disabled: true) should skip disabled cells', () => { + it('(soft disabled: false) should skip disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 0, col: 1}), }); cells[1][1].disabled.set(true); @@ -580,11 +580,11 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 2, col: 1}); }); - it('(wrap: false) (skip disabled: true) should not navigate through disabled cells', () => { + it('(wrap: false) (soft disabled: false) should not navigate through disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(false), - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 1, col: 1}), }); cells[2][1].disabled.set(true); @@ -620,7 +620,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('loop'), activeCoords: signal({row: 2, col: 1}), }); @@ -633,7 +633,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('loop'), activeCoords: signal({row: 2, col: 1}), }); @@ -661,7 +661,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('continuous'), activeCoords: signal({row: 2, col: 1}), }); @@ -678,7 +678,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('continuous'), activeCoords: signal({row: 1, col: 1}), }); @@ -733,10 +733,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 2, col: 2}); }); - it('(skip disabled: true) should skip disabled cells', () => { + it('(soft disabled: false) should skip disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridB, - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 0, col: 0}), }); cells[1][0].disabled.set(true); @@ -789,10 +789,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 1, col: 0}); }); - it('(skip disabled: false) should be able to navigate through disabled cells', () => { + it('(soft disabled: true) should be able to navigate through disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, - skipDisabled: signal(false), + softDisabled: signal(true), activeCoords: signal({row: 1, col: 1}), }); cells[1][0].disabled.set(true); @@ -800,10 +800,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 1, col: 0}); }); - it('(skip disabled: true) should skip disabled cells', () => { + it('(soft disabled: false) should skip disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 1, col: 2}), }); cells[1][1].disabled.set(true); @@ -811,11 +811,11 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 1, col: 0}); }); - it('(wrap: false) (skip disabled: true) should not navigate through disabled cells', () => { + it('(wrap: false) (soft disabled: false) should not navigate through disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(false), - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 1, col: 1}), }); cells[1][0].disabled.set(true); @@ -851,7 +851,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('loop'), activeCoords: signal({row: 1, col: 0}), }); @@ -864,7 +864,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('loop'), activeCoords: signal({row: 1, col: 0}), }); @@ -892,7 +892,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('continuous'), activeCoords: signal({row: 1, col: 0}), }); @@ -909,7 +909,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('continuous'), activeCoords: signal({row: 1, col: 1}), }); @@ -973,10 +973,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 2, col: 2}); }); - it('(skip disabled: true) should skip disabled cells', () => { + it('(soft disabled: false) should skip disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridC, - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 0, col: 3}), }); @@ -1031,10 +1031,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 1, col: 2}); }); - it('(skip disabled: false) should be able to navigate through disabled cells', () => { + it('(soft disabled: true) should be able to navigate through disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, - skipDisabled: signal(false), + softDisabled: signal(true), activeCoords: signal({row: 1, col: 1}), }); cells[1][2].disabled.set(true); @@ -1042,10 +1042,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 1, col: 2}); }); - it('(skip disabled: true) should skip disabled cells', () => { + it('(soft disabled: false) should skip disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 1, col: 0}), }); cells[1][1].disabled.set(true); @@ -1053,11 +1053,11 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 1, col: 2}); }); - it('(wrap: false) (skip disabled: true) should not navigate through disabled cells', () => { + it('(wrap: false) (soft disabled: false) should not navigate through disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(false), - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 1, col: 1}), }); cells[1][2].disabled.set(true); @@ -1093,7 +1093,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('loop'), activeCoords: signal({row: 1, col: 2}), }); @@ -1106,7 +1106,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('loop'), activeCoords: signal({row: 1, col: 2}), }); @@ -1134,7 +1134,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('continuous'), activeCoords: signal({row: 1, col: 2}), }); @@ -1151,7 +1151,7 @@ describe('GridNavigation', () => { const {gridNav, cells} = createGridNav({ cells: gridA, wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), wrapBehavior: signal('continuous'), activeCoords: signal({row: 1, col: 1}), }); @@ -1215,10 +1215,10 @@ describe('GridNavigation', () => { expect(gridNav.inputs.activeCoords()).toEqual({row: 0, col: 2}); }); - it('(skip disabled: true) should skip disabled cells', () => { + it('(soft disabled: false) should skip disabled cells', () => { const {gridNav, cells} = createGridNav({ cells: gridC, - skipDisabled: signal(true), + softDisabled: signal(false), activeCoords: signal({row: 0, col: 0}), }); cells[0][1].disabled.set(true); diff --git a/src/aria/ui-patterns/behaviors/grid-navigation/grid-navigation.ts b/src/aria/private/behaviors/grid-navigation/grid-navigation.ts similarity index 100% rename from src/aria/ui-patterns/behaviors/grid-navigation/grid-navigation.ts rename to src/aria/private/behaviors/grid-navigation/grid-navigation.ts diff --git a/src/aria/private/behaviors/grid/BUILD.bazel b/src/aria/private/behaviors/grid/BUILD.bazel new file mode 100644 index 000000000000..f5a971e3fa68 --- /dev/null +++ b/src/aria/private/behaviors/grid/BUILD.bazel @@ -0,0 +1,31 @@ +load("//tools:defaults.bzl", "ng_web_test_suite", "ts_project") + +package(default_visibility = ["//visibility:public"]) + +ts_project( + name = "grid", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), + deps = [ + "//:node_modules/@angular/core", + "//src/aria/private/behaviors/signal-like", + ], +) + +ts_project( + name = "unit_test_sources", + testonly = True, + srcs = glob(["**/*.spec.ts"]), + deps = [ + ":grid", + "//:node_modules/@angular/core", + "//src/aria/private/behaviors/signal-like", + ], +) + +ng_web_test_suite( + name = "unit_tests", + deps = [":unit_test_sources"], +) diff --git a/src/aria/private/behaviors/grid/grid-data.spec.ts b/src/aria/private/behaviors/grid/grid-data.spec.ts new file mode 100644 index 000000000000..bcac11eecae2 --- /dev/null +++ b/src/aria/private/behaviors/grid/grid-data.spec.ts @@ -0,0 +1,337 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {signal, SignalLike, WritableSignalLike} from '../signal-like/signal-like'; +import {BaseGridCell, GridData} from './grid-data'; + +export interface TestBaseGridCell extends BaseGridCell { + rowSpan: WritableSignalLike; + colSpan: WritableSignalLike; + id: SignalLike; +} + +/** + * GRID A: + * ┌─────┬─────┬─────┐ + * │ 0,0 │ 0,1 │ 0,2 │ + * ├─────┼─────┼─────┤ + * │ 1,0 │ 1,1 │ 1,2 │ + * ├─────┼─────┼─────┤ + * │ 2,0 │ 2,1 │ 2,2 │ + * └─────┴─────┴─────┘ + */ +export function createGridA(): TestBaseGridCell[][] { + return [ + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-1')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-2')}, + ], + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-1-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-1-1')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-1-2')}, + ], + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-1')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-2')}, + ], + ]; +} + +/** + * GRID B: + * ┌─────┬─────┬─────┐ + * │ 0,0 │ 0,1 │ 0,2 │ + * ├─────┼─────┤ │ + * │ 1,0 │ 1,1 │ │ + * ├─────┤ ├─────┤ + * │ 2,0 │ │ 2,2 │ + * │ ├─────┼─────┤ + * │ │ 3,1 │ 3,2 │ + * └─────┴─────┴─────┘ + */ +export function createGridB(): TestBaseGridCell[][] { + return [ + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-1')}, + {rowSpan: signal(2), colSpan: signal(1), id: signal('cell-0-2')}, + ], + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-1-0')}, + {rowSpan: signal(2), colSpan: signal(1), id: signal('cell-1-1')}, + ], + [ + {rowSpan: signal(2), colSpan: signal(1), id: signal('cell-2-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-2')}, + ], + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-3-1')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-3-2')}, + ], + ]; +} + +/** + * GRID C: + * ┌───────────┬─────┬─────┐ + * │ 0,0 │ 0,2 │ 0,3 │ + * ├─────┬─────┴─────┼─────┤ + * │ 1,0 │ 1,1 │ 1,3 │ + * ├─────┼─────┬─────┴─────┤ + * │ 2,0 │ 2,1 │ 2,2 │ + * └─────┴─────┴───────────┘ + */ +export function createGridC(): TestBaseGridCell[][] { + return [ + [ + {rowSpan: signal(1), colSpan: signal(2), id: signal('cell-0-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-2')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-3')}, + ], + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-1-0')}, + {rowSpan: signal(1), colSpan: signal(2), id: signal('cell-1-1')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-1-3')}, + ], + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-1')}, + {rowSpan: signal(1), colSpan: signal(2), id: signal('cell-2-2')}, + ], + ]; +} + +/** + * GRID D: + * ┌─────┬───────────┬─────┐ + * │ 0,0 │ 0,1 │ 0,3 │ + * │ ├───────────┼─────┤ + * │ │ 1,1 │ 1,3 │ + * ├─────┤ │ │ + * │ 2,0 │ │ │ + * ├─────┼─────┬─────┴─────┤ + * │ 3,0 │ 3,1 │ 3,2 │ + * └─────┴─────┴───────────┘ + */ +export function createGridD(): TestBaseGridCell[][] { + return [ + [ + {rowSpan: signal(2), colSpan: signal(1), id: signal('cell-0-0')}, + {rowSpan: signal(1), colSpan: signal(2), id: signal('cell-0-1')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-3')}, + ], + [ + {rowSpan: signal(2), colSpan: signal(2), id: signal('cell-1-1')}, + {rowSpan: signal(2), colSpan: signal(1), id: signal('cell-1-3')}, + ], + [{rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-0')}], + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-3-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-3-1')}, + {rowSpan: signal(1), colSpan: signal(2), id: signal('cell-3-2')}, + ], + ]; +} + +/** + * GRID E: Uneven rows (jagged) + * ┌─────┬─────┬─────┐ + * │ 0,0 │ 0,1 │ 0,2 │ + * ├─────┤ ├─────┘ + * │ 1,0 │ │ + * ├─────┼─────┤ + * │ 2,0 │ 2,1 │ + * └─────┴─────┴ + */ +export function createGridE(): TestBaseGridCell[][] { + return [ + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-0')}, + {rowSpan: signal(2), colSpan: signal(1), id: signal('cell-0-1')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-2')}, + ], + [{rowSpan: signal(1), colSpan: signal(1), id: signal('cell-1-0')}], + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-1')}, + ], + ]; +} + +/** + * GRID F: Grid with empty rows + * ┌─────┬─────┬─────┐ + * │ 0,0 │ 0,1 │ 0,2 │ + * ├─────┼─────┼─────┤ + * │ │ │ │ + * ├─────┼─────┼─────┤ + * │ 2,0 │ 2,1 │ 2,2 │ + * └─────┴─────┴─────┘ + */ +export function createGridF(): TestBaseGridCell[][] { + return [ + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-1')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-0-2')}, + ], + [], + [ + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-0')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-1')}, + {rowSpan: signal(1), colSpan: signal(1), id: signal('cell-2-2')}, + ], + ]; +} + +function createGridData(cells: TestBaseGridCell[][]): GridData { + return new GridData({cells: signal(cells)}); +} + +describe('GridData', () => { + describe('rowCount', () => { + it('should return the number of rows in the grid', () => {}); + }); + + describe('maxRowCount', () => { + it('should return the maximum number of rows, accounting for row spans', () => { + const gridA = createGridData(createGridA()); + expect(gridA.maxRowCount()).toBe(3); + + const gridB = createGridData(createGridB()); + expect(gridB.maxRowCount()).toBe(4); + + const gridC = createGridData(createGridC()); + expect(gridC.maxRowCount()).toBe(3); + + const gridD = createGridData(createGridD()); + expect(gridD.maxRowCount()).toBe(4); + + const gridF = createGridData(createGridE()); + expect(gridF.maxRowCount()).toBe(3); + + const gridG = createGridData(createGridF()); + expect(gridG.maxRowCount()).toBe(3); + }); + }); + + describe('maxColCount', () => { + it('should return the maximum number of columns, accounting for column spans', () => { + const gridA = createGridData(createGridA()); + expect(gridA.maxColCount()).toBe(3); + + const gridB = createGridData(createGridB()); + expect(gridB.maxColCount()).toBe(3); + + const gridC = createGridData(createGridC()); + expect(gridC.maxColCount()).toBe(4); + + const gridD = createGridData(createGridD()); + expect(gridD.maxColCount()).toBe(4); + + const gridE = createGridData(createGridE()); + expect(gridE.maxColCount()).toBe(3); + + const gridF = createGridData(createGridF()); + expect(gridF.maxColCount()).toBe(3); + }); + }); + + describe('getCell', () => { + it('should get the cell at the given coordinates', () => { + const cells = createGridD(); + const grid = createGridData(cells); + + expect(grid.getCell({row: 0, col: 0})).toBe(cells[0][0]); + expect(grid.getCell({row: 1, col: 0})).toBe(cells[0][0]); + expect(grid.getCell({row: 0, col: 1})).toBe(cells[0][1]); + expect(grid.getCell({row: 0, col: 2})).toBe(cells[0][1]); + expect(grid.getCell({row: 1, col: 1})).toBe(cells[1][0]); + expect(grid.getCell({row: 2, col: 2})).toBe(cells[1][0]); + }); + + it('should return undefined for out-of-bounds coordinates', () => { + const grid = createGridData(createGridA()); + expect(grid.getCell({row: 5, col: 5})).toBeUndefined(); + expect(grid.getCell({row: -1, col: 0})).toBeUndefined(); + }); + }); + + describe('getCoords', () => { + it('should get the primary coordinates of the given cell', () => { + const cells = createGridD(); + const grid = createGridData(cells); + + expect(grid.getCoords(cells[0][0])).toEqual({row: 0, col: 0}); + expect(grid.getCoords(cells[1][0])).toEqual({row: 1, col: 1}); + expect(grid.getCoords(cells[3][2])).toEqual({row: 3, col: 2}); + }); + }); + + describe('getAllCoords', () => { + it('should get all coordinates that the given cell spans', () => { + const cells = createGridD(); + const grid = createGridData(cells); + + expect(grid.getAllCoords(cells[0][0])).toEqual([ + {row: 0, col: 0}, + {row: 1, col: 0}, + ]); + expect(grid.getAllCoords(cells[1][0])).toEqual([ + {row: 1, col: 1}, + {row: 1, col: 2}, + {row: 2, col: 1}, + {row: 2, col: 2}, + ]); + expect(grid.getAllCoords(cells[3][2])).toEqual([ + {row: 3, col: 2}, + {row: 3, col: 3}, + ]); + }); + }); + + describe('getRowCount', () => { + it('should get the number of rows in the given column', () => { + const grid = createGridData(createGridD()); + expect(grid.getRowCount(0)).toBe(4); + expect(grid.getRowCount(1)).toBe(4); + expect(grid.getRowCount(2)).toBe(4); + expect(grid.getRowCount(3)).toBe(4); + }); + + it('should return undefined for an out-of-bounds column', () => { + const grid = createGridData(createGridA()); + expect(grid.getRowCount(5)).toBeUndefined(); + expect(grid.getRowCount(-1)).toBeUndefined(); + }); + }); + + describe('getColCount', () => { + it('should get the number of columns in the given row', () => { + const gridD = createGridData(createGridD()); + expect(gridD.getColCount(0)).toBe(4); + expect(gridD.getColCount(1)).toBe(4); + expect(gridD.getColCount(2)).toBe(4); + expect(gridD.getColCount(3)).toBe(4); + + const gridE = createGridData(createGridE()); + expect(gridE.getColCount(0)).toBe(3); + expect(gridE.getColCount(1)).toBe(2); + expect(gridE.getColCount(2)).toBe(2); + }); + + it('should return undefined for an out-of-bounds row', () => { + const grid = createGridData(createGridA()); + expect(grid.getColCount(5)).toBeUndefined(); + expect(grid.getColCount(-1)).toBeUndefined(); + }); + }); +}); diff --git a/src/aria/ui-patterns/behaviors/grid/grid-data.ts b/src/aria/private/behaviors/grid/grid-data.ts similarity index 96% rename from src/aria/ui-patterns/behaviors/grid/grid-data.ts rename to src/aria/private/behaviors/grid/grid-data.ts index b3065e97ac13..173677b4f791 100644 --- a/src/aria/ui-patterns/behaviors/grid/grid-data.ts +++ b/src/aria/private/behaviors/grid/grid-data.ts @@ -6,8 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed} from '@angular/core'; -import {SignalLike} from '../signal-like/signal-like'; +import {computed, SignalLike} from '../signal-like/signal-like'; /** Represents coordinates in a grid. */ export interface RowCol { @@ -41,9 +40,6 @@ export class GridData { /** The two-dimensional array of cells that represents the grid. */ readonly cells: SignalLike; - /** The number of rows in the grid. */ - readonly rowCount = computed(() => this.cells().length); - /** The maximum number of rows in the grid, accounting for row spans. */ readonly maxRowCount = computed(() => Math.max(...this._rowCountByCol().values(), 0)); @@ -131,6 +127,11 @@ export class GridData { this.cells = this.inputs.cells; } + /** Whether the cell exists. */ + hasCell(cell: T): boolean { + return this._coordsMap().has(cell); + } + /** Gets the cell at the given coordinates. */ getCell(rowCol: RowCol): T | undefined { return this._cellMap().get(`${rowCol.row}:${rowCol.col}`); diff --git a/src/aria/private/behaviors/grid/grid-focus.spec.ts b/src/aria/private/behaviors/grid/grid-focus.spec.ts new file mode 100644 index 000000000000..367891c4a116 --- /dev/null +++ b/src/aria/private/behaviors/grid/grid-focus.spec.ts @@ -0,0 +1,380 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {signal, SignalLike, WritableSignalLike} from '../signal-like/signal-like'; +import {GridData} from './grid-data'; +import {createGridA, createGridB, createGridD, TestBaseGridCell} from './grid-data.spec'; +import {GridFocus, GridFocusInputs} from './grid-focus'; + +export interface TestGridFocusCell extends TestBaseGridCell { + element: WritableSignalLike; + disabled: WritableSignalLike; +} + +function createTestCell(): Omit { + return { + element: signal(document.createElement('div')), + disabled: signal(false), + }; +} + +function createTestGrid(createGridFn: () => TestBaseGridCell[][]): TestGridFocusCell[][] { + return createGridFn().map(row => + row.map(cell => { + return {...createTestCell(), ...cell}; + }), + ); +} + +function setupGridFocus( + cells: SignalLike, + gridFocusInputs: Partial = {}, +): GridFocus { + const gridData = new GridData({cells}); + return new GridFocus({ + grid: gridData, + focusMode: signal('roving'), + disabled: signal(false), + softDisabled: signal(false), + ...gridFocusInputs, + }); +} + +describe('GridFocus', () => { + describe('stateEmpty', () => { + it('should be true initially', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells)); + expect(gridFocus.stateEmpty()).toBe(true); + }); + + it('should be false after focusing a cell', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells)); + + gridFocus.focusCell(cells[1][1]); + + expect(gridFocus.stateEmpty()).toBe(false); + }); + + it('should be true if activeCell is undefined', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells)); + + // Manually create a partially-empty state. + gridFocus.activeCell.set(undefined); + gridFocus.activeCoords.set({row: 1, col: 1}); + + expect(gridFocus.stateEmpty()).toBe(true); + }); + }); + + describe('stateStale', () => { + it('should be true if the active cell is no longer in the grid', () => { + const cells = createTestGrid(createGridA); + const cellsSignal = signal(cells); + const gridFocus = setupGridFocus(cellsSignal); + + gridFocus.focusCell(cells[1][1]); + + // Remove the active cell from the grid. + const newCells = createTestGrid(createGridA); + newCells[1].splice(1, 1); + cellsSignal.set(newCells); + + expect(gridFocus.stateStale()).toBe(true); + }); + + it('should be true if the active coordinates point to a different cell', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells)); + + gridFocus.focusCell(cells[1][1]); + + // Manually set the active coordinates to a different cell. + gridFocus.activeCoords.set({row: 0, col: 0}); + + expect(gridFocus.stateStale()).toBe(true); + }); + + it('should be false if the active cell and coordinates are valid and in sync', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells)); + + gridFocus.focusCell(cells[1][1]); + + expect(gridFocus.stateStale()).toBe(false); + }); + }); + + describe('activeDescendant', () => { + it('should return the ID of the active cell in activedescendant mode', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), { + focusMode: signal('activedescendant'), + }); + + gridFocus.focusCell(cells[1][1]); + + expect(gridFocus.activeDescendant()).toBe('cell-1-1'); + }); + + it('should be undefined in roving focus mode', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), {focusMode: signal('roving')}); + + gridFocus.focusCell(cells[1][1]); + + expect(gridFocus.activeDescendant()).toBeUndefined(); + }); + + it('should be undefined if the grid is disabled', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), { + focusMode: signal('activedescendant'), + disabled: signal(true), + }); + + gridFocus.activeCell.set(cells[1][1]); + + expect(gridFocus.activeDescendant()).toBeUndefined(); + }); + }); + + describe('gridDisabled', () => { + it('should be true if the grid is disabled via inputs', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), { + disabled: signal(true), + }); + expect(gridFocus.gridDisabled()).toBe(true); + }); + + it('should be true if all cells are disabled', () => { + const cells = createTestGrid(createGridA); + for (const row of cells) { + for (const cell of row) { + cell.disabled.set(true); + } + } + const gridFocus = setupGridFocus(signal(cells)); + expect(gridFocus.gridDisabled()).toBe(true); + }); + + it('should be true if there are no cells', () => { + const gridFocus = setupGridFocus(signal([])); + expect(gridFocus.gridDisabled()).toBe(true); + }); + + it('should be false if at least one cell is enabled', () => { + const cells = createTestGrid(createGridA); + for (const row of cells) { + for (const cell of row) { + cell.disabled.set(true); + } + } + // Enable one cell. + cells[1][1].disabled.set(false); + const gridFocus = setupGridFocus(signal(cells)); + expect(gridFocus.gridDisabled()).toBe(false); + }); + }); + + describe('gridTabIndex', () => { + it('should be 0 in activedescendant mode', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), { + focusMode: signal('activedescendant'), + }); + expect(gridFocus.gridTabIndex()).toBe(0); + }); + + it('should be -1 in roving focus mode', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), { + focusMode: signal('roving'), + }); + expect(gridFocus.gridTabIndex()).toBe(-1); + }); + + it('should be 0 if the grid is disabled', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), { + disabled: signal(true), + }); + expect(gridFocus.gridTabIndex()).toBe(0); + }); + }); + + describe('getCellTabindex', () => { + it('should return 0 for the active cell in roving mode', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), { + focusMode: signal('roving'), + }); + + gridFocus.focusCell(cells[1][1]); + + expect(gridFocus.getCellTabIndex(cells[1][1])).toBe(0); + }); + + it('should return -1 for inactive cells in roving mode', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), { + focusMode: signal('roving'), + }); + + gridFocus.focusCell(cells[1][1]); + + expect(gridFocus.getCellTabIndex(cells[0][0])).toBe(-1); + expect(gridFocus.getCellTabIndex(cells[2][2])).toBe(-1); + }); + + it('should return -1 for all cells in activedescendant mode', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), { + focusMode: signal('activedescendant'), + }); + + gridFocus.focusCell(cells[1][1]); + + expect(gridFocus.getCellTabIndex(cells[0][0])).toBe(-1); + expect(gridFocus.getCellTabIndex(cells[1][1])).toBe(-1); + }); + + it('should return -1 for all cells when the grid is disabled', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), {disabled: signal(true)}); + expect(gridFocus.getCellTabIndex(cells[1][1])).toBe(-1); + }); + }); + + describe('isFocusable', () => { + it('should return true for an enabled cell', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells)); + expect(gridFocus.isFocusable(cells[1][1])).toBe(true); + }); + + it('should return false for a disabled cell when softDisabled is false', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), {softDisabled: signal(false)}); + + cells[1][1].disabled.set(true); + + expect(gridFocus.isFocusable(cells[1][1])).toBe(false); + }); + + it('should return true for a disabled cell when softDisabled is true', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), {softDisabled: signal(true)}); + + cells[1][1].disabled.set(true); + + expect(gridFocus.isFocusable(cells[1][1])).toBe(true); + }); + }); + + describe('focusCell', () => { + it('should set the active cell and coordinates', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells)); + + const result = gridFocus.focusCell(cells[1][1]); + + expect(result).toBe(true); + expect(gridFocus.activeCell()).toBe(cells[1][1]); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 1}); + }); + + it('should not focus a disabled cell if softDisabled is false', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), {softDisabled: signal(false)}); + + gridFocus.focusCell(cells[0][0]); + cells[1][1].disabled.set(true); + + const result = gridFocus.focusCell(cells[1][1]); + + expect(result).toBe(false); + expect(gridFocus.activeCell()).toBe(cells[0][0]); + expect(gridFocus.activeCoords()).toEqual({row: 0, col: 0}); + }); + + it('should focus a disabled cell if softDisabled is true', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells), {softDisabled: signal(true)}); + + cells[1][1].disabled.set(true); + const result = gridFocus.focusCell(cells[1][1]); + + expect(result).toBe(true); + expect(gridFocus.activeCell()).toBe(cells[1][1]); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 1}); + }); + + it('should return false if the cell is not in the grid', () => { + const cells = createTestGrid(createGridA); + const gridFocus = setupGridFocus(signal(cells)); + const unrelatedCell = createTestGrid(createGridB)[0][0]; + + const result = gridFocus.focusCell(unrelatedCell); + + expect(result).toBe(false); + }); + }); + + describe('focusCoordinates', () => { + it('should set the active cell and coordinates', () => { + const cells = createTestGrid(createGridD); + const gridFocus = setupGridFocus(signal(cells)); + + const result = gridFocus.focusCoordinates({row: 1, col: 2}); + + expect(result).toBe(true); + // The cell at `[1][0]` spans `[1,1]`, `[1,2]`, `[2,1]`, and `[2,2]`. + expect(gridFocus.activeCell()).toBe(cells[1][0]); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 2}); + }); + + it('should not focus coordinates of a disabled cell if softDisabled is false', () => { + const cells = createTestGrid(createGridD); + const gridFocus = setupGridFocus(signal(cells), {softDisabled: signal(false)}); + + gridFocus.focusCoordinates({row: 0, col: 0}); + cells[1][0].disabled.set(true); // This cell spans {row: 1, col: 2} + + const result = gridFocus.focusCoordinates({row: 1, col: 2}); + + expect(result).toBe(false); + expect(gridFocus.activeCell()).toBe(cells[0][0]); + expect(gridFocus.activeCoords()).toEqual({row: 0, col: 0}); + }); + + it('should focus coordinates of a disabled cell if softDisabled is true', () => { + const cells = createTestGrid(createGridD); + const gridFocus = setupGridFocus(signal(cells), {softDisabled: signal(true)}); + + cells[1][0].disabled.set(true); // This cell spans {row: 1, col: 2} + const result = gridFocus.focusCoordinates({row: 1, col: 2}); + + expect(result).toBe(true); + expect(gridFocus.activeCell()).toBe(cells[1][0]); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 2}); + }); + + it('should return false for out-of-bounds coordinates', () => { + const cells = createTestGrid(createGridD); + const gridFocus = setupGridFocus(signal(cells)); + + const result = gridFocus.focusCoordinates({row: 10, col: 10}); + + expect(result).toBe(false); + }); + }); +}); diff --git a/src/aria/ui-patterns/behaviors/grid/grid-focus.ts b/src/aria/private/behaviors/grid/grid-focus.ts similarity index 89% rename from src/aria/ui-patterns/behaviors/grid/grid-focus.ts rename to src/aria/private/behaviors/grid/grid-focus.ts index 435a5d6abfeb..31f0502e80f7 100644 --- a/src/aria/ui-patterns/behaviors/grid/grid-focus.ts +++ b/src/aria/private/behaviors/grid/grid-focus.ts @@ -6,8 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed, signal} from '@angular/core'; -import {SignalLike} from '../signal-like/signal-like'; +import {computed, signal, WritableSignalLike, SignalLike} from '../signal-like/signal-like'; import type {GridData, BaseGridCell, RowCol} from './grid-data'; /** Represents an cell in a grid, such as a grid cell, that may receive focus. */ @@ -30,8 +29,8 @@ export interface GridFocusInputs { /** Whether the grid is disabled. */ disabled: SignalLike; - /** Whether disabled cells in the grid should be skipped when navigating. */ - skipDisabled: SignalLike; + /** Whether disabled cells in the grid should be focusable. */ + softDisabled: SignalLike; } /** Dependencies for the `GridFocus` class. */ @@ -43,7 +42,7 @@ interface GridFocusDeps { /** Controls focus for a 2D grid of cells. */ export class GridFocus { /** The current active cell. */ - readonly activeCell = signal(undefined); + readonly activeCell: WritableSignalLike = signal(undefined); /** The current active cell coordinates. */ readonly activeCoords = signal({row: -1, col: -1}); @@ -95,7 +94,7 @@ export class GridFocus { return gridCells.length === 0 || gridCells.every(row => row.every(cell => cell.disabled())); }); - /** The tabindex for the grid container. */ + /** The tab index for the grid container. */ readonly gridTabIndex = computed<-1 | 0>(() => { if (this.gridDisabled()) { return 0; @@ -105,8 +104,8 @@ export class GridFocus { constructor(readonly inputs: GridFocusInputs & GridFocusDeps) {} - /** Returns the tabindex for the given grid cell cell. */ - getCellTabindex(cell: T): -1 | 0 { + /** Returns the tab index for the given grid cell cell. */ + getCellTabIndex(cell: T): -1 | 0 { if (this.gridDisabled()) { return -1; } @@ -118,7 +117,7 @@ export class GridFocus { /** Returns true if the given cell can be navigated to. */ isFocusable(cell: T): boolean { - return !cell.disabled() || !this.inputs.skipDisabled(); + return this.inputs.grid.hasCell(cell) && (!cell.disabled() || this.inputs.softDisabled()); } /** Focuses the given cell. */ diff --git a/src/aria/private/behaviors/grid/grid-navigation.spec.ts b/src/aria/private/behaviors/grid/grid-navigation.spec.ts new file mode 100644 index 000000000000..d166d8fcefc1 --- /dev/null +++ b/src/aria/private/behaviors/grid/grid-navigation.spec.ts @@ -0,0 +1,2435 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {signal, SignalLike, WritableSignalLike} from '../signal-like/signal-like'; +import {GridData} from './grid-data'; +import { + createGridA, + createGridB, + createGridC, + createGridD, + createGridE, + createGridF, + TestBaseGridCell, +} from './grid-data.spec'; +import {GridFocus, GridFocusInputs} from './grid-focus'; +import {direction, GridNavigation, GridNavigationInputs, WrapStrategy} from './grid-navigation'; + +export interface TestGridNavigationCell extends TestBaseGridCell { + element: WritableSignalLike; + disabled: WritableSignalLike; +} + +function createTestCell(): Omit { + return { + element: signal(document.createElement('div')), + disabled: signal(false), + }; +} + +function createTestGrid(createGridFn: () => TestBaseGridCell[][]): TestGridNavigationCell[][] { + return createGridFn().map((row, r) => + row.map((cell, c) => { + return {...createTestCell(), ...cell}; + }), + ); +} + +function setupGridNavigation( + cells: SignalLike, + inputs: Partial = {}, +): { + gridNav: GridNavigation; + gridFocus: GridFocus; +} { + const gridData = new GridData({cells}); + const gridFocusInputs: GridFocusInputs = { + focusMode: signal('roving'), + disabled: signal(false), + softDisabled: signal(true), + }; + const gridFocus = new GridFocus({ + grid: gridData, + ...gridFocusInputs, + ...inputs, + }); + + const gridNav = new GridNavigation({ + grid: gridData, + gridFocus: gridFocus, + rowWrap: signal('loop'), + colWrap: signal('loop'), + ...gridFocusInputs, + ...inputs, + }); + + return { + gridNav, + gridFocus, + }; +} + +describe('GridNavigation', () => { + describe('gotoCell', () => { + it('should focus the given cell', () => { + const cells = createTestGrid(createGridA); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells)); + + const result = gridNav.gotoCell(cells[1][1]); + + expect(result).toBe(true); + expect(gridFocus.activeCell()).toBe(cells[1][1]); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 1}); + }); + + it('should return false if the cell cannot be focused', () => { + const cells = createTestGrid(createGridA); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + + cells[1][1].disabled.set(true); + const result = gridNav.gotoCell(cells[1][1]); + + expect(result).toBe(false); + expect(gridFocus.activeCell()).toBeUndefined(); + }); + }); + + describe('gotoCoords', () => { + it('should focus the cell at the given coordinates', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells)); + + const result = gridNav.gotoCoords({row: 1, col: 2}); + + expect(result).toBe(true); + // The cell at `[1][0]` spans `[1,1]`, `[1,2]`, `[2,1]`, and `[2,2]`. + expect(gridFocus.activeCell()).toBe(cells[1][0]); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 2}); + }); + + it('should return false if the coordinates cannot be focused when softDisabled is false', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + + cells[1][0].disabled.set(true); // This cell spans {row: 1, col: 2} + const result = gridNav.gotoCoords({row: 1, col: 2}); + + expect(result).toBe(false); + expect(gridFocus.activeCell()).toBeUndefined(); + }); + }); + + describe('peek', () => { + let cells: TestGridNavigationCell[][]; + let gridNav: GridNavigation; + let gridFocus: GridFocus; + + beforeEach(() => { + cells = createTestGrid(createGridB); + const setup = setupGridNavigation(signal(cells)); + gridNav = setup.gridNav; + gridFocus = setup.gridFocus; + }); + + describe('up', () => { + it('should get the next coordinates without changing focus', () => { + gridNav.gotoCoords({row: 1, col: 0}); + + const nextCoords = gridNav.peek(direction.Up, gridFocus.activeCoords()); + + expect(nextCoords).toEqual({row: 0, col: 0}); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 0}); + }); + + it('should respect the wrap strategy', () => { + const from = {row: 0, col: 0}; + gridNav.gotoCoords(from); + expect(gridNav.peek(direction.Up, from, 'loop')).toEqual({row: 3, col: 0}); + expect(gridNav.peek(direction.Up, from, 'nowrap')).toBeUndefined(); + expect(gridNav.peek(direction.Up, from, 'continuous')).toBeUndefined(); + }); + + it('should return undefined if all cells are disabled', () => { + cells.flat().forEach(cell => cell.disabled.set(true)); + gridNav.gotoCoords({row: 1, col: 0}); + + const nextCoords = gridNav.peek(direction.Up, gridFocus.activeCoords()); + + expect(nextCoords).toBeUndefined(); + }); + + it('should return undefined if all cells are disabled when softDisabled is false', () => { + const {gridNav} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + cells.flat().forEach(cell => cell.disabled.set(true)); + + const nextCoords = gridNav.peek(direction.Up, {row: 1, col: 0}); + + expect(nextCoords).toBeUndefined(); + }); + + it('should get disabled cells when allowDisabled is true and softDisabled is false', () => { + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + gridNav.gotoCoords({row: 1, col: 0}); + cells[0][0].disabled.set(true); + + const nextCoords = gridNav.peek(direction.Up, gridFocus.activeCoords(), 'nowrap', true); + + expect(nextCoords).toEqual({row: 0, col: 0}); + expect(gridNav.peek(direction.Up, gridFocus.activeCoords(), 'nowrap')).toBeUndefined(); + }); + }); + + describe('down', () => { + it('should get the next coordinates without changing focus', () => { + gridNav.gotoCoords({row: 1, col: 0}); + + const nextCoords = gridNav.peek(direction.Down, gridFocus.activeCoords()); + + expect(nextCoords).toEqual({row: 2, col: 0}); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 0}); + }); + + it('should respect the wrap strategy', () => { + const from = {row: 3, col: 1}; + gridNav.gotoCoords(from); + expect(gridNav.peek(direction.Down, from, 'loop')).toEqual({row: 0, col: 1}); + expect(gridNav.peek(direction.Down, from, 'nowrap')).toBeUndefined(); + expect(gridNav.peek(direction.Down, from, 'continuous')).toEqual({row: 0, col: 2}); + }); + + it('should return undefined if completely disabled', () => { + cells.flat().forEach(cell => cell.disabled.set(true)); + gridNav.gotoCoords({row: 1, col: 0}); + + const nextCoords = gridNav.peek(direction.Down, gridFocus.activeCoords()); + + expect(nextCoords).toBeUndefined(); + }); + + it('should get disabled cells when allowDisabled is true and softDisabled is false', () => { + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + gridNav.gotoCoords({row: 1, col: 0}); + cells[2][0].disabled.set(true); + + const nextCoords = gridNav.peek(direction.Down, gridFocus.activeCoords(), 'nowrap', true); + + expect(nextCoords).toEqual({row: 2, col: 0}); + expect(gridNav.peek(direction.Down, gridFocus.activeCoords(), 'nowrap')).toBeUndefined(); + }); + }); + + describe('left', () => { + it('should get the next coordinates without changing focus', () => { + gridNav.gotoCoords({row: 0, col: 1}); + + const nextCoords = gridNav.peek(direction.Left, gridFocus.activeCoords()); + + expect(nextCoords).toEqual({row: 0, col: 0}); + expect(gridFocus.activeCoords()).toEqual({row: 0, col: 1}); + }); + + it('should respect the wrap strategy', () => { + const from = {row: 0, col: 0}; + gridNav.gotoCoords(from); + expect(gridNav.peek(direction.Left, from, 'loop')).toEqual({row: 0, col: 2}); + expect(gridNav.peek(direction.Left, from, 'nowrap')).toBeUndefined(); + expect(gridNav.peek(direction.Left, from, 'continuous')).toBeUndefined(); + }); + + it('should return undefined if completely disabled', () => { + cells.flat().forEach(cell => cell.disabled.set(true)); + gridNav.gotoCoords({row: 1, col: 0}); + + const nextCoords = gridNav.peek(direction.Down, gridFocus.activeCoords()); + + expect(nextCoords).toBeUndefined(); + }); + + it('should get disabled cells when allowDisabled is true when softDisabled is false', () => { + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + gridNav.gotoCoords({row: 0, col: 1}); + cells[0][0].disabled.set(true); + + const nextCoords = gridNav.peek(direction.Left, gridFocus.activeCoords(), 'nowrap', true); + + expect(nextCoords).toEqual({row: 0, col: 0}); + expect(gridNav.peek(direction.Left, gridFocus.activeCoords(), 'nowrap')).toBeUndefined(); + }); + }); + + describe('right', () => { + it('should get the next coordinates without changing focus', () => { + gridNav.gotoCoords({row: 0, col: 1}); + + const nextCoords = gridNav.peek(direction.Right, gridFocus.activeCoords()); + + expect(nextCoords).toEqual({row: 0, col: 2}); + expect(gridFocus.activeCoords()).toEqual({row: 0, col: 1}); + }); + + it('should respect the wrap strategy', () => { + const from = {row: 0, col: 2}; + gridNav.gotoCoords(from); + expect(gridNav.peek(direction.Right, from, 'loop')).toEqual({row: 0, col: 0}); + expect(gridNav.peek(direction.Right, from, 'nowrap')).toBeUndefined(); + expect(gridNav.peek(direction.Right, from, 'continuous')).toEqual({row: 1, col: 0}); + }); + + it('should return undefined if completely disabled', () => { + cells.flat().forEach(cell => cell.disabled.set(true)); + gridNav.gotoCoords({row: 1, col: 0}); + + const nextCoords = gridNav.peek(direction.Down, gridFocus.activeCoords()); + + expect(nextCoords).toBeUndefined(); + }); + + it('should get disabled cells when allowDisabled is true and softDisabled is false', () => { + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + gridNav.gotoCoords({row: 0, col: 1}); + cells[0][2].disabled.set(true); + + const nextCoords = gridNav.peek(direction.Right, gridFocus.activeCoords(), 'nowrap', true); + + expect(nextCoords).toEqual({row: 0, col: 2}); + expect(gridNav.peek(direction.Right, gridFocus.activeCoords(), 'nowrap')).toBeUndefined(); + }); + }); + }); + + describe('advance', () => { + describe('wrap=continuous', () => { + describe('up', () => { + describe('case 1', () => { + it('from start', () => { + const cells = createTestGrid(createGridA); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridA); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('case 2', () => { + it('from start', () => { + const cells = createTestGrid(createGridB); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridB); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 3, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('case 3', () => { + it('from start', () => { + const cells = createTestGrid(createGridC); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridC); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 3}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('case 4', () => { + it('from start', () => { + const cells = createTestGrid(createGridD); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridD); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 3, col: 3}); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('case 5', () => { + it('from start', () => { + const cells = createTestGrid(createGridE); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridE); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('case 6', () => { + it('from start', () => { + const cells = createTestGrid(createGridF); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + }); + + it('from end', () => { + const cells = createTestGrid(createGridF); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + }); + + describe('down', () => { + describe('case 1', () => { + it('from start', () => { + const cells = createTestGrid(createGridA); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridA); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 2}); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + }); + + describe('case 2', () => { + it('from start', () => { + const cells = createTestGrid(createGridB); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + gridNav.gotoCoords({row: 3, col: 2}); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + }); + }); + + describe('case 3', () => { + it('from start', () => { + const cells = createTestGrid(createGridC); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + gridNav.gotoCoords({row: 2, col: 3}); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + }); + + describe('case 4', () => { + it('from start', () => { + const cells = createTestGrid(createGridD); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + gridNav.gotoCoords({row: 3, col: 3}); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + }); + }); + + describe('case 5', () => { + it('from start', () => { + const cells = createTestGrid(createGridE); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridE); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + gridNav.gotoCoords({row: 0, col: 2}); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + }); + }); + + describe('case 6', () => { + it('from start', () => { + const cells = createTestGrid(createGridF); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridF); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + gridNav.gotoCoords({row: 2, col: 2}); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + }); + }); + + describe('left', () => { + describe('case 1', () => { + it('from start', () => { + const cells = createTestGrid(createGridA); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + // Advancing left from the first cell should not change the active cell. + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridA); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('case 2', () => { + it('from start', () => { + const cells = createTestGrid(createGridB); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridB); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 3, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('case 3', () => { + it('from start', () => { + const cells = createTestGrid(createGridC); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridC); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('case 4', () => { + it('from start', () => { + const cells = createTestGrid(createGridD); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridD); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 3, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('case 5', () => { + it('from start', () => { + const cells = createTestGrid(createGridE); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridE); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 1}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('case 6', () => { + it('from start', () => { + const cells = createTestGrid(createGridF); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridF); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + }); + + describe('right', () => { + describe('case 1', () => { + it('from start', () => { + const cells = createTestGrid(createGridA); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridA); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 2}); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + }); + + describe('case 2', () => { + it('from start', () => { + const cells = createTestGrid(createGridB); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridB); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 3, col: 2}); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + }); + }); + + describe('case 3', () => { + it('from start', () => { + const cells = createTestGrid(createGridC); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridC); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 2}); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + }); + + describe('case 4', () => { + it('from start', () => { + const cells = createTestGrid(createGridD); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridD); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 3, col: 2}); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + }); + }); + + describe('case 5', () => { + it('from start', () => { + const cells = createTestGrid(createGridE); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridE); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 1}); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + }); + }); + + describe('case 6', () => { + it('from start', () => { + const cells = createTestGrid(createGridF); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + + it('from end', () => { + const cells = createTestGrid(createGridF); + const setup = setupGridNavigation(signal(cells), { + rowWrap: signal('continuous'), + colWrap: signal('continuous'), + }); + const gridNav = setup.gridNav; + const gridFocus = setup.gridFocus; + + gridNav.gotoCoords({row: 2, col: 2}); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-2'); + }); + }); + }); + }); + + describe('wrap=loop', () => { + describe('up', () => { + it('case 1', () => { + const cells = createTestGrid(createGridA); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 2', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 3', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 4', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 5', () => { + const cells = createTestGrid(createGridE); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 6', () => { + const cells = createTestGrid(createGridF); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('down', () => { + it('case 1', () => { + const cells = createTestGrid(createGridA); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 2', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 3', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 4', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 5', () => { + const cells = createTestGrid(createGridE); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 6', () => { + const cells = createTestGrid(createGridF); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('left', () => { + it('case 1', () => { + const cells = createTestGrid(createGridA); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 2', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 3', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 4', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 5', () => { + const cells = createTestGrid(createGridE); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 6', () => { + const cells = createTestGrid(createGridF); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('right', () => { + it('case 1', () => { + const cells = createTestGrid(createGridA); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 2', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 3', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 4', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 5', () => { + const cells = createTestGrid(createGridE); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 6', () => { + const cells = createTestGrid(createGridF); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('loop'), + colWrap: signal('loop'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + }); + + describe('wrap=nowrap', () => { + describe('up', () => { + it('case 1', () => { + const cells = createTestGrid(createGridA); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 2, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 2', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 3, col: 1}); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + }); + + it('case 3', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 2, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 4', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 3, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 5', () => { + const cells = createTestGrid(createGridE); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 2, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 6', () => { + const cells = createTestGrid(createGridF); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 2, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Up); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('down', () => { + it('case 1', () => { + const cells = createTestGrid(createGridA); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + }); + + it('case 2', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 1}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-1'); + }); + + it('case 3', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + }); + + it('case 4', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-0'); + }); + + it('case 5', () => { + const cells = createTestGrid(createGridE); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + }); + + it('case 6', () => { + const cells = createTestGrid(createGridF); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + gridNav.advance(direction.Down); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + }); + }); + + describe('left', () => { + it('case 1', () => { + const cells = createTestGrid(createGridA); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 2', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 3', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 3}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 4', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 3}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 5', () => { + const cells = createTestGrid(createGridE); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + + it('case 6', () => { + const cells = createTestGrid(createGridF); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 2}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Left); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + }); + }); + + describe('right', () => { + it('case 1', () => { + const cells = createTestGrid(createGridA); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + }); + + it('case 2', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + }); + + it('case 3', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + }); + + it('case 4', () => { + const cells = createTestGrid(createGridD); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-3'); + }); + + it('case 5', () => { + const cells = createTestGrid(createGridE); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + }); + + it('case 6', () => { + const cells = createTestGrid(createGridF); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + rowWrap: signal('nowrap'), + colWrap: signal('nowrap'), + }); + + gridNav.gotoCoords({row: 0, col: 0}); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-0'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-1'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + gridNav.advance(direction.Right); + expect(gridFocus.activeCell()!.id()).toBe('cell-0-2'); + }); + }); + }); + }); + + describe('first/peekFirst', () => { + it('should navigate to the first focusable cell in the grid when softDisabled is false', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + + // Disable the first few cells to make it more interesting. + cells[0][0].disabled.set(true); + cells[0][1].disabled.set(true); + + const firstCoords = gridNav.peekFirst(); + expect(firstCoords).toEqual({row: 0, col: 2}); + + // The active cell should not have changed yet. + expect(gridFocus.activeCell()).toBeUndefined(); + + const result = gridNav.first(); + expect(result).toBe(true); + expect(gridFocus.activeCell()).toBe(cells[0][2]); + expect(gridFocus.activeCoords()).toEqual({row: 0, col: 2}); + }); + + it('should navigate to the first focusable cell in the grid', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells)); + + // Disable the first few cells to make it more interesting. + cells[0][0].disabled.set(true); + cells[0][1].disabled.set(true); + + const firstCoords = gridNav.peekFirst(); + expect(firstCoords).toEqual({row: 0, col: 0}); + + // The active cell should not have changed yet. + expect(gridFocus.activeCell()).toBeUndefined(); + + const result = gridNav.first(); + expect(result).toBe(true); + expect(gridFocus.activeCell()).toBe(cells[0][0]); + expect(gridFocus.activeCoords()).toEqual({row: 0, col: 0}); + }); + + it('should navigate to the first focusable cell in a specific row when softDisabled is false', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + + // Disable the first cell in row 1. + cells[1][0].disabled.set(true); + + const firstInRowCoords = gridNav.peekFirst(1); + expect(firstInRowCoords).toEqual({row: 1, col: 1}); + + // The active cell should not have changed yet. + expect(gridFocus.activeCell()).toBeUndefined(); + + const result = gridNav.first(1); + expect(result).toBe(true); + expect(gridFocus.activeCell()).toBe(cells[1][1]); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 1}); + }); + + it('should navigate to the first focusable cell in a specific row', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells)); + + // Disable the first cell in row 1. + cells[1][0].disabled.set(true); + + const firstInRowCoords = gridNav.peekFirst(1); + expect(firstInRowCoords).toEqual({row: 1, col: 0}); + + // The active cell should not have changed yet. + expect(gridFocus.activeCell()).toBeUndefined(); + + const result = gridNav.first(1); + expect(result).toBe(true); + expect(gridFocus.activeCell()).toBe(cells[1][0]); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 0}); + }); + + it('should get disabled cells when allowDisabled is true and softDisabled is false', () => { + const cells = createTestGrid(createGridA); + const {gridNav} = setupGridNavigation(signal(cells), {softDisabled: signal(false)}); + cells[0][0].disabled.set(true); + + const firstCoords = gridNav.peekFirst(undefined, true); + + expect(firstCoords).toEqual({row: 0, col: 0}); + expect(gridNav.peekFirst()).toEqual({row: 0, col: 1}); + }); + }); + + describe('last/peekLast', () => { + it('should navigate to the last focusable cell in the grid when softDisabled is false', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + + // Disable the last few cells to make it more interesting. + cells[3][1].disabled.set(true); // cell-3-2 + cells[3][0].disabled.set(true); // cell-3-1 + + const lastCoords = gridNav.peekLast(); + expect(lastCoords).toEqual({row: 3, col: 0}); + + // The active cell should not have changed yet. + expect(gridFocus.activeCell()).toBeUndefined(); + + const result = gridNav.last(); + expect(result).toBe(true); + expect(gridFocus.activeCell()!.id()).toBe('cell-2-0'); + expect(gridFocus.activeCoords()).toEqual({row: 3, col: 0}); + }); + + it('should navigate to the last focusable cell in the grid', () => { + const cells = createTestGrid(createGridB); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells)); + + // Disable the last few cells to make it more interesting. + cells[3][1].disabled.set(true); // cell-3-2 + cells[3][0].disabled.set(true); // cell-3-1 + + const lastCoords = gridNav.peekLast(); + expect(lastCoords).toEqual({row: 3, col: 2}); + + // The active cell should not have changed yet. + expect(gridFocus.activeCell()).toBeUndefined(); + + const result = gridNav.last(); + expect(result).toBe(true); + expect(gridFocus.activeCell()!.id()).toBe('cell-3-2'); + expect(gridFocus.activeCoords()).toEqual({row: 3, col: 2}); + }); + + it('should navigate to the last focusable cell in a specific row when softDisabled is false', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells), { + softDisabled: signal(false), + }); + + // Disable the last cell in row 1. + cells[1][2].disabled.set(true); + + const lastInRowCoords = gridNav.peekLast(1); + expect(lastInRowCoords).toEqual({row: 1, col: 2}); + + const result = gridNav.last(1); + expect(result).toBe(true); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-1'); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 2}); + }); + + it('should navigate to the last focusable cell in a specific row', () => { + const cells = createTestGrid(createGridC); + const {gridNav, gridFocus} = setupGridNavigation(signal(cells)); + + // Disable the last cell in row 1. + cells[1][2].disabled.set(true); + + const lastInRowCoords = gridNav.peekLast(1); + expect(lastInRowCoords).toEqual({row: 1, col: 3}); + + const result = gridNav.last(1); + expect(result).toBe(true); + expect(gridFocus.activeCell()!.id()).toBe('cell-1-3'); + expect(gridFocus.activeCoords()).toEqual({row: 1, col: 3}); + }); + + it('should get disabled cells when allowDisabled is true and softDisabled is false', () => { + const cells = createTestGrid(createGridA); + const {gridNav} = setupGridNavigation(signal(cells), {softDisabled: signal(false)}); + cells[2][2].disabled.set(true); + + const lastCoords = gridNav.peekLast(undefined, true); + + expect(lastCoords).toEqual({row: 2, col: 2}); + expect(gridNav.peekLast()).toEqual({row: 2, col: 1}); + }); + }); +}); diff --git a/src/aria/ui-patterns/behaviors/grid/grid-navigation.ts b/src/aria/private/behaviors/grid/grid-navigation.ts similarity index 83% rename from src/aria/ui-patterns/behaviors/grid/grid-navigation.ts rename to src/aria/private/behaviors/grid/grid-navigation.ts index 54426bf3ed7e..45fa7f84af21 100644 --- a/src/aria/ui-patterns/behaviors/grid/grid-navigation.ts +++ b/src/aria/private/behaviors/grid/grid-navigation.ts @@ -6,8 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed} from '@angular/core'; -import {SignalLike} from '../signal-like/signal-like'; +import {SignalLike, computed} from '../signal-like/signal-like'; import {GridFocus, GridFocusCell, GridFocusInputs} from './grid-focus'; import {GridData, RowCol} from './grid-data'; @@ -73,9 +72,14 @@ export class GridNavigation { /** * Gets the coordinates of the next focusable cell in a given direction, without changing focus. */ - peek(direction: Delta, fromCoords: RowCol, wrap?: WrapStrategy): RowCol | undefined { + peek( + direction: Delta, + fromCoords: RowCol, + wrap?: WrapStrategy, + allowDisabled?: boolean, + ): RowCol | undefined { wrap = wrap ?? (direction.row !== undefined ? this.inputs.rowWrap() : this.inputs.colWrap()); - return this._peekDirectional(direction, fromCoords, wrap); + return this._peekDirectional(direction, fromCoords, wrap, allowDisabled); } /** @@ -90,14 +94,14 @@ export class GridNavigation { * Gets the coordinates of the first focusable cell. * If a row is not provided, searches the entire grid. */ - peekFirst(row?: number): RowCol | undefined { + peekFirst(row?: number, allowDisabled?: boolean): RowCol | undefined { const fromCoords = { row: row ?? 0, col: -1, }; return row === undefined - ? this._peekDirectional(direction.Right, fromCoords, 'continuous') - : this._peekDirectional(direction.Right, fromCoords, 'nowrap'); + ? this._peekDirectional(direction.Right, fromCoords, 'continuous', allowDisabled) + : this._peekDirectional(direction.Right, fromCoords, 'nowrap', allowDisabled); } /** @@ -113,14 +117,14 @@ export class GridNavigation { * Gets the coordinates of the last focusable cell. * If a row is not provided, searches the entire grid. */ - peekLast(row?: number): RowCol | undefined { + peekLast(row?: number, allowDisabled?: boolean): RowCol | undefined { const fromCoords = { row: row ?? this.inputs.grid.maxRowCount() - 1, col: this.inputs.grid.maxColCount(), }; return row === undefined - ? this._peekDirectional(direction.Left, fromCoords, 'continuous') - : this._peekDirectional(direction.Left, fromCoords, 'nowrap'); + ? this._peekDirectional(direction.Left, fromCoords, 'continuous', allowDisabled) + : this._peekDirectional(direction.Left, fromCoords, 'nowrap', allowDisabled); } /** @@ -139,7 +143,10 @@ export class GridNavigation { delta: Delta, fromCoords: RowCol, wrap: 'continuous' | 'loop' | 'nowrap', + allowDisabled: boolean = false, ): RowCol | undefined { + if (this.inputs.gridFocus.gridDisabled()) return undefined; + const fromCell = this.inputs.grid.getCell(fromCoords); const maxRowCount = this.inputs.grid.maxRowCount(); const maxColCount = this.inputs.grid.maxColCount(); @@ -154,13 +161,19 @@ export class GridNavigation { nextCoords.row + rowDelta < 0 || nextCoords.row + rowDelta >= maxRowCount; - if (wrap === 'nowrap' && isWrapping) return; + if (wrap === 'nowrap' && isWrapping) return undefined; if (wrap === 'continuous') { const generalDelta = delta.row ?? delta.col; const rowStep = isWrapping ? generalDelta : rowDelta; const colStep = isWrapping ? generalDelta : colDelta; + // Reaching start or end. + const bothWrapping = + (nextCoords.row + rowStep >= maxRowCount && nextCoords.col + colStep >= maxColCount) || + (nextCoords.row + rowStep < 0 && nextCoords.col + colStep < 0); + if (bothWrapping) return undefined; + nextCoords = { row: (nextCoords.row + rowStep + maxRowCount) % maxRowCount, col: (nextCoords.col + colStep + maxColCount) % maxColCount, @@ -174,6 +187,13 @@ export class GridNavigation { }; } + if (wrap === 'nowrap') { + nextCoords = { + row: nextCoords.row + rowDelta, + col: nextCoords.col + colDelta, + }; + } + // Back to original coordinates. if (nextCoords.row === fromCoords.row && nextCoords.col === fromCoords.col) { return undefined; @@ -183,7 +203,7 @@ export class GridNavigation { if ( nextCell !== undefined && nextCell !== fromCell && - this.inputs.gridFocus.isFocusable(nextCell) + (allowDisabled || this.inputs.gridFocus.isFocusable(nextCell)) ) { return nextCoords; } diff --git a/src/aria/private/behaviors/grid/grid-selection.spec.ts b/src/aria/private/behaviors/grid/grid-selection.spec.ts new file mode 100644 index 000000000000..95d057e698e0 --- /dev/null +++ b/src/aria/private/behaviors/grid/grid-selection.spec.ts @@ -0,0 +1,303 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {signal, SignalLike, WritableSignalLike} from '../signal-like/signal-like'; +import {GridData} from './grid-data'; +import {createGridA, createGridB, createGridD, TestBaseGridCell} from './grid-data.spec'; +import {GridFocus, GridFocusInputs} from './grid-focus'; +import {GridSelection, GridSelectionInputs} from './grid-selection'; + +export interface TestGridSelectionCell extends TestBaseGridCell { + element: WritableSignalLike; + disabled: WritableSignalLike; + selected: WritableSignalLike; + selectable: WritableSignalLike; +} + +function createTestCell(): Omit { + return { + element: signal(document.createElement('div')), + disabled: signal(false), + selected: signal(false), + selectable: signal(true), + }; +} + +function createTestGrid(createGridFn: () => TestBaseGridCell[][]): TestGridSelectionCell[][] { + return createGridFn().map(row => + row.map(cell => { + return {...createTestCell(), ...cell}; + }), + ); +} + +function setupGridSelection( + cells: SignalLike, + inputs: Partial = {}, +): { + gridSelection: GridSelection; + gridFocus: GridFocus; +} { + const gridData = new GridData({cells}); + const gridFocusInputs: GridFocusInputs = { + focusMode: signal('roving'), + disabled: signal(false), + softDisabled: signal(true), + }; + const gridFocus = new GridFocus({ + grid: gridData, + ...gridFocusInputs, + ...inputs, + }); + + const gridSelection = new GridSelection({ + grid: gridData, + gridFocus: gridFocus, + ...gridFocusInputs, + ...inputs, + }); + + return {gridSelection, gridFocus}; +} + +describe('GridSelection', () => { + describe('select', () => { + it('should select a single cell', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + + gridSelection.select({row: 1, col: 1}); + + expect(cells[1][1].selected()).toBe(true); + }); + + it('should select a range of cells', () => { + const cells = createTestGrid(createGridD); + const {gridSelection} = setupGridSelection(signal(cells)); + + gridSelection.select({row: 0, col: 0}, {row: 1, col: 1}); + + expect(cells[0][0].selected()).toBe(true); // Spans {0,0}, {1,0} + expect(cells[0][1].selected()).toBe(true); // Spans {0,1}, {0,2} + expect(cells[1][0].selected()).toBe(true); // Spans {1,1}, {1,2}, {2,1}, {2,2} + }); + + it('should not select disabled or unselectable cells', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + + cells[0][1].disabled.set(true); + cells[1][0].selectable.set(false); + + gridSelection.select({row: 0, col: 0}, {row: 1, col: 1}); + + expect(cells[0][0].selected()).toBe(true); + expect(cells[0][1].selected()).toBe(false); + expect(cells[1][0].selected()).toBe(false); + expect(cells[1][1].selected()).toBe(true); + }); + }); + + describe('deselect', () => { + it('should deselect a single cell', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + cells[1][1].selected.set(true); + + gridSelection.deselect({row: 1, col: 1}); + + expect(cells[1][1].selected()).toBe(false); + }); + + it('should deselect a range of cells', () => { + const cells = createTestGrid(createGridD); + const {gridSelection} = setupGridSelection(signal(cells)); + cells[0][0].selected.set(true); + cells[0][1].selected.set(true); + cells[1][0].selected.set(true); + + gridSelection.deselect({row: 0, col: 0}, {row: 1, col: 1}); + + expect(cells[0][0].selected()).toBe(false); + expect(cells[0][1].selected()).toBe(false); + expect(cells[1][0].selected()).toBe(false); + }); + }); + + describe('toggle', () => { + it('should toggle the selection of a single cell', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + + gridSelection.toggle({row: 1, col: 1}); + expect(cells[1][1].selected()).toBe(true); + + gridSelection.toggle({row: 1, col: 1}); + expect(cells[1][1].selected()).toBe(false); + }); + + it('should toggle a range of cells', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + cells[0][0].selected.set(true); + cells[1][1].selected.set(true); + + gridSelection.toggle({row: 0, col: 0}, {row: 0, col: 1}); + + expect(cells[0][0].selected()).toBe(false); + expect(cells[0][1].selected()).toBe(true); + expect(cells[1][1].selected()).toBe(true); // Unchanged + }); + }); + + describe('selectAll', () => { + it('should select all selectable and enabled cells', () => { + const cells = createTestGrid(createGridB); + const {gridSelection} = setupGridSelection(signal(cells)); + + cells[0][1].disabled.set(true); + cells[1][1].selectable.set(false); + + gridSelection.selectAll(); + + const flatCells = cells.flat(); + expect(flatCells.filter(c => c.selected()).length).toBe(flatCells.length - 2); + expect(cells[0][1].selected()).toBe(false); + expect(cells[1][1].selected()).toBe(false); + }); + }); + + describe('deselectAll', () => { + it('should deselect all cells', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + + // Select some cells + cells[0][0].selected.set(true); + cells[1][1].selected.set(true); + cells[2][2].selected.set(true); + + gridSelection.deselectAll(); + + const flatCells = cells.flat(); + expect(flatCells.every(c => !c.selected())).toBe(true); + }); + }); + + describe('_validCells', () => { + it('should yield all selectable and enabled cells in a range', () => { + const cells = createTestGrid(createGridD); + const {gridSelection} = setupGridSelection(signal(cells)); + + cells[0][1].disabled.set(true); // cell-0-1 + cells[1][0].selectable.set(false); // cell-1-1 + + const validCells = Array.from(gridSelection._validCells({row: 0, col: 0}, {row: 3, col: 3})); + + const validCellIds = validCells.map(c => c.id()); + const allCellIds = cells.flat().map(c => c.id()); + + expect(validCellIds).not.toContain('cell-0-1'); + expect(validCellIds).not.toContain('cell-1-1'); + expect(validCellIds.length).toBe(allCellIds.length - 2); + }); + }); + + describe('undo', () => { + it('should undo a select operation', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + + gridSelection.select({row: 1, col: 1}); + expect(cells[1][1].selected()).toBe(true); + + gridSelection.undo(); + expect(cells[1][1].selected()).toBe(false); + }); + + it('should undo a deselect operation', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + cells[1][1].selected.set(true); + + gridSelection.deselect({row: 1, col: 1}); + expect(cells[1][1].selected()).toBe(false); + + gridSelection.undo(); + expect(cells[1][1].selected()).toBe(true); + }); + + it('should undo a toggle operation', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + cells[0][0].selected.set(true); + + gridSelection.toggle({row: 0, col: 0}, {row: 0, col: 1}); + expect(cells[0][0].selected()).toBe(false); + expect(cells[0][1].selected()).toBe(true); + + gridSelection.undo(); + expect(cells[0][0].selected()).toBe(true); + expect(cells[0][1].selected()).toBe(false); + }); + + it('should undo a selectAll operation', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + + gridSelection.selectAll(); + expect(cells.flat().every(c => c.selected())).toBe(true); + + gridSelection.undo(); + expect(cells.flat().every(c => !c.selected())).toBe(true); + }); + + it('should undo a deselectAll operation', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + cells.flat().forEach(c => c.selected.set(true)); + + gridSelection.deselectAll(); + expect(cells.flat().every(c => !c.selected())).toBe(true); + + gridSelection.undo(); + expect(cells.flat().every(c => c.selected())).toBe(true); + }); + + it('should do nothing if there is nothing to undo', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + cells[1][1].selected.set(true); + + gridSelection.undo(); + expect(cells[1][1].selected()).toBe(true); + }); + + it('should only undo the last operation', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + + gridSelection.select({row: 0, col: 0}); + gridSelection.select({row: 1, col: 1}); + expect(cells[1][1].selected()).toBe(true); + + gridSelection.undo(); + expect(cells[0][0].selected()).toBe(true); + expect(cells[1][1].selected()).toBe(false); + }); + + it('should do nothing after undoing once', () => { + const cells = createTestGrid(createGridA); + const {gridSelection} = setupGridSelection(signal(cells)); + gridSelection.select({row: 1, col: 1}); + gridSelection.undo(); + gridSelection.undo(); + expect(cells[1][1].selected()).toBe(false); + }); + }); +}); diff --git a/src/aria/ui-patterns/behaviors/grid/grid-selection.ts b/src/aria/private/behaviors/grid/grid-selection.ts similarity index 63% rename from src/aria/ui-patterns/behaviors/grid/grid-selection.ts rename to src/aria/private/behaviors/grid/grid-selection.ts index b7f548f91ad7..70f9d4076988 100644 --- a/src/aria/ui-patterns/behaviors/grid/grid-selection.ts +++ b/src/aria/private/behaviors/grid/grid-selection.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.dev/license */ -import {SignalLike, WritableSignalLike} from '../signal-like/signal-like'; import {GridFocus, GridFocusCell, GridFocusInputs} from './grid-focus'; import {GridData, RowCol} from './grid-data'; +import {SignalLike, WritableSignalLike, signal} from '../signal-like/signal-like'; /** Represents a cell in a grid that can be selected. */ export interface GridSelectionCell extends GridFocusCell { @@ -33,50 +33,58 @@ interface GridSelectionDeps { /** Controls selection for a grid of items. */ export class GridSelection { + /** The list of cells that were changed in the last selection operation. */ + private readonly _undoList: WritableSignalLike<[T, boolean][]> = signal([]); + constructor(readonly inputs: GridSelectionInputs & GridSelectionDeps) {} + /** Reverts the last selection change. */ + undo(): void { + for (const [cell, oldState] of this._undoList()) { + cell.selected.set(oldState); + } + this._undoList.set([]); + } + /** Selects one or more cells in a given range. */ select(fromCoords: RowCol, toCoords?: RowCol): void { - for (const cell of this._validCells(fromCoords, toCoords ?? fromCoords)) { - cell.selected.set(true); - } + this._updateState(fromCoords, toCoords ?? fromCoords, () => true); } /** Deselects one or more cells in a given range. */ deselect(fromCoords: RowCol, toCoords?: RowCol): void { - for (const cell of this._validCells(fromCoords, toCoords ?? fromCoords)) { - cell.selected.set(false); - } + this._updateState(fromCoords, toCoords ?? fromCoords, () => false); } /** Toggles the selection state of one or more cells in a given range. */ toggle(fromCoords: RowCol, toCoords?: RowCol): void { - for (const cell of this._validCells(fromCoords, toCoords ?? fromCoords)) { - cell.selected.update(state => !state); - } + this._updateState(fromCoords, toCoords ?? fromCoords, oldState => !oldState); } /** Selects all valid cells in the grid. */ selectAll(): void { - for (const cell of this._validCells( + this._updateState( {row: 0, col: 0}, {row: this.inputs.grid.maxRowCount(), col: this.inputs.grid.maxColCount()}, - )) { - cell.selected.set(true); - } + () => true, + ); } /** Deselects all valid cells in the grid. */ deselectAll(): void { - for (const cell of this._validCells( + this._updateState( {row: 0, col: 0}, {row: this.inputs.grid.maxRowCount(), col: this.inputs.grid.maxColCount()}, - )) { - cell.selected.set(false); - } + () => false, + ); + } + + /** Whether a cell is selctable. */ + isSelectable(cell: T) { + return cell.selectable() && !cell.disabled(); } - /** A generator that yields all valid (selectable and not disabled) cells within a given range. */ + /** A generator that yields all cells within a given range. */ *_validCells(fromCoords: RowCol, toCoords: RowCol): Generator { const startRow = Math.min(fromCoords.row, toCoords.row); const startCol = Math.min(fromCoords.col, toCoords.col); @@ -87,12 +95,29 @@ export class GridSelection { for (let col = startCol; col < endCol + 1; col++) { const cell = this.inputs.grid.getCell({row, col}); if (cell === undefined) continue; - if (!cell.selectable()) continue; - if (cell.disabled()) continue; + if (!this.isSelectable(cell)) continue; if (visited.has(cell)) continue; visited.add(cell); yield cell; } } } + + /** + * Updates the selection state of cells in a given range and preserves previous changes + * to a undo list. + */ + private _updateState( + fromCoords: RowCol, + toCoords: RowCol, + stateFn: (oldState: boolean) => boolean, + ): void { + const undoList: [T, boolean][] = []; + for (const cell of this._validCells(fromCoords, toCoords)) { + const oldState = cell.selected(); + undoList.push([cell, oldState]); + cell.selected.set(stateFn(oldState)); + } + this._undoList.set(undoList); + } } diff --git a/src/aria/private/behaviors/grid/grid.spec.ts b/src/aria/private/behaviors/grid/grid.spec.ts new file mode 100644 index 000000000000..8db7756e7728 --- /dev/null +++ b/src/aria/private/behaviors/grid/grid.spec.ts @@ -0,0 +1,423 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {signal, SignalLike, WritableSignalLike} from '../signal-like/signal-like'; +import {Grid, GridInputs} from './grid'; +import {createGridA, createGridD, TestBaseGridCell} from './grid-data.spec'; +import {WrapStrategy} from './grid-navigation'; + +interface TestGridCell extends TestBaseGridCell { + element: WritableSignalLike; + disabled: WritableSignalLike; + selected: WritableSignalLike; + selectable: WritableSignalLike; +} + +function createTestCell(): Omit { + return { + element: signal(document.createElement('div')), + disabled: signal(false), + selected: signal(false), + selectable: signal(true), + }; +} + +function createTestGrid(createGridFn: () => TestBaseGridCell[][]): TestGridCell[][] { + return createGridFn().map(row => + row.map(cell => { + return {...createTestCell(), ...cell}; + }), + ); +} + +function setupGrid( + cells: SignalLike, + inputs: Partial> = {}, +): Grid { + const gridInputs: GridInputs = { + cells, + focusMode: signal('roving'), + disabled: signal(false), + softDisabled: signal(true), + rowWrap: signal('loop'), + colWrap: signal('loop'), + ...inputs, + }; + + return new Grid(gridInputs); +} + +describe('Grid', () => { + describe('indices', () => { + it('should return 1-based row and column indices', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + + expect(grid.rowIndex(cells[1][2])).toBe(2); + expect(grid.colIndex(cells[1][2])).toBe(3); + }); + + it('should return undefined for a cell not in the grid', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + const otherCell = createTestGrid(createGridA)[0][0]; + + expect(grid.rowIndex(otherCell)).toBeUndefined(); + expect(grid.colIndex(otherCell)).toBeUndefined(); + }); + }); + + describe('cellTabIndex', () => { + it('should return the tab index for a cell', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + + grid.gotoCell(cells[1][1]); + + expect(grid.cellTabIndex(cells[1][1])).toBe(0); + expect(grid.cellTabIndex(cells[0][0])).toBe(-1); + }); + }); + + describe('navigation', () => { + let cells: TestGridCell[][]; + let grid: Grid; + + beforeEach(() => { + cells = createTestGrid(createGridA); + grid = setupGrid(signal(cells)); + grid.gotoCell(cells[1][1]); + }); + + it('should navigate up/down/left/right', () => { + expect(grid.focusBehavior.activeCell()).toBe(cells[1][1]); + grid.up(); + expect(grid.focusBehavior.activeCell()).toBe(cells[0][1]); + grid.down(); + expect(grid.focusBehavior.activeCell()).toBe(cells[1][1]); + grid.left(); + expect(grid.focusBehavior.activeCell()).toBe(cells[1][0]); + grid.right(); + expect(grid.focusBehavior.activeCell()).toBe(cells[1][1]); + }); + + it('should navigate to first/last cell in grid', () => { + grid.last(); + expect(grid.focusBehavior.activeCell()).toBe(cells[2][2]); + grid.first(); + expect(grid.focusBehavior.activeCell()).toBe(cells[0][0]); + }); + + it('should navigate to first/last cell in row', () => { + grid.lastInRow(); + expect(grid.focusBehavior.activeCell()).toBe(cells[1][2]); + grid.firstInRow(); + expect(grid.focusBehavior.activeCell()).toBe(cells[1][0]); + }); + + describe('with selection', () => { + it('should select one on navigate when `selectOne` is true', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[0][0]); + grid.select(); // cell 0,0 is selected + + grid.down({selectOne: true}); + + expect(cells[0][0].selected()).toBe(false); + expect(cells[1][0].selected()).toBe(true); + expect(grid.focusBehavior.activeCell()).toBe(cells[1][0]); + }); + + it('should select on navigate when `select` is true', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[0][0]); + grid.select(); // cell 0,0 is selected + + grid.down({select: true}); + + expect(cells[0][0].selected()).toBe(true); + expect(cells[1][0].selected()).toBe(true); + expect(grid.focusBehavior.activeCell()).toBe(cells[1][0]); + }); + + it('should toggle on navigate when `toggle` is true', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[0][0]); + + grid.down({toggle: true}); // Move to 1,0 and select it + expect(cells[1][0].selected()).toBe(true); + + grid.up({toggle: true}); // Move to 0,0 and select it + expect(cells[0][0].selected()).toBe(true); + expect(cells[1][0].selected()).toBe(true); // 1,0 remains selected + + grid.down({toggle: true}); // Move to 1,0 and deselect it + expect(cells[1][0].selected()).toBe(false); + }); + + it('should toggle one on navigate when `toggleOne` is true', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[0][0]); + grid.select(); // cell 0,0 is selected + + grid.down({toggleOne: true}); // Move to 1,0 + + expect(cells[0][0].selected()).toBe(false); + expect(cells[1][0].selected()).toBe(true); + + grid.down({toggleOne: true}); // Move to 2,0 + expect(cells[1][0].selected()).toBe(false); + expect(cells[2][0].selected()).toBe(true); + }); + + it('should range select on navigate when `anchor` is true', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[1][1]); + grid.down({anchor: true}); + expect(cells.flat().filter(c => c.selected()).length).toBe(2); + expect(cells[1][1].selected()).toBe(true); + expect(cells[2][1].selected()).toBe(true); + }); + }); + }); + + describe('selection', () => { + describe('selectRow', () => { + it('should select all cells in the current row', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[0][0]); + grid.select(); + expect(cells[0][0].selected()).toBe(true); + + grid.gotoCell(cells[1][1]); + grid.selectRow(); + + expect(cells[0][0].selected()).toBe(false); + expect(cells[1][0].selected()).toBe(true); + expect(cells[1][1].selected()).toBe(true); + expect(cells[1][2].selected()).toBe(true); + expect(cells[2][0].selected()).toBe(false); + }); + }); + + describe('selectCol', () => { + it('should select all cells in the current column', () => { + const cells = createTestGrid(createGridD); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[0][0]); + grid.selectCol(); + + expect(cells[0][0].selected()).toBe(true); // spans row 0 and 1 in col 0 + expect(cells[2][0].selected()).toBe(true); + expect(cells[3][0].selected()).toBe(true); + expect(cells[0][1].selected()).toBe(false); + }); + }); + + describe('select', () => { + it('should select the active cell', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[1][1]); + grid.select(); + + expect(cells[1][1].selected()).toBe(true); + expect(cells[0][0].selected()).toBe(false); + }); + }); + + describe('deselect', () => { + it('should deselect the active cell', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[1][1]); + grid.select(); + expect(cells[1][1].selected()).toBe(true); + + grid.deselect(); + expect(cells[1][1].selected()).toBe(false); + }); + }); + + describe('toggle', () => { + it('should toggle the selection of the active cell', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[1][1]); + + grid.toggle(); + expect(cells[1][1].selected()).toBe(true); + + grid.toggle(); + expect(cells[1][1].selected()).toBe(false); + }); + }); + + describe('toggleOne', () => { + it('should toggle the selection of the active cell and deselect others', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + grid.gotoCell(cells[0][0]); + grid.select(); + + grid.gotoCell(cells[1][1]); + grid.toggleOne(); + + expect(cells[0][0].selected()).toBe(false); + expect(cells[1][1].selected()).toBe(true); + + grid.toggleOne(); + expect(cells[1][1].selected()).toBe(false); + }); + }); + + describe('selectAll', () => { + it('should select all selectable cells', () => { + const cells = createTestGrid(createGridA); + cells[1][1].selectable.set(false); + const grid = setupGrid(signal(cells)); + grid.selectAll(); + + expect(cells.flat().filter(c => c.selected()).length).toBe(8); + expect(cells[1][1].selected()).toBe(false); + }); + }); + }); + + describe('setDefaultState', () => { + it('should focus the first focusable selected cell if one exists', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells), {softDisabled: signal(false)}); + + // This one is selected but not focusable. + cells[1][1].selected.set(true); + cells[1][1].disabled.set(true); + + // This is the first focusable selected cell. + cells[2][0].selected.set(true); + + // This one is also focusable and selected, but comes after. + cells[2][2].selected.set(true); + + const result = grid.setDefaultState(); + + expect(result).toBe(true); + expect(grid.focusBehavior.activeCell()).toBe(cells[2][0]); + }); + + it('should focus the first focusable cell if no selected cell exists', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells), {softDisabled: signal(false)}); + + cells[0][0].disabled.set(true); + + const result = grid.setDefaultState(); + + expect(result).toBe(true); + expect(grid.focusBehavior.activeCell()).toBe(cells[0][1]); + }); + + it('should return false if no focusable cell is found', () => { + const cells = createTestGrid(createGridA); + cells.flat().forEach(c => c.disabled.set(true)); + const grid = setupGrid(signal(cells), {softDisabled: signal(false)}); + + const result = grid.setDefaultState(); + + expect(result).toBe(false); + expect(grid.focusBehavior.activeCell()).toBeUndefined(); + }); + }); + + describe('resetState', () => { + it('should focus the first focusable cell if state is empty', () => { + const cells = createTestGrid(createGridA); + const grid = setupGrid(signal(cells)); + + expect(grid.focusBehavior.stateEmpty()).toBe(true); + const result = grid.resetState(); + expect(result).toBe(true); + expect(grid.focusBehavior.activeCell()).toBe(cells[0][0]); + }); + + it('should return false if no focusable cell is found when state is empty', () => { + const cells = createTestGrid(createGridA); + cells.flat().forEach(c => c.disabled.set(true)); + const grid = setupGrid(signal(cells)); + + const result = grid.resetState(); + expect(result).toBe(false); + expect(grid.focusBehavior.activeCell()).toBeUndefined(); + }); + + it('should re-focus the active cell if it is stale but still exists', () => { + const cellsSignal = signal(createTestGrid(createGridA)); + const grid = setupGrid(cellsSignal); + const originalCell = cellsSignal()[1][1]; + grid.gotoCell(originalCell); + + // Simulate reordering by creating a new grid but keeping the original cell instance + const newCells = createTestGrid(createGridA); + newCells[2][2] = originalCell; + cellsSignal.set(newCells); + + expect(grid.focusBehavior.stateStale()).toBe(true); + const result = grid.resetState(); + expect(result).toBe(true); + expect(grid.focusBehavior.activeCell()).toBe(originalCell); + expect(grid.focusBehavior.activeCoords()).toEqual({row: 2, col: 2}); + }); + + it('should focus the original coordinates if the active cell is gone', () => { + const cellsSignal = signal(createTestGrid(createGridA)); + const grid = setupGrid(cellsSignal); + grid.gotoCell(cellsSignal()[1][1]); + + // Replace the cell at {1,1} + const newCells = createTestGrid(createGridA); + cellsSignal.set(newCells); + + expect(grid.focusBehavior.stateStale()).toBe(true); + const result = grid.resetState(); + expect(result).toBe(true); + expect(grid.focusBehavior.activeCell()).toBe(newCells[1][1]); + expect(grid.focusBehavior.activeCoords()).toEqual({row: 1, col: 1}); + }); + + it('should focus the first cell if active cell and coords are no longer valid', () => { + const cellsSignal = signal(createTestGrid(createGridA)); + const grid = setupGrid(cellsSignal); + grid.gotoCell(cellsSignal()[2][2]); + + // Make grid smaller + const newCells: TestGridCell[][] = [ + [ + {...createTestCell(), id: signal('cell-0-0'), rowSpan: signal(1), colSpan: signal(1)}, + {...createTestCell(), id: signal('cell-0-1'), rowSpan: signal(1), colSpan: signal(1)}, + ], + [ + {...createTestCell(), id: signal('cell-1-0'), rowSpan: signal(1), colSpan: signal(1)}, + {...createTestCell(), id: signal('cell-1-1'), rowSpan: signal(1), colSpan: signal(1)}, + ], + ]; + cellsSignal.set(newCells); + + expect(grid.focusBehavior.stateStale()).toBe(true); + const result = grid.resetState(); + expect(result).toBe(true); + expect(grid.focusBehavior.activeCell()).toBe(newCells[0][0]); + expect(grid.focusBehavior.activeCoords()).toEqual({row: 0, col: 0}); + }); + }); +}); diff --git a/src/aria/private/behaviors/grid/grid.ts b/src/aria/private/behaviors/grid/grid.ts new file mode 100644 index 000000000000..6d0316395d38 --- /dev/null +++ b/src/aria/private/behaviors/grid/grid.ts @@ -0,0 +1,419 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {GridData, BaseGridCell, GridDataInputs, RowCol} from './grid-data'; +import {GridFocus, GridFocusCell, GridFocusInputs} from './grid-focus'; +import { + direction, + GridNavigation, + GridNavigationCell, + GridNavigationInputs, +} from './grid-navigation'; +import {GridSelectionCell, GridSelectionInputs, GridSelection} from './grid-selection'; +import {computed, linkedSignal, signal, SignalLike} from '../signal-like/signal-like'; + +/** The selection operations that can be performed after a navigation operation. */ +export interface NavOptions { + /** Toggles the selection state of the active cell. */ + toggle?: boolean; + + /** + * Toggles the selection state of the active cell, and deselects all other cells if the + * active cell is selected. If the active cell is the only selected cell, it will be deselected. + */ + toggleOne?: boolean; + + /** Selects the active cell, preserving the selection state of other cells. */ + select?: boolean; + + /** Deselects all other cells and selects the active cell. */ + selectOne?: boolean; + + /** + * Moves the selection anchor to the active cell and updates the selection to include all + * cells between the anchor and the active cell. + */ + anchor?: boolean; +} + +/** A type that represents a cell in a grid, combining all cell-related interfaces. */ +export type GridCell = BaseGridCell & GridFocusCell & GridNavigationCell & GridSelectionCell; + +/** Represents the required inputs for a grid. */ +export type GridInputs = GridDataInputs & + GridFocusInputs & + GridNavigationInputs & + GridSelectionInputs; + +/** The main class that orchestrates the grid behaviors. */ +export class Grid { + /** The underlying data structure for the grid. */ + readonly data: GridData; + + /** Controls focus for the grid. */ + readonly focusBehavior: GridFocus; + + /** Controls navigation for the grid. */ + readonly navigationBehavior: GridNavigation; + + /** Controls selection for the grid. */ + readonly selectionBehavior: GridSelection; + + /** The anchor point for range selection, linked to the active coordinates. */ + readonly selectionAnchor = linkedSignal(() => this.focusBehavior.activeCoords()); + + /** The cell at the selection anchor. */ + readonly selectionAnchorCell = computed(() => this.data.getCell(this.selectionAnchor())); + + /** Whether a range selection has settled. */ + readonly selectionStabled = signal(true); + + /** Whether all selectable cells are selected. */ + readonly allSelected: SignalLike = computed(() => + this.data + .cells() + .flat() + .filter(c => this.selectionBehavior.isSelectable(c)) + .every(c => c.selected()), + ); + + /** The tab index for the grid container. */ + readonly gridTabIndex: SignalLike<-1 | 0> = () => this.focusBehavior.gridTabIndex(); + + /** Whether the grid is in a disabled state. */ + readonly gridDisabled: SignalLike = () => this.focusBehavior.gridDisabled(); + + /** The ID of the active descendant for ARIA `activedescendant` focus management. */ + readonly activeDescendant: SignalLike = () => + this.focusBehavior.activeDescendant(); + + constructor(readonly inputs: GridInputs) { + this.data = new GridData(inputs); + this.focusBehavior = new GridFocus({...inputs, grid: this.data}); + this.navigationBehavior = new GridNavigation({ + ...inputs, + grid: this.data, + gridFocus: this.focusBehavior, + }); + this.selectionBehavior = new GridSelection({ + ...inputs, + grid: this.data, + gridFocus: this.focusBehavior, + }); + } + + /** Gets the 1-based row index of a cell. */ + rowIndex(cell: T): number | undefined { + const index = this.data.getCoords(cell)?.row; + return index !== undefined ? index + 1 : undefined; + } + + /** Gets the 1-based column index of a cell. */ + colIndex(cell: T): number | undefined { + const index = this.data.getCoords(cell)?.col; + return index !== undefined ? index + 1 : undefined; + } + + /** Gets the tab index for a given cell. */ + cellTabIndex(cell: T): -1 | 0 { + return this.focusBehavior.getCellTabIndex(cell); + } + + /** Navigates to the cell above the currently active cell. */ + up(opts: NavOptions = {}): boolean { + return this._navigateWithSelection( + () => + opts.anchor + ? this._updateSelectionAnchor(() => + this.navigationBehavior.peek(direction.Up, this.selectionAnchor(), 'nowrap', true), + ) + : this.navigationBehavior.advance(direction.Up), + opts, + ); + } + + /** Navigates to the cell below the currently active cell. */ + down(opts: NavOptions = {}): boolean { + return this._navigateWithSelection( + () => + opts.anchor + ? this._updateSelectionAnchor(() => + this.navigationBehavior.peek(direction.Down, this.selectionAnchor(), 'nowrap', true), + ) + : this.navigationBehavior.advance(direction.Down), + opts, + ); + } + + /** Navigates to the cell to the left of the currently active cell. */ + left(opts: NavOptions = {}): boolean { + return this._navigateWithSelection( + () => + opts.anchor + ? this._updateSelectionAnchor(() => + this.navigationBehavior.peek(direction.Left, this.selectionAnchor(), 'nowrap', true), + ) + : this.navigationBehavior.advance(direction.Left), + opts, + ); + } + + /** Navigates to the cell to the right of the currently active cell. */ + right(opts: NavOptions = {}): boolean { + return this._navigateWithSelection( + () => + opts.anchor + ? this._updateSelectionAnchor(() => + this.navigationBehavior.peek(direction.Right, this.selectionAnchor(), 'nowrap', true), + ) + : this.navigationBehavior.advance(direction.Right), + opts, + ); + } + + /** Navigates to the first focusable cell in the grid. */ + first(opts: NavOptions = {}): boolean { + return this._navigateWithSelection( + () => + opts.anchor + ? this._updateSelectionAnchor(() => this.navigationBehavior.peekFirst(undefined, true)) + : this.navigationBehavior.first(), + opts, + ); + } + + /** Navigates to the first focusable cell in the current row. */ + firstInRow(opts: NavOptions = {}): boolean { + const row = this.focusBehavior.activeCoords().row; + return this._navigateWithSelection( + () => + opts.anchor + ? this._updateSelectionAnchor(() => this.navigationBehavior.peekFirst(row, true)) + : this.navigationBehavior.first(row), + opts, + ); + } + + /** Navigates to the last focusable cell in the grid. */ + last(opts: NavOptions = {}): boolean { + return this._navigateWithSelection( + () => + opts.anchor + ? this._updateSelectionAnchor(() => this.navigationBehavior.peekLast(undefined, true)) + : this.navigationBehavior.last(), + opts, + ); + } + + /** Navigates to the last focusable cell in the current row. */ + lastInRow(opts: NavOptions = {}): boolean { + const row = this.focusBehavior.activeCoords().row; + return this._navigateWithSelection( + () => + opts.anchor + ? this._updateSelectionAnchor(() => this.navigationBehavior.peekLast(row, true)) + : this.navigationBehavior.last(row), + opts, + ); + } + + /** Selects all cells in the current row. */ + selectRow(): void { + const row = this.focusBehavior.activeCoords().row; + this.selectionBehavior.deselectAll(); + this.selectionBehavior.select({row, col: 0}, {row, col: this.data.maxColCount()}); + } + + /** Selects all cells in the current column. */ + selectCol(): void { + const col = this.focusBehavior.activeCoords().col; + this.selectionBehavior.deselectAll(); + this.selectionBehavior.select({row: 0, col}, {row: this.data.maxRowCount(), col}); + } + + /** Selects the active cell. */ + select(): void { + this.selectionBehavior.select(this.focusBehavior.activeCoords()); + } + + /** Deselects the active cell. */ + deselect(): void { + this.selectionBehavior.deselect(this.focusBehavior.activeCoords()); + } + + /** + * Toggles the selection state of the coordinates of the given cell + * or the current active coordinates. + */ + toggle(): void { + this.selectionBehavior.toggle(this.focusBehavior.activeCoords()); + } + + /** Toggles the selection state of the active cell, and deselects all other cells. */ + toggleOne(): void { + const selected = !!this.focusBehavior.activeCell()?.selected(); + if (selected) { + this.deselect(); + return; + } + + this.deselectAll(); + this.select(); + } + + /** Selects all selectable cells in the grid. */ + selectAll(): void { + this.selectionBehavior.selectAll(); + } + + /** Deselects all cells in the grid. */ + deselectAll(): void { + this.selectionBehavior.deselectAll(); + } + + /** Navigates to and focuses the given cell. */ + gotoCell(cell: T, opts: NavOptions = {}): boolean { + return this._navigateWithSelection( + () => + opts.anchor + ? this._updateSelectionAnchor(() => this.data.getCoords(cell)) + : this.navigationBehavior.gotoCell(cell), + opts, + ); + } + + /** Sets the default active state of the grid. */ + setDefaultState(): boolean { + // Try to find a selected cell that's focusable. + const focusableSelectedCell: T | undefined = this.data + .cells() + .flat() + .filter(c => this.focusBehavior.isFocusable(c)) + .find(c => c.selected()); + + if (focusableSelectedCell !== undefined) { + this.focusBehavior.focusCell(focusableSelectedCell); + return true; + } + + // Otherwise find the first focusable cell. + const firstFocusableCoords = this.navigationBehavior.peekFirst(); + + if (firstFocusableCoords !== undefined) { + return this.focusBehavior.focusCoordinates(firstFocusableCoords); + } + + return false; + } + + /** Resets the active state of the grid if it is empty or stale. */ + resetState(): boolean { + if (this.focusBehavior.stateEmpty()) { + return this.setDefaultState(); + } + + if (this.focusBehavior.stateStale()) { + // Try focus on the same active cell after if a reordering happened. + if (this.focusBehavior.focusCell(this.focusBehavior.activeCell()!)) { + return true; + } + + // If the active cell is no longer exist, focus on the coordinates instead. + if (this.focusBehavior.focusCoordinates(this.focusBehavior.activeCoords())) { + return true; + } + + // If the coordinates no longer valid, go back to the first available cell. + if (this.focusBehavior.focusCoordinates(this.navigationBehavior.peekFirst()!)) { + return true; + } + } + + return false; + } + + /** Updates the selection anchor to the given coordinates. */ + private _updateSelectionAnchor(peekFn: () => RowCol | undefined): boolean { + const coords = peekFn(); + const success = coords !== undefined; + if (!success) return false; + this.selectionAnchor.set(coords); + return success; + } + + /** Updates the selection to include all cells between the anchor and the active cell. */ + private _updateRangeSelection(): void { + if (!this.selectionStabled()) { + this.selectionBehavior.undo(); + } + this.selectionBehavior.select( + ...this._getSelectionCoords(this.focusBehavior.activeCoords(), this.selectionAnchor()), + ); + } + + /** Gets the start and end coordinates for a selection range. */ + private _getSelectionCoords(startCoords: RowCol, endCoords: RowCol): [RowCol, RowCol] { + const startCell = this.data.getCell(startCoords)!; + const endCell = this.data.getCell(endCoords)!; + const allCoords = [...this.data.getAllCoords(startCell)!, ...this.data.getAllCoords(endCell)!]; + const allRows = allCoords.map(c => c.row); + const allCols = allCoords.map(c => c.col); + const fromCoords = { + row: Math.min(...allRows), + col: Math.min(...allCols), + }; + const toCoords = { + row: Math.max(...allRows), + col: Math.max(...allCols), + }; + + return [fromCoords, toCoords]; + } + + /** Executes a navigation operation and applies selection options. */ + private _navigateWithSelection(op: () => boolean, opts: NavOptions = {}): boolean { + const success = op(); + if (!success) return false; + + if (opts.anchor) { + this._updateRangeSelection(); + this.selectionStabled.set(false); + return success; + } + + // Selection becomes stable after the active cell/coords moved. + this.selectionStabled.set(true); + + if (opts.select) { + this.select(); + return success; + } + + if (opts.selectOne) { + this.deselectAll(); + this.select(); + return success; + } + + if (opts.toggle) { + this.toggle(); + return success; + } + + if (opts.toggleOne) { + const selected = !!this.focusBehavior.activeCell()?.selected(); + this.deselectAll(); + if (!selected) { + this.select(); + } + return success; + } + + return success; + } +} diff --git a/src/aria/ui-patterns/behaviors/grid/index.ts b/src/aria/private/behaviors/grid/index.ts similarity index 100% rename from src/aria/ui-patterns/behaviors/grid/index.ts rename to src/aria/private/behaviors/grid/index.ts diff --git a/src/aria/ui-patterns/behaviors/label/BUILD b/src/aria/private/behaviors/label/BUILD similarity index 76% rename from src/aria/ui-patterns/behaviors/label/BUILD rename to src/aria/private/behaviors/label/BUILD index 4e53d5d033e1..26e99c7d5b4b 100644 --- a/src/aria/ui-patterns/behaviors/label/BUILD +++ b/src/aria/private/behaviors/label/BUILD @@ -8,8 +8,7 @@ ts_project( "label.ts", ], deps = [ - "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/signal-like", ], ) @@ -21,7 +20,7 @@ ng_project( ], deps = [ ":label", - "//:node_modules/@angular/core", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/ui-patterns/behaviors/label/label.spec.ts b/src/aria/private/behaviors/label/label.spec.ts similarity index 95% rename from src/aria/ui-patterns/behaviors/label/label.spec.ts rename to src/aria/private/behaviors/label/label.spec.ts index a12218b6fd04..6c7beef7c6c3 100644 --- a/src/aria/ui-patterns/behaviors/label/label.spec.ts +++ b/src/aria/private/behaviors/label/label.spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {signal, WritableSignal} from '@angular/core'; +import {signal, WritableSignalLike} from '../signal-like/signal-like'; import {LabelControl, LabelControlInputs, LabelControlOptionalInputs} from './label'; // This is a helper type for the initial values passed to the setup function. @@ -20,7 +20,7 @@ type TestLabelControlInputs = LabelControlInputs & Required; }; diff --git a/src/aria/ui-patterns/behaviors/label/label.ts b/src/aria/private/behaviors/label/label.ts similarity index 93% rename from src/aria/ui-patterns/behaviors/label/label.ts rename to src/aria/private/behaviors/label/label.ts index 5debdce1c4f1..e8eb5a09f053 100644 --- a/src/aria/ui-patterns/behaviors/label/label.ts +++ b/src/aria/private/behaviors/label/label.ts @@ -5,8 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ -import {computed} from '@angular/core'; -import {SignalLike} from '../signal-like/signal-like'; +import {computed, SignalLike} from '../signal-like/signal-like'; /** Represents the required inputs for the label control. */ export interface LabelControlInputs { diff --git a/src/aria/ui-patterns/behaviors/list-focus/BUILD.bazel b/src/aria/private/behaviors/list-focus/BUILD.bazel similarity index 84% rename from src/aria/ui-patterns/behaviors/list-focus/BUILD.bazel rename to src/aria/private/behaviors/list-focus/BUILD.bazel index 8efad0179f46..e50359cdc323 100644 --- a/src/aria/ui-patterns/behaviors/list-focus/BUILD.bazel +++ b/src/aria/private/behaviors/list-focus/BUILD.bazel @@ -10,7 +10,7 @@ ts_project( ), deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/signal-like", ], ) @@ -21,6 +21,7 @@ ng_project( deps = [ ":list-focus", "//:node_modules/@angular/core", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/ui-patterns/behaviors/list-focus/list-focus.spec.ts b/src/aria/private/behaviors/list-focus/list-focus.spec.ts similarity index 69% rename from src/aria/ui-patterns/behaviors/list-focus/list-focus.spec.ts rename to src/aria/private/behaviors/list-focus/list-focus.spec.ts index cb9cce52279f..c37c1e40f629 100644 --- a/src/aria/ui-patterns/behaviors/list-focus/list-focus.spec.ts +++ b/src/aria/private/behaviors/list-focus/list-focus.spec.ts @@ -6,11 +6,11 @@ * found in the LICENSE file at https://angular.dev/license */ -import {Signal, signal, WritableSignal} from '@angular/core'; +import {SignalLike, signal, WritableSignalLike} from '../signal-like/signal-like'; import {ListFocus, ListFocusInputs, ListFocusItem} from './list-focus'; type TestItem = ListFocusItem & { - disabled: WritableSignal; + disabled: WritableSignalLike; }; type TestInputs = Partial> & { @@ -22,7 +22,7 @@ export function getListFocus(inputs: TestInputs = {}): ListFocus return new ListFocus({ activeItem: signal(items()[0]), disabled: signal(false), - skipDisabled: signal(false), + softDisabled: signal(true), focusMode: signal('roving'), element: signal({focus: () => {}} as HTMLElement), items: items, @@ -30,7 +30,7 @@ export function getListFocus(inputs: TestInputs = {}): ListFocus }); } -function getItems(length: number): Signal { +function getItems(length: number): SignalLike { return signal( Array.from({length}).map((_, i) => { return { @@ -51,22 +51,22 @@ describe('List Focus', () => { focusManager = getListFocus({focusMode: signal('roving')}); }); - it('should set the list tabindex to -1', () => { - expect(focusManager.getListTabindex()).toBe(-1); + it('should set the list to -1', () => { + expect(focusManager.getListTabIndex()).toBe(-1); }); - it('should set the activedescendant to undefined', () => { + it('should set the active descendant to undefined', () => { expect(focusManager.getActiveDescendant()).toBeUndefined(); }); - it('should set the tabindex based on the active index', () => { + it('should set the tab index based on the active index', () => { const items = focusManager.inputs.items() as TestItem[]; focusManager.inputs.activeItem.set(focusManager.inputs.items()[2]); - expect(focusManager.getItemTabindex(items[0])).toBe(-1); - expect(focusManager.getItemTabindex(items[1])).toBe(-1); - expect(focusManager.getItemTabindex(items[2])).toBe(0); - expect(focusManager.getItemTabindex(items[3])).toBe(-1); - expect(focusManager.getItemTabindex(items[4])).toBe(-1); + expect(focusManager.getItemTabIndex(items[0])).toBe(-1); + expect(focusManager.getItemTabIndex(items[1])).toBe(-1); + expect(focusManager.getItemTabIndex(items[2])).toBe(0); + expect(focusManager.getItemTabIndex(items[3])).toBe(-1); + expect(focusManager.getItemTabIndex(items[4])).toBe(-1); }); }); @@ -77,22 +77,22 @@ describe('List Focus', () => { focusManager = getListFocus({focusMode: signal('activedescendant')}); }); - it('should set the list tabindex to 0', () => { - expect(focusManager.getListTabindex()).toBe(0); + it('should set the list tab index to 0', () => { + expect(focusManager.getListTabIndex()).toBe(0); }); it('should set the activedescendant to the active items id', () => { expect(focusManager.getActiveDescendant()).toBe(focusManager.inputs.items()[0].id()); }); - it('should set the tabindex of all items to -1', () => { + it('should set the tab index of all items to -1', () => { const items = focusManager.inputs.items() as TestItem[]; focusManager.inputs.activeItem.set(focusManager.inputs.items()[0]); - expect(focusManager.getItemTabindex(items[0])).toBe(-1); - expect(focusManager.getItemTabindex(items[1])).toBe(-1); - expect(focusManager.getItemTabindex(items[2])).toBe(-1); - expect(focusManager.getItemTabindex(items[3])).toBe(-1); - expect(focusManager.getItemTabindex(items[4])).toBe(-1); + expect(focusManager.getItemTabIndex(items[0])).toBe(-1); + expect(focusManager.getItemTabIndex(items[1])).toBe(-1); + expect(focusManager.getItemTabIndex(items[2])).toBe(-1); + expect(focusManager.getItemTabIndex(items[3])).toBe(-1); + expect(focusManager.getItemTabIndex(items[4])).toBe(-1); }); it('should update the activedescendant of the list when navigating', () => { @@ -109,7 +109,7 @@ describe('List Focus', () => { describe('#isFocusable', () => { it('should return true for enabled items', () => { - const focusManager = getListFocus({skipDisabled: signal(true)}); + const focusManager = getListFocus({softDisabled: signal(false)}); const items = focusManager.inputs.items() as TestItem[]; expect(focusManager.isFocusable(items[0])).toBeTrue(); expect(focusManager.isFocusable(items[1])).toBeTrue(); @@ -117,7 +117,7 @@ describe('List Focus', () => { }); it('should return false for disabled items', () => { - const focusManager = getListFocus({skipDisabled: signal(true)}); + const focusManager = getListFocus({softDisabled: signal(false)}); const items = focusManager.inputs.items() as TestItem[]; items[1].disabled.set(true); @@ -126,8 +126,8 @@ describe('List Focus', () => { expect(focusManager.isFocusable(items[2])).toBeTrue(); }); - it('should return true for disabled items if skip disabled is false', () => { - const focusManager = getListFocus({skipDisabled: signal(false)}); + it('should return true for disabled items if soft disabled is true', () => { + const focusManager = getListFocus({softDisabled: signal(true)}); const items = focusManager.inputs.items() as TestItem[]; items[1].disabled.set(true); diff --git a/src/aria/ui-patterns/behaviors/list-focus/list-focus.ts b/src/aria/private/behaviors/list-focus/list-focus.ts similarity index 85% rename from src/aria/ui-patterns/behaviors/list-focus/list-focus.ts rename to src/aria/private/behaviors/list-focus/list-focus.ts index 53e1c47fd174..60de40b19407 100644 --- a/src/aria/ui-patterns/behaviors/list-focus/list-focus.ts +++ b/src/aria/private/behaviors/list-focus/list-focus.ts @@ -6,8 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed, signal} from '@angular/core'; -import {SignalLike, WritableSignalLike} from '../signal-like/signal-like'; +import {computed, signal, SignalLike, WritableSignalLike} from '../signal-like/signal-like'; /** Represents an item in a collection, such as a listbox option, than may receive focus. */ export interface ListFocusItem { @@ -15,7 +14,7 @@ export interface ListFocusItem { id: SignalLike; /** The html element that should receive focus. */ - element: SignalLike; + element: SignalLike; /** Whether an item is disabled. */ disabled: SignalLike; @@ -38,8 +37,8 @@ export interface ListFocusInputs { /** The active item. */ activeItem: WritableSignalLike; - /** Whether disabled items in the list should be skipped when navigating. */ - skipDisabled: SignalLike; + /** Whether disabled items in the list should be focusable. */ + softDisabled: SignalLike; element: SignalLike; } @@ -77,16 +76,16 @@ export class ListFocus { return this.inputs.activeItem()?.id() ?? undefined; } - /** The tabindex for the list. */ - getListTabindex(): -1 | 0 { + /** The tab index for the list. */ + getListTabIndex(): -1 | 0 { if (this.isListDisabled()) { return 0; } return this.inputs.focusMode() === 'activedescendant' ? 0 : -1; } - /** Returns the tabindex for the given item. */ - getItemTabindex(item: T): -1 | 0 { + /** Returns the tab index for the given item. */ + getItemTabIndex(item: T): -1 | 0 { if (this.isListDisabled()) { return -1; } @@ -107,7 +106,7 @@ export class ListFocus { if (opts?.focusElement || opts?.focusElement === undefined) { this.inputs.focusMode() === 'roving' - ? item.element().focus() + ? item.element()?.focus() : this.inputs.element()?.focus(); } @@ -116,6 +115,6 @@ export class ListFocus { /** Returns true if the given item can be navigated to. */ isFocusable(item: T): boolean { - return !item.disabled() || !this.inputs.skipDisabled(); + return !item.disabled() || this.inputs.softDisabled(); } } diff --git a/src/aria/ui-patterns/behaviors/list-navigation/BUILD.bazel b/src/aria/private/behaviors/list-navigation/BUILD.bazel similarity index 65% rename from src/aria/ui-patterns/behaviors/list-navigation/BUILD.bazel rename to src/aria/private/behaviors/list-navigation/BUILD.bazel index 22e9433bad1a..4464b5c39ba1 100644 --- a/src/aria/ui-patterns/behaviors/list-navigation/BUILD.bazel +++ b/src/aria/private/behaviors/list-navigation/BUILD.bazel @@ -9,9 +9,8 @@ ts_project( exclude = ["**/*.spec.ts"], ), deps = [ - "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/list-focus", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/list-focus", + "//src/aria/private/behaviors/signal-like", ], ) @@ -21,8 +20,8 @@ ng_project( srcs = glob(["**/*.spec.ts"]), deps = [ ":list-navigation", - "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/list-focus:unit_test_sources", + "//src/aria/private/behaviors/list-focus:unit_test_sources", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/ui-patterns/behaviors/list-navigation/list-navigation.spec.ts b/src/aria/private/behaviors/list-navigation/list-navigation.spec.ts similarity index 91% rename from src/aria/ui-patterns/behaviors/list-navigation/list-navigation.spec.ts rename to src/aria/private/behaviors/list-navigation/list-navigation.spec.ts index 04bc68f605af..e230e8b7e576 100644 --- a/src/aria/ui-patterns/behaviors/list-navigation/list-navigation.spec.ts +++ b/src/aria/private/behaviors/list-navigation/list-navigation.spec.ts @@ -6,12 +6,12 @@ * found in the LICENSE file at https://angular.dev/license */ -import {signal, WritableSignal} from '@angular/core'; +import {signal, WritableSignalLike} from '../signal-like/signal-like'; import {ListNavigation, ListNavigationInputs, ListNavigationItem} from './list-navigation'; import {getListFocus} from '../list-focus/list-focus.spec'; type TestItem = ListNavigationItem & { - disabled: WritableSignal; + disabled: WritableSignalLike; }; type TestInputs = Partial> & { numItems?: number; @@ -73,7 +73,7 @@ describe('List Navigation', () => { }); it('should skip disabled items', () => { - const nav = getNavigation({skipDisabled: signal(true)}); + const nav = getNavigation({softDisabled: signal(false)}); const items = nav.inputs.items() as TestItem[]; items[1].disabled.set(true); nav.next(); // 0 -> 2 @@ -81,7 +81,7 @@ describe('List Navigation', () => { }); it('should not skip disabled items', () => { - const nav = getNavigation({skipDisabled: signal(false)}); + const nav = getNavigation({softDisabled: signal(true)}); const items = nav.inputs.items() as TestItem[]; items[1].disabled.set(true); nav.next(); // 0 -> 1 @@ -91,7 +91,7 @@ describe('List Navigation', () => { it('should wrap and skip disabled items', () => { const nav = getNavigation({ wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), }); const items = nav.inputs.items() as TestItem[]; items[2].disabled.set(true); @@ -105,7 +105,7 @@ describe('List Navigation', () => { }); it('should do nothing if other items are disabled', () => { - const nav = getNavigation({skipDisabled: signal(true)}); + const nav = getNavigation({softDisabled: signal(false)}); const items = nav.inputs.items() as TestItem[]; items[1].disabled.set(true); items[2].disabled.set(true); @@ -150,7 +150,7 @@ describe('List Navigation', () => { }); it('should skip disabled items', () => { - const nav = getNavigation({skipDisabled: signal(true)}); + const nav = getNavigation({softDisabled: signal(false)}); nav.goto(nav.inputs.items()[2]); const items = nav.inputs.items() as TestItem[]; items[1].disabled.set(true); @@ -159,7 +159,7 @@ describe('List Navigation', () => { }); it('should not skip disabled items', () => { - const nav = getNavigation({skipDisabled: signal(false)}); + const nav = getNavigation({softDisabled: signal(true)}); nav.goto(nav.inputs.items()[2]); const items = nav.inputs.items() as TestItem[]; items[1].disabled.set(true); @@ -170,7 +170,7 @@ describe('List Navigation', () => { it('should wrap and skip disabled items', () => { const nav = getNavigation({ wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), }); nav.goto(nav.inputs.items()[2]); const items = nav.inputs.items() as TestItem[]; @@ -182,7 +182,7 @@ describe('List Navigation', () => { it('should do nothing if other items are disabled', () => { const nav = getNavigation({ - skipDisabled: signal(true), + softDisabled: signal(false), }); const items = nav.inputs.items() as TestItem[]; items[1].disabled.set(true); @@ -209,7 +209,7 @@ describe('List Navigation', () => { }); it('should skip disabled items', () => { - const nav = getNavigation({skipDisabled: signal(true)}); + const nav = getNavigation({softDisabled: signal(false)}); nav.goto(nav.inputs.items()[2]); const items = nav.inputs.items() as TestItem[]; items[0].disabled.set(true); @@ -218,7 +218,7 @@ describe('List Navigation', () => { }); it('should not skip disabled items', () => { - const nav = getNavigation({skipDisabled: signal(false)}); + const nav = getNavigation({softDisabled: signal(true)}); nav.goto(nav.inputs.items()[2]); const items = nav.inputs.items() as TestItem[]; items[0].disabled.set(true); @@ -236,7 +236,7 @@ describe('List Navigation', () => { it('should skip disabled items', () => { const nav = getNavigation({ - skipDisabled: signal(true), + softDisabled: signal(false), }); const items = nav.inputs.items() as TestItem[]; items[4].disabled.set(true); @@ -246,7 +246,7 @@ describe('List Navigation', () => { it('should not skip disabled items', () => { const nav = getNavigation({ - skipDisabled: signal(false), + softDisabled: signal(true), }); const items = nav.inputs.items() as TestItem[]; items[4].disabled.set(true); diff --git a/src/aria/ui-patterns/behaviors/list-navigation/list-navigation.ts b/src/aria/private/behaviors/list-navigation/list-navigation.ts similarity index 87% rename from src/aria/ui-patterns/behaviors/list-navigation/list-navigation.ts rename to src/aria/private/behaviors/list-navigation/list-navigation.ts index 7899eec6e180..fb63c70386ac 100644 --- a/src/aria/ui-patterns/behaviors/list-navigation/list-navigation.ts +++ b/src/aria/private/behaviors/list-navigation/list-navigation.ts @@ -55,19 +55,29 @@ export class ListNavigation { /** Navigates to the first item in the list. */ first(opts?: {focusElement?: boolean}): boolean { - const item = this.inputs.items().find(i => this.inputs.focusManager.isFocusable(i)); + const item = this.peekFirst(); return item ? this.goto(item, opts) : false; } /** Navigates to the last item in the list. */ last(opts?: {focusElement?: boolean}): boolean { - const items = this.inputs.items(); + const item = this.peekLast(); + return item ? this.goto(item, opts) : false; + } + + /** Gets the first focusable item from the given list of items. */ + peekFirst(items: T[] = this.inputs.items()): T | undefined { + return items.find(i => this.inputs.focusManager.isFocusable(i)); + } + + /** Gets the last focusable item from the given list of items. */ + peekLast(items: T[] = this.inputs.items()): T | undefined { for (let i = items.length - 1; i >= 0; i--) { if (this.inputs.focusManager.isFocusable(items[i])) { - return this.goto(items[i], opts); + return items[i]; } } - return false; + return; } /** Advances to the next or previous focusable item in the list based on the given delta. */ diff --git a/src/aria/ui-patterns/behaviors/list-selection/BUILD.bazel b/src/aria/private/behaviors/list-selection/BUILD.bazel similarity index 68% rename from src/aria/ui-patterns/behaviors/list-selection/BUILD.bazel rename to src/aria/private/behaviors/list-selection/BUILD.bazel index 9d9c1d33441b..b2924326a38d 100644 --- a/src/aria/ui-patterns/behaviors/list-selection/BUILD.bazel +++ b/src/aria/private/behaviors/list-selection/BUILD.bazel @@ -10,8 +10,8 @@ ts_project( ), deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/list-focus", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/list-focus", + "//src/aria/private/behaviors/signal-like", ], ) @@ -22,8 +22,9 @@ ng_project( deps = [ ":list-selection", "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/list-focus", - "//src/aria/ui-patterns/behaviors/list-focus:unit_test_sources", + "//src/aria/private/behaviors/list-focus", + "//src/aria/private/behaviors/list-focus:unit_test_sources", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/ui-patterns/behaviors/list-selection/list-selection.spec.ts b/src/aria/private/behaviors/list-selection/list-selection.spec.ts similarity index 79% rename from src/aria/ui-patterns/behaviors/list-selection/list-selection.spec.ts rename to src/aria/private/behaviors/list-selection/list-selection.spec.ts index ef54329c7131..b33eac1f0cca 100644 --- a/src/aria/ui-patterns/behaviors/list-selection/list-selection.spec.ts +++ b/src/aria/private/behaviors/list-selection/list-selection.spec.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.dev/license */ -import {Signal, signal, WritableSignal} from '@angular/core'; +import {SignalLike, signal, WritableSignalLike} from '../signal-like/signal-like'; import {ListSelectionItem, ListSelection, ListSelectionInputs} from './list-selection'; import {getListFocus} from '../list-focus/list-focus.spec'; import {ListFocus} from '../list-focus/list-focus'; type TestItem = ListSelectionItem & { - disabled: WritableSignal; - selectable: WritableSignal; + disabled: WritableSignalLike; + selectable: WritableSignalLike; }; type TestInputs = Partial> & { numItems?: number; @@ -27,14 +27,14 @@ function getSelection(inputs: TestInputs = {}): ListSelection { +function getItems(length: number): SignalLike { return signal( Array.from({length}).map((_, i) => { return { @@ -54,7 +54,7 @@ describe('List Selection', () => { it('should select an item', () => { const selection = getSelection(); selection.select(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); it('should select multiple options', () => { @@ -65,7 +65,7 @@ describe('List Selection', () => { selection.inputs.focusManager.focus(items[1]); selection.select(); // [0, 1] - expect(selection.inputs.value()).toEqual([0, 1]); + expect(selection.inputs.values()).toEqual([0, 1]); }); it('should not select multiple options', () => { @@ -74,7 +74,7 @@ describe('List Selection', () => { selection.select(); // [0] selection.inputs.focusManager.focus(items[1]); selection.select(); // [1] - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); it('should not select disabled items', () => { @@ -82,7 +82,7 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].disabled.set(true); selection.select(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should not select non-selectable items', () => { @@ -90,14 +90,14 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].selectable.set(false); selection.select(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should do nothing to already selected items', () => { const selection = getSelection(); selection.select(); // [0] selection.select(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); }); @@ -105,7 +105,7 @@ describe('List Selection', () => { it('should deselect an item', () => { const selection = getSelection(); selection.deselect(); // [] - expect(selection.inputs.value().length).toBe(0); + expect(selection.inputs.values().length).toBe(0); }); it('should not deselect disabled items', () => { @@ -114,7 +114,7 @@ describe('List Selection', () => { selection.select(); // [0] items[0].disabled.set(true); selection.deselect(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); it('should not deselect non-selectable items', () => { @@ -123,7 +123,7 @@ describe('List Selection', () => { selection.select(); // [0] items[0].selectable.set(false); selection.deselect(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); }); @@ -131,14 +131,14 @@ describe('List Selection', () => { it('should select an unselected item', () => { const selection = getSelection(); selection.toggle(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); it('should deselect a selected item', () => { const selection = getSelection(); selection.select(); // [0] selection.toggle(); // [] - expect(selection.inputs.value().length).toBe(0); + expect(selection.inputs.values().length).toBe(0); }); it('should not toggle non-selectable items', () => { @@ -146,7 +146,7 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].selectable.set(false); selection.toggle(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); }); @@ -154,14 +154,14 @@ describe('List Selection', () => { it('should select an unselected item', () => { const selection = getSelection({multi: signal(true)}); selection.toggleOne(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); it('should deselect a selected item', () => { const selection = getSelection({multi: signal(true)}); selection.select(); // [0] selection.toggleOne(); // [] - expect(selection.inputs.value().length).toBe(0); + expect(selection.inputs.values().length).toBe(0); }); it('should only leave one item selected', () => { @@ -170,7 +170,7 @@ describe('List Selection', () => { selection.select(); // [0] selection.inputs.focusManager.focus(items[1]); selection.toggleOne(); // [1] - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); it('should not toggle non-selectable items', () => { @@ -178,7 +178,7 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].selectable.set(false); selection.toggleOne(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); }); @@ -186,13 +186,13 @@ describe('List Selection', () => { it('should select all items', () => { const selection = getSelection({multi: signal(true)}); selection.selectAll(); - expect(selection.inputs.value()).toEqual([0, 1, 2, 3, 4]); + expect(selection.inputs.values()).toEqual([0, 1, 2, 3, 4]); }); it('should do nothing if a list is not multiselectable', () => { const selection = getSelection({multi: signal(false)}); selection.selectAll(); - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should not select non-selectable items', () => { @@ -200,7 +200,7 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[1].selectable.set(false); selection.selectAll(); - expect(selection.inputs.value()).toEqual([0, 2, 3, 4]); + expect(selection.inputs.values()).toEqual([0, 2, 3, 4]); }); }); @@ -209,14 +209,14 @@ describe('List Selection', () => { const selection = getSelection({multi: signal(true)}); selection.selectAll(); // [0, 1, 2, 3, 4] selection.deselectAll(); // [] - expect(selection.inputs.value().length).toBe(0); + expect(selection.inputs.values().length).toBe(0); }); it('should deselect items that are not in the list', () => { const selection = getSelection({multi: signal(true)}); - selection.inputs.value.update(() => [5]); + selection.inputs.values.update(() => [5]); selection.deselectAll(); - expect(selection.inputs.value().length).toBe(0); + expect(selection.inputs.values().length).toBe(0); }); it('should not deselect non-selectable items', () => { @@ -225,7 +225,7 @@ describe('List Selection', () => { selection.selectAll(); // [0, 1, 2, 3, 4] items[1].selectable.set(false); selection.deselectAll(); // [1] - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); }); @@ -233,14 +233,14 @@ describe('List Selection', () => { it('should select all items', () => { const selection = getSelection({multi: signal(true)}); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([0, 1, 2, 3, 4]); + expect(selection.inputs.values()).toEqual([0, 1, 2, 3, 4]); }); it('should deselect all if all items are selected', () => { const selection = getSelection({multi: signal(true)}); selection.selectAll(); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should ignore disabled items when determining if all items are selected', () => { @@ -248,9 +248,9 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].disabled.set(true); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([1, 2, 3, 4]); + expect(selection.inputs.values()).toEqual([1, 2, 3, 4]); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should ignore non-selectable items when determining if all items are selected', () => { @@ -258,9 +258,9 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].selectable.set(false); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([1, 2, 3, 4]); + expect(selection.inputs.values()).toEqual([1, 2, 3, 4]); selection.toggleAll(); - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); }); @@ -271,7 +271,7 @@ describe('List Selection', () => { selection.selectOne(); // [0] selection.inputs.focusManager.focus(items[1]); selection.selectOne(); // [1] - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); it('should not select disabled items', () => { @@ -280,7 +280,7 @@ describe('List Selection', () => { items[0].disabled.set(true); selection.select(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should not select non-selectable items', () => { @@ -288,14 +288,14 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; items[0].selectable.set(false); selection.selectOne(); // [] - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); }); it('should do nothing to already selected items', () => { const selection = getSelection({multi: signal(true)}); selection.selectOne(); // [0] selection.selectOne(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); }); it('should do nothing if the current active item is disabled', () => { @@ -304,12 +304,12 @@ describe('List Selection', () => { selection.inputs.focusManager.focus(items[1]); selection.select(); - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); selection.inputs.focusManager.focus(items[0]); items[0].disabled.set(true); selection.selectOne(); - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); it('should not select an item if the list is not multiselectable and not all items are deselected', () => { @@ -318,12 +318,12 @@ describe('List Selection', () => { selection.inputs.focusManager.focus(items[1]); selection.select(); - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); items[1].disabled.set(true); selection.inputs.focusManager.focus(items[2]); selection.selectOne(); - expect(selection.inputs.value()).toEqual([1]); + expect(selection.inputs.values()).toEqual([1]); }); }); @@ -334,7 +334,7 @@ describe('List Selection', () => { selection.select(); // [0] selection.inputs.focusManager.focus(items[2]); selection.selectRange(); // [0, 1, 2] - expect(selection.inputs.value()).toEqual([0, 1, 2]); + expect(selection.inputs.values()).toEqual([0, 1, 2]); }); it('should select all items from an anchor at a higher index', () => { @@ -346,7 +346,7 @@ describe('List Selection', () => { selection.inputs.focusManager.focus(items[1]); selection.selectRange(); // [3, 2, 1] - expect(selection.inputs.value()).toEqual([3, 2, 1]); + expect(selection.inputs.values()).toEqual([3, 2, 1]); }); it('should deselect items within the range when the range is changed', () => { @@ -355,15 +355,15 @@ describe('List Selection', () => { selection.inputs.activeItem.set(items[2]); selection.select(); // [2] - expect(selection.inputs.value()).toEqual([2]); + expect(selection.inputs.values()).toEqual([2]); selection.inputs.focusManager.focus(items[4]); selection.selectRange(); // [2, 3, 4] - expect(selection.inputs.value()).toEqual([2, 3, 4]); + expect(selection.inputs.values()).toEqual([2, 3, 4]); selection.inputs.focusManager.focus(items[0]); selection.selectRange(); // [2, 1, 0] - expect(selection.inputs.value()).toEqual([2, 1, 0]); + expect(selection.inputs.values()).toEqual([2, 1, 0]); }); it('should not select a disabled item', () => { @@ -372,15 +372,15 @@ describe('List Selection', () => { items[1].disabled.set(true); selection.select(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); selection.inputs.focusManager.focus(items[1]); selection.selectRange(); // [0] - expect(selection.inputs.value()).toEqual([0]); + expect(selection.inputs.values()).toEqual([0]); selection.inputs.focusManager.focus(items[2]); selection.selectRange(); // [0, 2] - expect(selection.inputs.value()).toEqual([0, 2]); + expect(selection.inputs.values()).toEqual([0, 2]); }); it('should not select a non-selectable item', () => { @@ -390,7 +390,7 @@ describe('List Selection', () => { selection.select(); // [0] selection.inputs.focusManager.focus(items[2]); selection.selectRange(); // [0, 2] - expect(selection.inputs.value()).toEqual([0, 2]); + expect(selection.inputs.values()).toEqual([0, 2]); }); it('should not deselect a disabled item', () => { @@ -401,15 +401,15 @@ describe('List Selection', () => { items[1].disabled.set(true); selection.select(); // [0, 1] - expect(selection.inputs.value()).toEqual([1, 0]); + expect(selection.inputs.values()).toEqual([1, 0]); selection.inputs.focusManager.focus(items[2]); selection.selectRange(); // [0, 1, 2] - expect(selection.inputs.value()).toEqual([1, 0, 2]); + expect(selection.inputs.values()).toEqual([1, 0, 2]); selection.inputs.focusManager.focus(items[0]); selection.selectRange(); // [0, 1] - expect(selection.inputs.value()).toEqual([1, 0]); + expect(selection.inputs.values()).toEqual([1, 0]); }); it('should not deselect a non-selectable item', () => { @@ -418,13 +418,13 @@ describe('List Selection', () => { selection.select(items[1]); // [1] items[1].selectable.set(false); selection.select(); // [0, 1] - expect(selection.inputs.value()).toEqual([1, 0]); + expect(selection.inputs.values()).toEqual([1, 0]); selection.inputs.focusManager.focus(items[2]); selection.selectRange(); // [0, 1, 2] - expect(selection.inputs.value()).toEqual([1, 0, 2]); + expect(selection.inputs.values()).toEqual([1, 0, 2]); selection.inputs.focusManager.focus(items[0]); selection.selectRange(); // [0, 1] - expect(selection.inputs.value()).toEqual([1, 0]); + expect(selection.inputs.values()).toEqual([1, 0]); }); }); @@ -434,10 +434,10 @@ describe('List Selection', () => { const items = selection.inputs.items() as TestItem[]; selection.inputs.focusManager.focus(items[2]); selection.beginRangeSelection(); - expect(selection.inputs.value()).toEqual([]); + expect(selection.inputs.values()).toEqual([]); selection.inputs.focusManager.focus(items[4]); selection.selectRange(); // [2, 3, 4] - expect(selection.inputs.value()).toEqual([2, 3, 4]); + expect(selection.inputs.values()).toEqual([2, 3, 4]); }); it('should be able to select a range starting on a disabled item', () => { @@ -447,7 +447,7 @@ describe('List Selection', () => { selection.beginRangeSelection(0); selection.inputs.focusManager.focus(items[2]); selection.selectRange(); - expect(selection.inputs.value()).toEqual([1, 2]); + expect(selection.inputs.values()).toEqual([1, 2]); }); }); }); diff --git a/src/aria/ui-patterns/behaviors/list-selection/list-selection.ts b/src/aria/private/behaviors/list-selection/list-selection.ts similarity index 85% rename from src/aria/ui-patterns/behaviors/list-selection/list-selection.ts rename to src/aria/private/behaviors/list-selection/list-selection.ts index d687b9939e3d..540164b487be 100644 --- a/src/aria/ui-patterns/behaviors/list-selection/list-selection.ts +++ b/src/aria/private/behaviors/list-selection/list-selection.ts @@ -6,11 +6,10 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed, signal} from '@angular/core'; -import {SignalLike, WritableSignalLike} from '../signal-like/signal-like'; +import {computed, signal, SignalLike, WritableSignalLike} from '../signal-like/signal-like'; import {ListFocus, ListFocusInputs, ListFocusItem} from '../list-focus/list-focus'; -/** Represents an item in a collection, such as a listbox option, than can be selected. */ +/** Represents an item in a collection, such as a listbox option, that can be selected. */ export interface ListSelectionItem extends ListFocusItem { /** The value of the item. */ value: SignalLike; @@ -25,7 +24,7 @@ export interface ListSelectionInputs, V> extends multi: SignalLike; /** The current value of the list selection. */ - value: WritableSignalLike; + values: WritableSignalLike; /** The selection strategy used by the list. */ selectionMode: SignalLike<'follow' | 'explicit'>; @@ -41,7 +40,7 @@ export class ListSelection, V> { /** The currently selected items. */ selectedItems = computed(() => - this.inputs.items().filter(item => this.inputs.value().includes(item.value())), + this.inputs.items().filter(item => this.inputs.values().includes(item.value())), ); constructor(readonly inputs: ListSelectionInputs & {focusManager: ListFocus}) {} @@ -54,7 +53,7 @@ export class ListSelection, V> { !item || item.disabled() || !item.selectable() || - this.inputs.value().includes(item.value()) + this.inputs.values().includes(item.value()) ) { return; } @@ -67,23 +66,23 @@ export class ListSelection, V> { if (opts.anchor) { this.beginRangeSelection(index); } - this.inputs.value.update(values => values.concat(item.value())); + this.inputs.values.update(values => values.concat(item.value())); } /** Deselects the item at the current active index. */ - deselect(item?: T | null) { + deselect(item?: ListSelectionItem) { item = item ?? this.inputs.focusManager.inputs.activeItem(); if (item && !item.disabled() && item.selectable()) { - this.inputs.value.update(values => values.filter(value => value !== item.value())); + this.inputs.values.update(values => values.filter(value => value !== item.value())); } } /** Toggles the item at the current active index. */ - toggle() { - const item = this.inputs.focusManager.inputs.activeItem(); + toggle(item?: ListSelectionItem) { + item = item ?? this.inputs.focusManager.inputs.activeItem(); if (item) { - this.inputs.value().includes(item.value()) ? this.deselect() : this.select(); + this.inputs.values().includes(item.value()) ? this.deselect(item) : this.select(item); } } @@ -91,7 +90,7 @@ export class ListSelection, V> { toggleOne() { const item = this.inputs.focusManager.inputs.activeItem(); if (item) { - this.inputs.value().includes(item.value()) ? this.deselect() : this.selectOne(); + this.inputs.values().includes(item.value()) ? this.deselect() : this.selectOne(); } } @@ -123,12 +122,12 @@ export class ListSelection, V> { // inverse (and more common) effect of keeping enabled items selected when they aren't in the // list. - for (const value of this.inputs.value()) { + for (const value of this.inputs.values()) { const item = this.inputs.items().find(i => i.value() === value); item ? this.deselect(item) - : this.inputs.value.update(values => values.filter(v => v !== value)); + : this.inputs.values.update(values => values.filter(v => v !== value)); } } @@ -142,7 +141,7 @@ export class ListSelection, V> { .filter(i => !i.disabled() && i.selectable()) .map(i => i.value()); - selectableValues.every(i => this.inputs.value().includes(i)) + selectableValues.every(i => this.inputs.values().includes(i)) ? this.deselectAll() : this.selectAll(); } @@ -156,7 +155,7 @@ export class ListSelection, V> { this.deselectAll(); - if (this.inputs.value().length > 0 && !this.inputs.multi()) { + if (this.inputs.values().length > 0 && !this.inputs.multi()) { return; } diff --git a/src/aria/ui-patterns/behaviors/list-typeahead/BUILD.bazel b/src/aria/private/behaviors/list-typeahead/BUILD.bazel similarity index 68% rename from src/aria/ui-patterns/behaviors/list-typeahead/BUILD.bazel rename to src/aria/private/behaviors/list-typeahead/BUILD.bazel index 4a4c998e0386..5b00cfe35e88 100644 --- a/src/aria/ui-patterns/behaviors/list-typeahead/BUILD.bazel +++ b/src/aria/private/behaviors/list-typeahead/BUILD.bazel @@ -10,8 +10,8 @@ ts_project( ), deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/list-focus", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/list-focus", + "//src/aria/private/behaviors/signal-like", ], ) @@ -22,8 +22,9 @@ ng_project( deps = [ ":list-typeahead", "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/list-focus", - "//src/aria/ui-patterns/behaviors/list-focus:unit_test_sources", + "//src/aria/private/behaviors/list-focus", + "//src/aria/private/behaviors/list-focus:unit_test_sources", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/ui-patterns/behaviors/list-typeahead/list-typeahead.spec.ts b/src/aria/private/behaviors/list-typeahead/list-typeahead.spec.ts similarity index 85% rename from src/aria/ui-patterns/behaviors/list-typeahead/list-typeahead.spec.ts rename to src/aria/private/behaviors/list-typeahead/list-typeahead.spec.ts index 34c57899e4ca..3b60a852b58f 100644 --- a/src/aria/ui-patterns/behaviors/list-typeahead/list-typeahead.spec.ts +++ b/src/aria/private/behaviors/list-typeahead/list-typeahead.spec.ts @@ -6,14 +6,13 @@ * found in the LICENSE file at https://angular.dev/license */ -import {Signal, signal, WritableSignal} from '@angular/core'; +import {SignalLike, signal, WritableSignalLike} from '../signal-like/signal-like'; import {ListTypeaheadItem, ListTypeahead, ListTypeaheadInputs} from './list-typeahead'; -import {fakeAsync, tick} from '@angular/core/testing'; import {getListFocus} from '../list-focus/list-focus.spec'; import {ListFocus} from '../list-focus/list-focus'; type TestItem = ListTypeaheadItem & { - disabled: WritableSignal; + disabled: WritableSignalLike; }; type TestInputs = Partial> & { numItems?: number; @@ -27,12 +26,12 @@ function getTypeahead(inputs: TestInputs = {}): ListTypeahead { focusManager, ...focusManager.inputs, items, - typeaheadDelay: signal(0.5), + typeaheadDelay: signal(500), ...inputs, }); } -function getItems(length: number): Signal { +function getItems(length: number): SignalLike { return signal( Array.from({length}).map((_, i) => { return { @@ -68,26 +67,26 @@ describe('List Typeahead', () => { expect(typeahead.inputs.focusManager.activeIndex()).toBe(3); }); - it('should reset after a delay', fakeAsync(() => { + it('should reset after a delay', async () => { typeahead.search('i'); expect(typeahead.inputs.focusManager.activeIndex()).toBe(1); - tick(500); + await new Promise(resolve => setTimeout(resolve, 500)); typeahead.search('i'); expect(typeahead.inputs.focusManager.activeIndex()).toBe(2); - })); + }); it('should skip disabled items', () => { items[1].disabled.set(true); - (typeahead.inputs.skipDisabled as WritableSignal).set(true); + (typeahead.inputs.softDisabled as WritableSignalLike).set(false); typeahead.search('i'); expect(typeahead.inputs.focusManager.activeIndex()).toBe(2); }); it('should not skip disabled items', () => { items[1].disabled.set(true); - (typeahead.inputs.skipDisabled as WritableSignal).set(false); + (typeahead.inputs.softDisabled as WritableSignalLike).set(true); typeahead.search('i'); expect(typeahead.inputs.focusManager.activeIndex()).toBe(1); }); diff --git a/src/aria/ui-patterns/behaviors/list-typeahead/list-typeahead.ts b/src/aria/private/behaviors/list-typeahead/list-typeahead.ts similarity index 95% rename from src/aria/ui-patterns/behaviors/list-typeahead/list-typeahead.ts rename to src/aria/private/behaviors/list-typeahead/list-typeahead.ts index 3ee7bfe3a7a0..41e1d797c535 100644 --- a/src/aria/ui-patterns/behaviors/list-typeahead/list-typeahead.ts +++ b/src/aria/private/behaviors/list-typeahead/list-typeahead.ts @@ -6,8 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed, signal} from '@angular/core'; -import {SignalLike} from '../signal-like/signal-like'; +import {computed, signal, SignalLike} from '../signal-like/signal-like'; import {ListFocus, ListFocusInputs, ListFocusItem} from '../list-focus/list-focus'; /** @@ -74,7 +73,7 @@ export class ListTypeahead { this.timeout = setTimeout(() => { this._query.set(''); this._startIndex.set(undefined); - }, this.inputs.typeaheadDelay() * 1000); + }, this.inputs.typeaheadDelay()); return true; } diff --git a/src/aria/ui-patterns/behaviors/list/BUILD.bazel b/src/aria/private/behaviors/list/BUILD.bazel similarity index 63% rename from src/aria/ui-patterns/behaviors/list/BUILD.bazel rename to src/aria/private/behaviors/list/BUILD.bazel index 6e3522120137..fcc2b54428ea 100644 --- a/src/aria/ui-patterns/behaviors/list/BUILD.bazel +++ b/src/aria/private/behaviors/list/BUILD.bazel @@ -10,12 +10,12 @@ ts_project( ), deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/event-manager", - "//src/aria/ui-patterns/behaviors/list-focus", - "//src/aria/ui-patterns/behaviors/list-navigation", - "//src/aria/ui-patterns/behaviors/list-selection", - "//src/aria/ui-patterns/behaviors/list-typeahead", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/event-manager", + "//src/aria/private/behaviors/list-focus", + "//src/aria/private/behaviors/list-navigation", + "//src/aria/private/behaviors/list-selection", + "//src/aria/private/behaviors/list-typeahead", + "//src/aria/private/behaviors/signal-like", ], ) @@ -26,6 +26,7 @@ ng_project( deps = [ ":list", "//:node_modules/@angular/core", + "//src/aria/private/behaviors/signal-like", "//src/cdk/keycodes", "//src/cdk/testing/private", ], diff --git a/src/aria/ui-patterns/behaviors/list/list.spec.ts b/src/aria/private/behaviors/list/list.spec.ts similarity index 74% rename from src/aria/ui-patterns/behaviors/list/list.spec.ts rename to src/aria/private/behaviors/list/list.spec.ts index 82e7c45c8ba7..6e4cc1296216 100644 --- a/src/aria/ui-patterns/behaviors/list/list.spec.ts +++ b/src/aria/private/behaviors/list/list.spec.ts @@ -6,15 +6,14 @@ * found in the LICENSE file at https://angular.dev/license */ -import {signal, WritableSignal} from '@angular/core'; +import {signal, WritableSignalLike} from '../signal-like/signal-like'; import {List, ListItem, ListInputs} from './list'; -import {fakeAsync, tick} from '@angular/core/testing'; type TestItem = ListItem & { - disabled: WritableSignal; - selectable: WritableSignal; - searchTerm: WritableSignal; - value: WritableSignal; + disabled: WritableSignalLike; + selectable: WritableSignalLike; + searchTerm: WritableSignalLike; + value: WritableSignalLike; }; type TestInputs = ListInputs, V>; @@ -23,9 +22,9 @@ type TestList = List, V>; describe('List Behavior', () => { function getList(inputs: Partial> & Pick, 'items'>): TestList { return new List({ - value: inputs.value ?? signal([]), + values: inputs.values ?? signal([]), activeItem: signal(undefined), - typeaheadDelay: inputs.typeaheadDelay ?? signal(0.5), + typeaheadDelay: inputs.typeaheadDelay ?? signal(500), wrap: inputs.wrap ?? signal(true), disabled: inputs.disabled ?? signal(false), multi: inputs.multi ?? signal(false), @@ -33,7 +32,7 @@ describe('List Behavior', () => { orientation: inputs.orientation ?? signal('vertical'), element: signal({focus: () => {}} as HTMLElement), focusMode: inputs.focusMode ?? signal('roving'), - skipDisabled: inputs.skipDisabled ?? signal(true), + softDisabled: inputs.softDisabled ?? signal(true), selectionMode: signal('explicit'), ...inputs, }); @@ -77,36 +76,36 @@ describe('List Behavior', () => { } describe('with focusMode: "activedescendant"', () => { - it('should set the list tabindex to 0', () => { + it('should set the list tab index to 0', () => { const {list} = getDefaultPatterns({focusMode: signal('activedescendant')}); - expect(list.tabindex()).toBe(0); + expect(list.tabIndex()).toBe(0); }); it('should set the active descendant to the active item id', () => { const {list} = getDefaultPatterns({focusMode: signal('activedescendant')}); - expect(list.activedescendant()).toBe('item-0'); + expect(list.activeDescendant()).toBe('item-0'); list.next(); - expect(list.activedescendant()).toBe('item-1'); + expect(list.activeDescendant()).toBe('item-1'); }); - it('should set item tabindex to -1', () => { + it('should set item tab index to -1', () => { const {list, items} = getDefaultPatterns({focusMode: signal('activedescendant')}); expect(list.getItemTabindex(items[0])).toBe(-1); }); }); describe('with focusMode: "roving"', () => { - it('should set the list tabindex to -1', () => { + it('should set the list tab index to -1', () => { const {list} = getDefaultPatterns({focusMode: signal('roving')}); - expect(list.tabindex()).toBe(-1); + expect(list.tabIndex()).toBe(-1); }); it('should not set the active descendant', () => { const {list} = getDefaultPatterns({focusMode: signal('roving')}); - expect(list.activedescendant()).toBeUndefined(); + expect(list.activeDescendant()).toBeUndefined(); }); - it('should set the active item tabindex to 0 and others to -1', () => { + it('should set the active item tab index to 0 and others to -1', () => { const {list, items} = getDefaultPatterns({focusMode: signal('roving')}); expect(list.getItemTabindex(items[0])).toBe(0); expect(list.getItemTabindex(items[1])).toBe(-1); @@ -116,6 +115,36 @@ describe('List Behavior', () => { }); }); + describe('with disabled: true and softDisabled is false', () => { + let list: TestList; + + beforeEach(() => { + const patterns = getDefaultPatterns({disabled: signal(true), softDisabled: signal(false)}); + list = patterns.list; + }); + + it('should report disabled state', () => { + expect(list.disabled()).toBe(true); + }); + + it('should not change active index on navigation', () => { + expect(list.inputs.activeItem()).toBe(list.inputs.items()[0]); + list.next(); + expect(list.inputs.activeItem()).toBe(list.inputs.items()[0]); + list.last(); + expect(list.inputs.activeItem()).toBe(list.inputs.items()[0]); + }); + + it('should not select items', () => { + list.next({selectOne: true}); + expect(list.inputs.values()).toEqual([]); + }); + + it('should have a tab index of 0', () => { + expect(list.tabIndex()).toBe(0); + }); + }); + describe('with disabled: true', () => { let list: TestList; @@ -138,11 +167,11 @@ describe('List Behavior', () => { it('should not select items', () => { list.next({selectOne: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); - it('should have a tabindex of 0', () => { - expect(list.tabindex()).toBe(0); + it('should have a tab index of 0', () => { + expect(list.tabIndex()).toBe(0); }); }); @@ -177,8 +206,8 @@ describe('List Behavior', () => { expect(list.inputs.activeItem()).toBe(list.inputs.items()[8]); }); - it('should skip disabled items when navigating', () => { - const {list, items} = getDefaultPatterns(); + it('should skip disabled items when softDisabled is false', () => { + const {list, items} = getDefaultPatterns({softDisabled: signal(false)}); items[1].disabled.set(true); // Disable second item expect(list.inputs.activeItem()).toBe(list.inputs.items()[0]); list.next(); @@ -187,8 +216,8 @@ describe('List Behavior', () => { expect(list.inputs.activeItem()).toBe(list.inputs.items()[0]); // Should skip back to 'Apple' }); - it('should not skip disabled items when skipDisabled is false', () => { - const {list, items} = getDefaultPatterns({skipDisabled: signal(false)}); + it('should not skip disabled items when navigating', () => { + const {list, items} = getDefaultPatterns(); items[1].disabled.set(true); // Disable second item expect(list.inputs.activeItem()).toBe(list.inputs.items()[0]); list.next(); @@ -225,7 +254,7 @@ describe('List Behavior', () => { beforeEach(() => { const patterns = getDefaultPatterns({ - value: signal([]), + values: signal([]), multi: signal(false), }); list = patterns.list; @@ -234,39 +263,39 @@ describe('List Behavior', () => { it('should not select when navigating', () => { list.next(); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should select an item when navigating with selectOne:true', () => { list.next({selectOne: true}); - expect(list.inputs.value()).toEqual(['Apricot']); + expect(list.inputs.values()).toEqual(['Apricot']); }); it('should not select a non-selectable item when navigating with selectOne:true', () => { items[1].selectable.set(false); list.next({selectOne: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should toggle an item when navigating with toggle:true', () => { list.goto(items[1], {selectOne: true}); - expect(list.inputs.value()).toEqual(['Apricot']); + expect(list.inputs.values()).toEqual(['Apricot']); list.goto(items[1], {toggle: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should not toggle a non-selectable item when navigating with toggle:true', () => { items[1].selectable.set(false); list.goto(items[1], {toggle: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should only allow one selected item', () => { list.next({selectOne: true}); - expect(list.inputs.value()).toEqual(['Apricot']); + expect(list.inputs.values()).toEqual(['Apricot']); list.next({selectOne: true}); - expect(list.inputs.value()).toEqual(['Banana']); + expect(list.inputs.values()).toEqual(['Banana']); }); }); @@ -276,7 +305,7 @@ describe('List Behavior', () => { beforeEach(() => { const patterns = getDefaultPatterns({ - value: signal([]), + values: signal([]), multi: signal(true), }); list = patterns.list; @@ -285,63 +314,67 @@ describe('List Behavior', () => { it('should not select when navigating', () => { list.next(); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should select an item with toggle:true', () => { list.next({toggle: true}); - expect(list.inputs.value()).toEqual(['Apricot']); + expect(list.inputs.values()).toEqual(['Apricot']); }); it('should not select a non-selectable item with toggle:true', () => { items[1].selectable.set(false); list.next({toggle: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should allow multiple selected items', () => { list.next({toggle: true}); list.next({toggle: true}); - expect(list.inputs.value()).toEqual(['Apricot', 'Banana']); + expect(list.inputs.values()).toEqual(['Apricot', 'Banana']); }); it('should select a range of items with selectRange:true', () => { list.anchor(0); list.next({selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(list.inputs.values()).toEqual(['Apple', 'Apricot']); list.next({selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple', 'Apricot', 'Banana']); + expect(list.inputs.values()).toEqual(['Apple', 'Apricot', 'Banana']); list.prev({selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(list.inputs.values()).toEqual(['Apple', 'Apricot']); list.prev({selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple']); + expect(list.inputs.values()).toEqual(['Apple']); }); it('should not wrap when range selecting', () => { list.anchor(0); list.prev({selectRange: true}); expect(list.inputs.activeItem()).toBe(list.inputs.items()[0]); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); it('should not select disabled items in a range', () => { items[1].disabled.set(true); list.anchor(0); list.goto(items[3], {selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple', 'Banana', 'Blackberry']); + expect(list.inputs.values()).toEqual(['Apple', 'Banana', 'Blackberry']); }); it('should not select non-selectable items in a range', () => { items[1].selectable.set(false); list.anchor(0); list.goto(items[3], {selectRange: true}); - expect(list.inputs.value()).toEqual(['Apple', 'Banana', 'Blackberry']); + expect(list.inputs.values()).toEqual(['Apple', 'Banana', 'Blackberry']); }); }); }); describe('Typeahead', () => { - it('should navigate to an item via typeahead', fakeAsync(() => { + function delay(amount: number) { + return new Promise(resolve => setTimeout(resolve, amount)); + } + + it('should navigate to an item via typeahead', async () => { const {list} = getDefaultPatterns(); expect(list.inputs.activeItem()).toBe(list.inputs.items()[0]); list.search('b'); @@ -350,36 +383,35 @@ describe('List Behavior', () => { expect(list.inputs.activeItem()).toBe(list.inputs.items()[3]); // Blackberry list.search('u'); expect(list.inputs.activeItem()).toBe(list.inputs.items()[4]); // Blueberry - - tick(500); // Default delay + await delay(500); list.search('c'); expect(list.inputs.activeItem()).toBe(list.inputs.items()[5]); // Cantaloupe - })); + }); - it('should respect typeaheadDelay', fakeAsync(() => { - const {list} = getDefaultPatterns({typeaheadDelay: signal(0.1)}); + it('should respect typeaheadDelay', async () => { + const {list} = getDefaultPatterns({typeaheadDelay: signal(100)}); list.search('b'); expect(list.inputs.activeItem()).toBe(list.inputs.items()[2]); // Banana - tick(50); // Less than delay + await delay(50); // Less than delay list.search('l'); expect(list.inputs.activeItem()).toBe(list.inputs.items()[3]); // Blackberry - tick(101); // More than delay + await delay(101); // More than delay list.search('c'); expect(list.inputs.activeItem()).toBe(list.inputs.items()[5]); // Cantaloupe - })); + }); it('should select an item via typeahead', () => { const {list} = getDefaultPatterns({multi: signal(false)}); list.search('b', {selectOne: true}); - expect(list.inputs.value()).toEqual(['Banana']); + expect(list.inputs.values()).toEqual(['Banana']); }); it('should not select a non-selectable item via typeahead', () => { const {list, items} = getDefaultPatterns({multi: signal(false)}); items[2].selectable.set(false); // 'Banana' list.search('b', {selectOne: true}); - expect(list.inputs.value()).toEqual([]); + expect(list.inputs.values()).toEqual([]); }); }); }); diff --git a/src/aria/ui-patterns/behaviors/list/list.ts b/src/aria/private/behaviors/list/list.ts similarity index 93% rename from src/aria/ui-patterns/behaviors/list/list.ts rename to src/aria/private/behaviors/list/list.ts index 49576d5902ac..cd9ac11d914d 100644 --- a/src/aria/ui-patterns/behaviors/list/list.ts +++ b/src/aria/private/behaviors/list/list.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed, signal} from '@angular/core'; +import {computed, signal} from '../signal-like/signal-like'; import {ListFocus, ListFocusInputs, ListFocusItem} from '../list-focus/list-focus'; import { ListNavigation, @@ -64,10 +64,10 @@ export class List, V> { disabled = computed(() => this.focusBehavior.isListDisabled()); /** The id of the current active item. */ - activedescendant = computed(() => this.focusBehavior.getActiveDescendant()); + activeDescendant = computed(() => this.focusBehavior.getActiveDescendant()); - /** The tabindex of the list. */ - tabindex = computed(() => this.focusBehavior.getListTabindex()); + /** The tab index of the list. */ + tabIndex = computed(() => this.focusBehavior.getListTabIndex()); /** The index of the currently active item in the list. */ activeIndex = computed(() => this.focusBehavior.activeIndex()); @@ -100,9 +100,9 @@ export class List, V> { }); } - /** Returns the tabindex for the given item. */ + /** Returns the tab index for the given item. */ getItemTabindex(item: T) { - return this.focusBehavior.getItemTabindex(item); + return this.focusBehavior.getItemTabIndex(item); } /** Navigates to the first option in the list. */ @@ -161,8 +161,8 @@ export class List, V> { } /** Deselects the currently active item in the list. */ - deselect() { - this.selectionBehavior.deselect(); + deselect(item?: T) { + this.selectionBehavior.deselect(item); } /** Deselects all items in the list. */ @@ -171,8 +171,8 @@ export class List, V> { } /** Toggles the currently active item in the list. */ - toggle() { - this.selectionBehavior.toggle(); + toggle(item?: T) { + this.selectionBehavior.toggle(item); } /** Toggles the currently active item in the list, deselecting all other items. */ diff --git a/src/aria/ui-patterns/behaviors/popup/BUILD.bazel b/src/aria/private/behaviors/popup/BUILD.bazel similarity index 84% rename from src/aria/ui-patterns/behaviors/popup/BUILD.bazel rename to src/aria/private/behaviors/popup/BUILD.bazel index 3702057adb4a..e8a28821a272 100644 --- a/src/aria/ui-patterns/behaviors/popup/BUILD.bazel +++ b/src/aria/private/behaviors/popup/BUILD.bazel @@ -10,7 +10,7 @@ ts_project( ), deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/signal-like", ], ) @@ -21,6 +21,7 @@ ng_project( deps = [ ":popup", "//:node_modules/@angular/core", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/ui-patterns/behaviors/popup/popup.spec.ts b/src/aria/private/behaviors/popup/popup.spec.ts similarity index 96% rename from src/aria/ui-patterns/behaviors/popup/popup.spec.ts rename to src/aria/private/behaviors/popup/popup.spec.ts index cf7795d5eac4..ace9271cbe86 100644 --- a/src/aria/ui-patterns/behaviors/popup/popup.spec.ts +++ b/src/aria/private/behaviors/popup/popup.spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {signal} from '@angular/core'; +import {signal} from '../signal-like/signal-like'; import {PopupTypes, PopupControl, PopupControlInputs} from './popup'; type TestInputs = Partial>; diff --git a/src/aria/ui-patterns/behaviors/popup/popup.ts b/src/aria/private/behaviors/popup/popup.ts similarity index 100% rename from src/aria/ui-patterns/behaviors/popup/popup.ts rename to src/aria/private/behaviors/popup/popup.ts diff --git a/src/aria/ui-patterns/behaviors/signal-like/BUILD.bazel b/src/aria/private/behaviors/signal-like/BUILD.bazel similarity index 73% rename from src/aria/ui-patterns/behaviors/signal-like/BUILD.bazel rename to src/aria/private/behaviors/signal-like/BUILD.bazel index d8dda4c30030..c029acaf49b9 100644 --- a/src/aria/ui-patterns/behaviors/signal-like/BUILD.bazel +++ b/src/aria/private/behaviors/signal-like/BUILD.bazel @@ -5,5 +5,7 @@ package(default_visibility = ["//visibility:public"]) ts_project( name = "signal-like", srcs = ["signal-like.ts"], - deps = [], + deps = [ + "//:node_modules/@angular/core", + ], ) diff --git a/src/aria/private/behaviors/signal-like/signal-like.ts b/src/aria/private/behaviors/signal-like/signal-like.ts new file mode 100644 index 000000000000..ee11e6ff9fa9 --- /dev/null +++ b/src/aria/private/behaviors/signal-like/signal-like.ts @@ -0,0 +1,66 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + createComputed, + createLinkedSignal, + createSignal, + linkedSignalSetFn, + linkedSignalUpdateFn, + SIGNAL, + untracked as primitiveUntracked, +} from '@angular/core/primitives/signals'; + +export {primitiveUntracked as untracked}; + +export type SignalLike = () => T; + +export interface WritableSignalLike extends SignalLike { + set(value: T): void; + update(updateFn: (value: T) => T): void; + asReadonly(): SignalLike; +} + +/** Converts a getter setter style signal to a WritableSignalLike. */ +export function convertGetterSetterToWritableSignalLike( + getter: () => T, + setter: (v: T) => void, +): WritableSignalLike { + // tslint:disable-next-line:ban Have to use `Object.assign` to preserve the getter function. + return Object.assign(getter, { + set: setter, + update: (updateCallback: (v: T) => T) => setter(updateCallback(getter())), + asReadonly: () => getter, + }); +} + +export function computed(computation: () => T): SignalLike { + const computed = createComputed(computation); + // TODO: Remove the `toString` after https://github.com/angular/angular/pull/65948 is merged. + computed.toString = () => `[Computed: ${computed()}]`; + computed[SIGNAL].debugName = ''; + return computed; +} + +export function signal(initialValue: T): WritableSignalLike { + const [get, set, update] = createSignal(initialValue); + get[SIGNAL].debugName = ''; + // tslint:disable-next-line:ban Have to use `Object.assign` to preserve the getter function. + return Object.assign(get, {set, update, asReadonly: () => get}); +} + +export function linkedSignal(sourceFn: () => T): WritableSignalLike { + const getter = createLinkedSignal(sourceFn, s => s); + getter[SIGNAL].debugName = ''; + // tslint:disable-next-line:ban Have to use `Object.assign` to preserve the getter function. + return Object.assign(getter, { + set: (v: T) => linkedSignalSetFn(getter[SIGNAL], v), + update: (updater: (v: T) => T) => linkedSignalUpdateFn(getter[SIGNAL], updater), + asReadonly: () => getter, + }); +} diff --git a/src/aria/ui-patterns/combobox/BUILD.bazel b/src/aria/private/combobox/BUILD.bazel similarity index 67% rename from src/aria/ui-patterns/combobox/BUILD.bazel rename to src/aria/private/combobox/BUILD.bazel index 4dda9b51a441..61c73f8a68a8 100644 --- a/src/aria/ui-patterns/combobox/BUILD.bazel +++ b/src/aria/private/combobox/BUILD.bazel @@ -10,9 +10,9 @@ ts_project( ), deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/event-manager", - "//src/aria/ui-patterns/behaviors/list", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/event-manager", + "//src/aria/private/behaviors/list", + "//src/aria/private/behaviors/signal-like", ], ) @@ -23,9 +23,9 @@ ts_project( deps = [ ":combobox", "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", - "//src/aria/ui-patterns/listbox", - "//src/aria/ui-patterns/tree", + "//src/aria/private/behaviors/signal-like", + "//src/aria/private/listbox", + "//src/aria/private/tree", "//src/cdk/keycodes", "//src/cdk/testing/private", ], diff --git a/src/aria/ui-patterns/combobox/combobox.spec.ts b/src/aria/private/combobox/combobox.spec.ts similarity index 73% rename from src/aria/ui-patterns/combobox/combobox.spec.ts rename to src/aria/private/combobox/combobox.spec.ts index 9d18703e841e..7b71471193b6 100644 --- a/src/aria/ui-patterns/combobox/combobox.spec.ts +++ b/src/aria/private/combobox/combobox.spec.ts @@ -6,23 +6,22 @@ * found in the LICENSE file at https://angular.dev/license */ -import {signal, WritableSignal} from '@angular/core'; import {ComboboxInputs, ComboboxPattern} from './combobox'; import {OptionPattern} from '../listbox/option'; import {ComboboxListboxPattern} from '../listbox/combobox-listbox'; import {createKeyboardEvent} from '@angular/cdk/testing/private'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; +import {SignalLike, signal, WritableSignalLike} from '../behaviors/signal-like/signal-like'; import {ModifierKeys} from '@angular/cdk/testing'; import {TreeItemPattern} from '../tree/tree'; import {ComboboxTreePattern} from '../tree/combobox-tree'; // Test types type TestOption = OptionPattern & { - disabled: WritableSignal; + disabled: WritableSignalLike; }; type TestInputs = { - readonly [K in keyof ComboboxInputs]: WritableSignal< + readonly [K in keyof ComboboxInputs]: WritableSignalLike< ComboboxInputs[K] extends SignalLike ? T : never >; }; @@ -65,7 +64,7 @@ function _type( combobox: ComboboxPattern, allOptions: TestOption[] | TreeItemPattern[], popup: ComboboxListboxPattern | ComboboxTreePattern, - firstMatch: WritableSignal, + firstMatch: WritableSignalLike, backspace = false, ) { combobox.onFocusIn(); @@ -77,9 +76,9 @@ function _type( ); const options = allOptions.filter(o => o.searchTerm().startsWith(text)); if (popup instanceof ComboboxListboxPattern) { - (popup.inputs.items as WritableSignal).set(options); + (popup.inputs.items as WritableSignalLike).set(options); } else if (popup instanceof ComboboxTreePattern) { - (popup.inputs.allItems as WritableSignal).set(options); + (popup.inputs.allItems as WritableSignalLike).set(options); } firstMatch.set(options[0]?.value()); combobox.onFilter(); @@ -87,7 +86,7 @@ function _type( function getComboboxPattern( inputs: Partial<{ - [K in keyof TestInputs]: TestInputs[K] extends WritableSignal ? T : never; + [K in keyof TestInputs]: TestInputs[K] extends WritableSignalLike ? T : never; }> = {}, ) { const containerEl = signal(document.createElement('div')); @@ -106,6 +105,7 @@ function getComboboxPattern( filterMode: signal(inputs.filterMode ?? 'manual'), firstMatch, inputValue, + alwaysExpanded: signal(false), }); return {combobox, inputEl, containerEl, firstMatch, inputValue}; @@ -121,14 +121,14 @@ function getListboxPattern( const listbox = new ComboboxListboxPattern({ id: signal('listbox-1'), items: options, - value: signal(initialValue ? [initialValue] : []), + values: signal(initialValue ? [initialValue] : []), combobox: signal(combobox) as any, activeItem: signal(undefined), - typeaheadDelay: signal(0.5), + typeaheadDelay: signal(500), wrap: signal(true), readonly: signal(false), disabled: signal(false), - skipDisabled: signal(true), + softDisabled: signal(true), multi: signal(false), focusMode: signal('activedescendant'), textDirection: signal('ltr'), @@ -165,13 +165,13 @@ function getTreePattern( const tree = new ComboboxTreePattern({ id: signal('tree-1'), allItems: items, - value: signal(initialValue ? [initialValue] : []), + values: signal(initialValue ? [initialValue] : []), combobox: signal(combobox) as any, activeItem: signal(undefined), - typeaheadDelay: signal(0.5), + typeaheadDelay: signal(500), wrap: signal(true), disabled: signal(false), - skipDisabled: signal(true), + softDisabled: signal(true), multi: signal(false), focusMode: signal('activedescendant'), textDirection: signal('ltr'), @@ -192,9 +192,10 @@ function getTreePattern( element.role = 'treeitem'; const treeItem = new TreeItemPattern({ value: signal(node.value), - id: signal('tree-item-' + tree.allItems().length), + id: signal('tree-item-' + tree.inputs.allItems().length), disabled: signal(false), selectable: signal(true), + expanded: signal(false), searchTerm: signal(node.value), tree: signal(tree), parent: signal(parent), @@ -203,13 +204,13 @@ function getTreePattern( children: signal([]), }); - (tree.allItems as WritableSignal[]>).update(items => + (tree.inputs.allItems as WritableSignalLike[]>).update(items => items.concat(treeItem), ); if (node.children) { const children = createTreeItems(node.children, treeItem); - (treeItem.children as WritableSignal[]>).set(children); + (treeItem.inputs.children as WritableSignalLike[]>).set(children); } return treeItem; @@ -223,7 +224,7 @@ function getTreePattern( describe('Combobox with Listbox Pattern', () => { function getPatterns( inputs: Partial<{ - [K in keyof TestInputs]: TestInputs[K] extends WritableSignal ? T : never; + [K in keyof TestInputs]: TestInputs[K] extends WritableSignalLike ? T : never; }> = {}, ) { const {combobox, inputEl, containerEl, firstMatch, inputValue} = getComboboxPattern(inputs); @@ -239,7 +240,7 @@ describe('Combobox with Listbox Pattern', () => { 'Cranberry', ]); - (combobox.inputs.popupControls as WritableSignal).set(listbox); + (combobox.inputs.popupControls as WritableSignalLike).set(listbox); return { combobox, @@ -295,13 +296,6 @@ describe('Combobox with Listbox Pattern', () => { }); describe('Expansion', () => { - it('should open on click', () => { - const {combobox, inputEl} = getPatterns(); - expect(combobox.expanded()).toBe(false); - combobox.onPointerup(clickInput(inputEl)); - expect(combobox.expanded()).toBe(true); - }); - it('should open on ArrowDown', () => { const {combobox} = getPatterns(); expect(combobox.expanded()).toBe(false); @@ -332,6 +326,15 @@ describe('Combobox with Listbox Pattern', () => { expect(combobox.expanded()).toBe(false); }); + it('should not close on Enter if the option is disabled', () => { + const {combobox, options} = getPatterns(); + options()[0].disabled.set(true); + combobox.onKeydown(down()); + expect(combobox.expanded()).toBe(true); + combobox.onKeydown(enter()); + expect(combobox.expanded()).toBe(true); + }); + it('should close on focusout', () => { const {combobox} = getPatterns(); combobox.onKeydown(down()); @@ -357,7 +360,7 @@ describe('Combobox with Listbox Pattern', () => { it('should not expand when disabled', () => { const {combobox, inputEl} = getPatterns({disabled: true}); expect(combobox.expanded()).toBe(false); - combobox.onPointerup(clickInput(inputEl)); + combobox.onClick(clickInput(inputEl)); expect(combobox.expanded()).toBe(false); }); }); @@ -367,7 +370,7 @@ describe('Combobox with Listbox Pattern', () => { let listbox: ComboboxListboxPattern; let inputEl: HTMLInputElement; let options: () => TestOption[]; - let firstMatch: WritableSignal; + let firstMatch: WritableSignalLike; function type(text: string, opts: {backspace?: boolean} = {}) { _type(text, inputEl, combobox, options(), listbox, firstMatch, opts.backspace); @@ -381,55 +384,55 @@ describe('Combobox with Listbox Pattern', () => { }); it('should select and commit on click', () => { - combobox.onPointerup(clickOption(listbox.inputs.items(), 0)); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + combobox.onClick(clickOption(listbox.inputs.items(), 0)); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); + expect(listbox.inputs.values()).toEqual(['Apple']); expect(inputEl.value).toBe('Apple'); }); it('should select and commit to input on Enter', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); + expect(listbox.inputs.values()).toEqual(['Apple']); expect(inputEl.value).toBe('Apple'); }); it('should select on focusout if the input text exactly matches an item', () => { type('Apple'); combobox.onFocusOut(new FocusEvent('focusout')); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); + expect(listbox.inputs.values()).toEqual(['Apple']); }); - it('should deselect on backspace', () => { + it('should deselect on close if the input text does not match any options', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); + expect(listbox.inputs.values()).toEqual(['Apple']); type('Appl', {backspace: true}); - combobox.onInput(new InputEvent('input', {inputType: 'deleteContentBackward'})); - - expect(listbox.getSelectedItem()).toBe(undefined); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual(['Apple']); + combobox.onKeydown(escape()); + expect(listbox.inputs.values()).toEqual([]); }); it('should not select on navigation', () => { combobox.onKeydown(down()); - expect(listbox.getSelectedItem()).toBe(undefined); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.getSelectedItems().length).toBe(0); + expect(listbox.inputs.values()).toEqual([]); }); it('should not select on input', () => { type('A'); - expect(listbox.getSelectedItem()).toBe(undefined); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.getSelectedItems().length).toBe(0); + expect(listbox.inputs.values()).toEqual([]); }); it('should not select on focusout if the input text does not match an item', () => { type('Appl'); combobox.onFocusOut(new FocusEvent('focusout')); - expect(listbox.getSelectedItem()).toBe(undefined); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.getSelectedItems().length).toBe(0); + expect(listbox.inputs.values()).toEqual([]); expect(inputEl.value).toBe('Appl'); }); }); @@ -442,9 +445,9 @@ describe('Combobox with Listbox Pattern', () => { }); it('should select and commit on click', () => { - combobox.onPointerup(clickOption(listbox.inputs.items(), 3)); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[3]); - expect(listbox.inputs.value()).toEqual(['Blackberry']); + combobox.onClick(clickOption(listbox.inputs.items(), 3)); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[3]); + expect(listbox.inputs.values()).toEqual(['Blackberry']); expect(inputEl.value).toBe('Blackberry'); }); @@ -453,38 +456,38 @@ describe('Combobox with Listbox Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[2]); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[2]); + expect(listbox.inputs.values()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should select the last item on arrow up when collapsed', () => { combobox.onKeydown(up()); - expect(listbox.getSelectedItem()).toBe( + expect(listbox.getSelectedItems()[0]).toBe( listbox.inputs.items()[listbox.inputs.items().length - 1], ); - expect(listbox.inputs.value()).toEqual(['Cranberry']); + expect(listbox.inputs.values()).toEqual(['Cranberry']); }); it('should select on navigation', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[1]); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[1]); + expect(listbox.inputs.values()).toEqual(['Apricot']); }); it('should select the first option on input', () => { type('A'); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); type('Apr'); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); }); it('should commit the selected option on focusout', () => { @@ -493,6 +496,13 @@ describe('Combobox with Listbox Pattern', () => { combobox.onFocusOut(new FocusEvent('focusout')); expect(inputEl.value).toBe('Apple'); }); + + it('should not commit an option on focusout if the popup is closed', () => { + type('A'); + combobox.onKeydown(escape()); + combobox.onFocusOut(new FocusEvent('focusout')); + expect(inputEl.value).toBe('A'); + }); }); describe('when filterMode is "highlight"', () => { @@ -503,9 +513,9 @@ describe('Combobox with Listbox Pattern', () => { }); it('should select and commit on click', () => { - combobox.onPointerup(clickOption(listbox.inputs.items(), 3)); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[3]); - expect(listbox.inputs.value()).toEqual(['Blackberry']); + combobox.onClick(clickOption(listbox.inputs.items(), 3)); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[3]); + expect(listbox.inputs.values()).toEqual(['Blackberry']); expect(inputEl.value).toBe('Blackberry'); }); @@ -514,38 +524,38 @@ describe('Combobox with Listbox Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[2]); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[2]); + expect(listbox.inputs.values()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should select the last item on arrow up when collapsed', () => { combobox.onKeydown(up()); - expect(listbox.getSelectedItem()).toBe( + expect(listbox.getSelectedItems()[0]).toBe( listbox.inputs.items()[listbox.inputs.items().length - 1], ); - expect(listbox.inputs.value()).toEqual(['Cranberry']); + expect(listbox.inputs.values()).toEqual(['Cranberry']); }); it('should select on navigation', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); - expect(listbox.getSelectedItem()).toBe(listbox.inputs.items()[1]); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[1]); + expect(listbox.inputs.values()).toEqual(['Apricot']); }); it('should select the first option on input', () => { type('A'); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); type('Apr'); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); }); it('should commit the selected option on navigation', () => { @@ -585,12 +595,46 @@ describe('Combobox with Listbox Pattern', () => { }); }); }); + + describe('Readonly mode', () => { + describe('with single-select', () => { + it('should select and close on selection', () => { + const {combobox, listbox, inputEl} = getPatterns({readonly: true}); + combobox.onClick(clickOption(listbox.inputs.items(), 2)); + expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[2]); + expect(listbox.inputs.values()).toEqual(['Banana']); + expect(inputEl.value).toBe('Banana'); + expect(combobox.expanded()).toBe(false); + }); + + it('should close on escape', () => { + const {combobox} = getPatterns({readonly: true}); + combobox.onKeydown(down()); + expect(combobox.expanded()).toBe(true); + combobox.onKeydown(escape()); + expect(combobox.expanded()).toBe(false); + }); + }); + + describe('with multi-select', () => { + it('should allow users to select multiple options', () => { + const {combobox, listbox, inputEl} = getPatterns({readonly: true}); + (listbox.inputs.multi as WritableSignalLike).set(true); + + combobox.onClick(clickOption(listbox.inputs.items(), 1)); + combobox.onClick(clickOption(listbox.inputs.items(), 2)); + + expect(listbox.inputs.values()).toEqual(['Apricot', 'Banana']); + expect(inputEl.value).toBe('Apricot, Banana'); + }); + }); + }); }); describe('Combobox with Tree Pattern', () => { function getPatterns( inputs: Partial<{ - [K in keyof TestInputs]: TestInputs[K] extends WritableSignal ? T : never; + [K in keyof TestInputs]: TestInputs[K] extends WritableSignalLike ? T : never; }> = {}, ) { const {combobox, inputEl, containerEl, firstMatch, inputValue} = getComboboxPattern(inputs); @@ -600,7 +644,7 @@ describe('Combobox with Tree Pattern', () => { {value: 'Grains', children: [{value: 'Rice'}, {value: 'Wheat'}]}, ]); - (combobox.inputs.popupControls as WritableSignal).set(tree); + (combobox.inputs.popupControls as WritableSignalLike).set(tree); return { combobox, @@ -698,7 +742,7 @@ describe('Combobox with Tree Pattern', () => { let tree: ComboboxTreePattern; let inputEl: HTMLInputElement; let items: () => TreeItemPattern[]; - let firstMatch: WritableSignal; + let firstMatch: WritableSignalLike; function type(text: string, opts: {backspace?: boolean} = {}) { _type(text, inputEl, combobox, items(), tree, firstMatch, opts.backspace); @@ -712,53 +756,54 @@ describe('Combobox with Tree Pattern', () => { }); it('should select and commit on click', () => { - combobox.onPointerup(clickTreeItem(tree.inputs.allItems(), 0)); - expect(tree.inputs.value()).toEqual(['Fruit']); + combobox.onClick(clickTreeItem(tree.inputs.allItems(), 0)); + expect(tree.inputs.values()).toEqual(['Fruit']); expect(inputEl.value).toBe('Fruit'); }); it('should select and commit to input on Enter', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(tree.getSelectedItem()).toBe(tree.inputs.allItems()[0]); - expect(tree.inputs.value()).toEqual(['Fruit']); + expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[0]); + expect(tree.inputs.values()).toEqual(['Fruit']); expect(inputEl.value).toBe('Fruit'); }); it('should select on focusout if the input text exactly matches an item', () => { - combobox.onPointerup(clickInput(inputEl)); + combobox.onClick(clickInput(inputEl)); type('Apple'); combobox.onFocusOut(new FocusEvent('focusout')); - expect(tree.inputs.value()).toEqual(['Apple']); + expect(tree.inputs.values()).toEqual(['Apple']); }); - it('should deselect on backspace', () => { + it('should deselect on close if the input text does not match any options', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); - type('Appl', {backspace: true}); - - expect(tree.getSelectedItem()).toBe(undefined); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual(['Fruit']); + type('Frui', {backspace: true}); + expect(tree.inputs.values()).toEqual(['Fruit']); + combobox.onKeydown(escape()); + expect(tree.inputs.values()).toEqual([]); }); it('should not select on navigation', () => { combobox.onKeydown(down()); - expect(tree.getSelectedItem()).toBe(undefined); - expect(tree.inputs.value()).toEqual([]); + expect(tree.getSelectedItems().length).toBe(0); + expect(tree.inputs.values()).toEqual([]); }); it('should not select on input', () => { type('A'); - expect(tree.getSelectedItem()).toBe(undefined); - expect(tree.inputs.value()).toEqual([]); + expect(tree.getSelectedItems().length).toBe(0); + expect(tree.inputs.values()).toEqual([]); }); it('should not select on focusout if the input text does not match an item', () => { type('Appl'); combobox.onFocusOut(new FocusEvent('focusout')); - expect(tree.getSelectedItem()).toBe(undefined); - expect(tree.inputs.value()).toEqual([]); + expect(tree.getSelectedItems().length).toBe(0); + expect(tree.inputs.values()).toEqual([]); expect(inputEl.value).toBe('Appl'); }); }); @@ -771,9 +816,9 @@ describe('Combobox with Tree Pattern', () => { }); it('should select and commit on click', () => { - combobox.onPointerup(clickTreeItem(tree.inputs.allItems(), 2)); - expect(tree.getSelectedItem()).toBe(tree.inputs.allItems()[2]); - expect(tree.inputs.value()).toEqual(['Banana']); + combobox.onClick(clickTreeItem(tree.inputs.allItems(), 2)); + expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[2]); + expect(tree.inputs.values()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); @@ -782,34 +827,34 @@ describe('Combobox with Tree Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Grains']); + expect(tree.inputs.values()).toEqual(['Grains']); expect(inputEl.value).toBe('Grains'); }); it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); - expect(tree.getSelectedItem()).toBe(tree.inputs.allItems()[0]); - expect(tree.inputs.value()).toEqual(['Fruit']); + expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[0]); + expect(tree.inputs.values()).toEqual(['Fruit']); }); it('should select the last focusable item on arrow up when collapsed', () => { combobox.onKeydown(up()); - expect(tree.inputs.value()).toEqual(['Grains']); + expect(tree.inputs.values()).toEqual(['Grains']); }); it('should select on navigation', () => { combobox.onKeydown(down()); combobox.onKeydown(right()); combobox.onKeydown(right()); - expect(tree.inputs.value()).toEqual(['Apple']); + expect(tree.inputs.values()).toEqual(['Apple']); }); it('should select the first option on input', () => { type('B'); - expect(tree.inputs.value()).toEqual(['Banana']); + expect(tree.inputs.values()).toEqual(['Banana']); type('Bro'); - expect(tree.inputs.value()).toEqual(['Broccoli']); + expect(tree.inputs.values()).toEqual(['Broccoli']); }); it('should commit the selected option on focusout', () => { @@ -828,9 +873,9 @@ describe('Combobox with Tree Pattern', () => { }); it('should select and commit on click', () => { - combobox.onPointerup(clickTreeItem(tree.inputs.allItems(), 2)); - expect(tree.getSelectedItem()).toBe(tree.inputs.allItems()[2]); - expect(tree.inputs.value()).toEqual(['Banana']); + combobox.onClick(clickTreeItem(tree.inputs.allItems(), 2)); + expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[2]); + expect(tree.inputs.values()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); @@ -839,34 +884,34 @@ describe('Combobox with Tree Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Grains']); + expect(tree.inputs.values()).toEqual(['Grains']); expect(inputEl.value).toBe('Grains'); }); it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); - expect(tree.getSelectedItem()).toBe(tree.inputs.allItems()[0]); - expect(tree.inputs.value()).toEqual(['Fruit']); + expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[0]); + expect(tree.inputs.values()).toEqual(['Fruit']); }); it('should select the last focusable item on arrow up when collapsed', () => { combobox.onKeydown(up()); - expect(tree.inputs.value()).toEqual(['Grains']); + expect(tree.inputs.values()).toEqual(['Grains']); }); it('should select on navigation', () => { combobox.onKeydown(down()); combobox.onKeydown(right()); combobox.onKeydown(right()); - expect(tree.inputs.value()).toEqual(['Apple']); + expect(tree.inputs.values()).toEqual(['Apple']); }); it('should select the first option on input', () => { type('B'); - expect(tree.inputs.value()).toEqual(['Banana']); + expect(tree.inputs.values()).toEqual(['Banana']); type('Bro'); - expect(tree.inputs.value()).toEqual(['Broccoli']); + expect(tree.inputs.values()).toEqual(['Broccoli']); }); it('should commit the selected option on navigation', () => { @@ -876,7 +921,7 @@ describe('Combobox with Tree Pattern', () => { combobox.onKeydown(right()); expect(inputEl.value).toBe('Apple'); combobox.onKeydown(down()); - expect(tree.inputs.value()).toEqual(['Banana']); + expect(tree.inputs.values()).toEqual(['Banana']); }); it('should commit the selected option on focusout', () => { @@ -894,4 +939,24 @@ describe('Combobox with Tree Pattern', () => { }); }); }); + + describe('Readonly mode', () => { + it('should select and close on selection', () => { + const {combobox, tree, inputEl} = getPatterns({readonly: true}); + combobox.onClick(clickInput(inputEl)); + expect(combobox.expanded()).toBe(true); + combobox.onClick(clickTreeItem(tree.inputs.allItems(), 0)); + expect(tree.inputs.values()).toEqual(['Fruit']); + expect(inputEl.value).toBe('Fruit'); + expect(combobox.expanded()).toBe(false); + }); + + it('should close on escape', () => { + const {combobox} = getPatterns({readonly: true}); + combobox.onKeydown(down()); + expect(combobox.expanded()).toBe(true); + combobox.onKeydown(escape()); + expect(combobox.expanded()).toBe(false); + }); + }); }); diff --git a/src/aria/ui-patterns/combobox/combobox.ts b/src/aria/private/combobox/combobox.ts similarity index 51% rename from src/aria/ui-patterns/combobox/combobox.ts rename to src/aria/private/combobox/combobox.ts index 9d8163d68db5..0e20884fe071 100644 --- a/src/aria/ui-patterns/combobox/combobox.ts +++ b/src/aria/private/combobox/combobox.ts @@ -7,14 +7,20 @@ */ import {KeyboardEventManager, PointerEventManager} from '../behaviors/event-manager'; -import {computed, signal} from '@angular/core'; -import {SignalLike, WritableSignalLike} from '../behaviors/signal-like/signal-like'; +import { + computed, + signal, + SignalLike, + WritableSignalLike, +} from '../behaviors/signal-like/signal-like'; import {ListItem} from '../behaviors/list/list'; /** Represents the required inputs for a combobox. */ export interface ComboboxInputs, V> { /** The controls for the popup associated with the combobox. */ - popupControls: SignalLike | ComboboxTreeControls | undefined>; + popupControls: SignalLike< + ComboboxListboxControls | ComboboxTreeControls | ComboboxDialogPattern | undefined + >; /** The HTML input element that serves as the combobox input. */ inputEl: SignalLike; @@ -39,6 +45,9 @@ export interface ComboboxInputs, V> { /** Whether the combobox is in a right-to-left context. */ textDirection: SignalLike<'rtl' | 'ltr'>; + + /** Whether the combobox is always expanded. */ + alwaysExpanded: SignalLike; } /** An interface that allows combobox popups to expose the necessary controls for the combobox. */ @@ -49,6 +58,11 @@ export interface ComboboxListboxControls, V> { /** The ARIA role for the popup. */ role: SignalLike<'listbox' | 'tree' | 'grid'>; + // TODO(wagnermaciel): Add validation that ensures only readonly comboboxes can have multi-select popups. + + /** Whether multiple items in the popup can be selected at once. */ + multi: SignalLike; + /** The ID of the active item in the popup. */ activeId: SignalLike; @@ -56,7 +70,7 @@ export interface ComboboxListboxControls, V> { items: SignalLike; /** Navigates to the given item in the popup. */ - focus: (item: T) => void; + focus: (item: T, opts?: {focusElement?: boolean}) => void; /** Navigates to the next item in the popup. */ next: () => void; @@ -73,6 +87,9 @@ export interface ComboboxListboxControls, V> { /** Selects the current item in the popup. */ select: (item?: T) => void; + /** Toggles the selection state of the given item in the popup. */ + toggle: (item?: T) => void; + /** Clears the selection state of the popup. */ clearSelection: () => void; @@ -82,15 +99,20 @@ export interface ComboboxListboxControls, V> { /** Returns the item corresponding to the given event. */ getItem: (e: PointerEvent) => T | undefined; - /** Returns the currently selected item in the popup. */ - getSelectedItem: () => T | undefined; + /** Returns the currently active (focused) item in the popup. */ + getActiveItem: () => T | undefined; + + /** Returns the currently selected items in the popup. */ + getSelectedItems: () => T[]; /** Sets the value of the combobox based on the selected item. */ setValue: (value: V | undefined) => void; // For re-setting the value if the popup was destroyed. } -export interface ComboboxTreeControls, V> - extends ComboboxListboxControls { +export interface ComboboxTreeControls, V> extends ComboboxListboxControls< + T, + V +> { /** Whether the currently active item in the popup is collapsible. */ isItemCollapsible: () => boolean; @@ -101,13 +123,19 @@ export interface ComboboxTreeControls, V> collapseItem: () => void; /** Checks if the currently active item in the popup is expandable. */ - isItemExpandable: () => boolean; + isItemExpandable: (item?: T) => boolean; /** Expands all nodes in the tree. */ expandAll: () => void; /** Collapses all nodes in the tree. */ collapseAll: () => void; + + /** Toggles the expansion state of the currently active item in the popup. */ + toggleExpansion: (item?: T) => void; + + /** Whether the current active item is selectable. */ + isItemSelectable: (item?: T) => boolean; } /** Controls the state of a combobox. */ @@ -115,8 +143,18 @@ export class ComboboxPattern, V> { /** Whether the combobox is expanded. */ expanded = signal(false); + /** Whether the combobox is disabled. */ + disabled = () => this.inputs.disabled(); + /** The ID of the active item in the combobox. */ - activedescendant = computed(() => this.inputs.popupControls()?.activeId() ?? null); + activeDescendant = computed(() => { + const popupControls = this.inputs.popupControls(); + if (popupControls instanceof ComboboxDialogPattern) { + return null; + } + + return popupControls?.activeId() ?? null; + }); /** The currently highlighted item in the combobox. */ highlightedItem = signal(undefined); @@ -127,6 +165,9 @@ export class ComboboxPattern, V> { /** Whether the combobox is focused. */ isFocused = signal(false); + /** Whether the combobox has ever been focused. */ + hasBeenFocused = signal(false); + /** The key used to navigate to the previous item in the list. */ expandKey = computed(() => (this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight')); @@ -144,72 +185,139 @@ export class ComboboxPattern, V> { /** The ARIA role of the popup associated with the combobox. */ hasPopup = computed(() => this.inputs.popupControls()?.role() || null); - /** Whether the combobox is interactive. */ - isInteractive = computed(() => !this.inputs.disabled() && !this.inputs.readonly()); + /** Whether the combobox is read-only. */ + readonly = computed(() => this.inputs.readonly() || this.inputs.disabled() || null); + + /** Returns the listbox controls for the combobox. */ + listControls = () => { + const popupControls = this.inputs.popupControls(); + + if (popupControls instanceof ComboboxDialogPattern) { + return null; + } + + return popupControls; + }; + + /** Returns the tree controls for the combobox. */ + treeControls = () => { + const popupControls = this.inputs.popupControls(); + + if (popupControls?.role() === 'tree') { + return popupControls as ComboboxTreeControls; + } + + return null; + }; /** The keydown event manager for the combobox. */ keydown = computed(() => { + const manager = new KeyboardEventManager(); + const popupControls = this.inputs.popupControls(); + + if (!popupControls) { + return manager; + } + + if (popupControls instanceof ComboboxDialogPattern) { + if (!this.expanded()) { + manager.on('ArrowUp', () => this.open()).on('ArrowDown', () => this.open()); + + if (this.readonly()) { + manager.on('Enter', () => this.open()).on(' ', () => this.open()); + } + } + + return manager; + } + + if (!this.inputs.alwaysExpanded()) { + manager.on('Escape', () => this.close({reset: !this.readonly()})); + } + if (!this.expanded()) { - return new KeyboardEventManager() + manager .on('ArrowDown', () => this.open({first: true})) .on('ArrowUp', () => this.open({last: true})); - } - const popupControls = this.inputs.popupControls(); + if (this.readonly()) { + manager + .on('Enter', () => this.open({selected: true})) + .on(' ', () => this.open({selected: true})); + } - if (!popupControls) { - return new KeyboardEventManager(); + return manager; } - const manager = new KeyboardEventManager() + manager .on('ArrowDown', () => this.next()) .on('ArrowUp', () => this.prev()) .on('Home', () => this.first()) - .on('End', () => this.last()) - .on('Escape', () => { - // TODO(wagnermaciel): We may want to fold this logic into the close() method. - if (this.inputs.filterMode() === 'highlight' && popupControls.activeId()) { - popupControls.unfocus(); - popupControls.clearSelection(); - - const inputEl = this.inputs.inputEl(); - if (inputEl) { - inputEl.value = this.inputs.inputValue!(); - } - } else { - this.close(); - this.inputs.popupControls()?.clearSelection(); - } - }) // TODO: When filter mode is 'highlight', escape should revert to the last committed value. - .on('Enter', () => this.select({commit: true, close: true})); + .on('End', () => this.last()); + + if (this.readonly()) { + manager.on(' ', () => this.select({commit: true, close: !popupControls.multi()})); + } - if (popupControls.role() === 'tree') { - const treeControls = popupControls as ComboboxTreeControls; + if (popupControls.role() === 'listbox') { + manager.on('Enter', () => { + this.select({commit: true, close: !popupControls.multi()}); + }); + } - if (treeControls.isItemExpandable() || treeControls.isItemCollapsible()) { - manager.on(this.collapseKey(), () => this.collapseItem()); - } + const treeControls = this.treeControls(); - if (treeControls.isItemExpandable()) { - manager.on(this.expandKey(), () => this.expandItem()); + if (treeControls?.isItemSelectable()) { + manager.on('Enter', () => this.select({commit: true, close: true})); + } + + if (treeControls?.isItemExpandable()) { + manager + .on(this.expandKey(), () => this.expandItem()) + .on(this.collapseKey(), () => this.collapseItem()); + + if (!treeControls.isItemSelectable()) { + manager.on('Enter', () => this.expandItem()); } } + if (treeControls?.isItemCollapsible()) { + manager.on(this.collapseKey(), () => this.collapseItem()); + } + return manager; }); - /** The pointerup event manager for the combobox. */ - pointerup = computed(() => + /** The click event manager for the combobox. */ + click = computed(() => new PointerEventManager().on(e => { - const item = this.inputs.popupControls()?.getItem(e); + if (e.target === this.inputs.inputEl()) { + if (this.readonly()) { + this.expanded() ? this.close() : this.open({selected: true}); + } + } - if (item) { - this.select({item, commit: true, close: true}); - this.inputs.inputEl()?.focus(); // Return focus to the input after selecting. + const controls = this.inputs.popupControls(); + + if (controls instanceof ComboboxDialogPattern) { + return; } - if (e.target === this.inputs.inputEl()) { - this.open(); + const item = controls?.getItem(e); + + if (item) { + if (controls?.role() === 'tree') { + const treeControls = controls as ComboboxTreeControls; + + if (treeControls.isItemExpandable(item) && !treeControls.isItemSelectable(item)) { + treeControls.toggleExpansion(item); + this.inputs.inputEl()?.focus(); + return; + } + } + + this.select({item, commit: true, close: !controls?.multi()}); + this.inputs.inputEl()?.focus(); // Return focus to the input after selecting. } }), ); @@ -218,21 +326,21 @@ export class ComboboxPattern, V> { /** Handles keydown events for the combobox. */ onKeydown(event: KeyboardEvent) { - if (this.isInteractive()) { + if (!this.inputs.disabled()) { this.keydown().handle(event); } } - /** Handles pointerup events for the combobox. */ - onPointerup(event: PointerEvent) { - if (this.isInteractive()) { - this.pointerup().handle(event); + /** Handles click events for the combobox. */ + onClick(event: MouseEvent) { + if (!this.inputs.disabled()) { + this.click().handle(event as PointerEvent); } } /** Handles input events for the combobox. */ onInput(event: Event) { - if (!this.isInteractive()) { + if (this.inputs.disabled() || this.inputs.readonly()) { return; } @@ -242,27 +350,41 @@ export class ComboboxPattern, V> { return; } + const popupControls = this.inputs.popupControls(); + + if (popupControls instanceof ComboboxDialogPattern) { + return; + } + this.open(); this.inputs.inputValue?.set(inputEl.value); this.isDeleting = event instanceof InputEvent && !!event.inputType.match(/^delete/); - if (this.inputs.filterMode() === 'manual') { - const searchTerm = this.inputs.popupControls()?.getSelectedItem()?.searchTerm(); - - if (searchTerm && this.inputs.inputValue!() !== searchTerm) { - this.inputs.popupControls()?.clearSelection(); - } + if (this.inputs.filterMode() === 'highlight' && !this.isDeleting) { + this.highlight(); } } /** Handles focus in events for the combobox. */ onFocusIn() { + if (this.inputs.alwaysExpanded() && !this.hasBeenFocused()) { + const firstSelectedItem = this.listControls()?.getSelectedItems()[0]; + firstSelectedItem ? this.listControls()?.focus(firstSelectedItem) : this.first(); + } + this.isFocused.set(true); + this.hasBeenFocused.set(true); } /** Handles focus out events for the combobox. */ onFocusOut(event: FocusEvent) { - if (this.inputs.disabled() || this.inputs.readonly()) { + if (this.inputs.disabled()) { + return; + } + + const popupControls = this.inputs.popupControls(); + + if (popupControls instanceof ComboboxDialogPattern) { return; } @@ -271,11 +393,20 @@ export class ComboboxPattern, V> { !this.inputs.containerEl()?.contains(event.relatedTarget) ) { this.isFocused.set(false); + + if (!this.expanded()) { + return; + } + + if (this.readonly()) { + this.close(); + return; + } + if (this.inputs.filterMode() !== 'manual') { this.commit(); } else { - const item = this.inputs - .popupControls() + const item = popupControls ?.items() .find(i => i.searchTerm() === this.inputs.inputEl()?.value); @@ -293,18 +424,27 @@ export class ComboboxPattern, V> { // TODO(wagnermaciel): Consider whether we should not provide this default behavior for the // listbox. Instead, we may want to allow users to have no match so that typing does not focus // any option. - if (this.inputs.popupControls()?.role() === 'listbox') { - return this.inputs.popupControls()?.items()[0]; + if (this.listControls()?.role() === 'listbox') { + return this.listControls()?.items()[0]; } - return this.inputs - .popupControls() + return this.listControls() ?.items() .find(i => i.value() === this.inputs.firstMatch()); }); /** Handles filtering logic for the combobox. */ onFilter() { + if (this.readonly()) { + return; + } + + const popupControls = this.inputs.popupControls(); + + if (popupControls instanceof ComboboxDialogPattern) { + return; + } + // TODO(wagnermaciel) // When the user first interacts with the combobox, the popup will lazily render for the first // time. This is a simple way to detect this and avoid auto-focus & selection logic, but this @@ -328,12 +468,12 @@ export class ComboboxPattern, V> { const item = this.firstMatch(); if (!item) { - this.inputs.popupControls()?.clearSelection(); - this.inputs.popupControls()?.unfocus(); + popupControls?.clearSelection(); + popupControls?.unfocus(); return; } - this.inputs.popupControls()?.focus(item); + popupControls?.focus(item); if (this.inputs.filterMode() !== 'manual') { this.select({item}); @@ -347,7 +487,8 @@ export class ComboboxPattern, V> { /** Highlights the currently selected item in the combobox. */ highlight() { const inputEl = this.inputs.inputEl(); - const item = this.inputs.popupControls()?.getSelectedItem(); + const selectedItems = this.listControls()?.getSelectedItems(); + const item = selectedItems?.[0]; if (!inputEl || !item) { return; @@ -367,14 +508,85 @@ export class ComboboxPattern, V> { } /** Closes the combobox. */ - close() { - this.expanded.set(false); - this.inputs.popupControls()?.unfocus(); + close(opts?: {reset: boolean}) { + const popupControls = this.inputs.popupControls(); + + if (this.inputs.alwaysExpanded()) { + return; + } + + if (popupControls instanceof ComboboxDialogPattern) { + this.expanded.set(false); + return; + } + + if (this.readonly()) { + this.expanded.set(false); + popupControls?.unfocus(); + return; + } + + if (!opts?.reset) { + if (this.inputs.filterMode() === 'manual') { + if ( + !this.listControls() + ?.items() + .some(i => i.searchTerm() === this.inputs.inputEl()?.value) + ) { + this.listControls()?.clearSelection(); + } + } + + this.expanded.set(false); + popupControls?.unfocus(); + return; + } + + if (!this.expanded()) { + this.inputs.inputValue?.set(''); + popupControls?.clearSelection(); + + const inputEl = this.inputs.inputEl(); + + if (inputEl) { + inputEl.value = ''; + } + } else if (this.expanded()) { + this.expanded.set(false); + const selectedItem = popupControls?.getSelectedItems()?.[0]; + + if (selectedItem?.searchTerm() !== this.inputs.inputValue!()) { + popupControls?.clearSelection(); + } + + return; + } + + this.close(); + + if (!this.readonly()) { + popupControls?.clearSelection(); + } } /** Opens the combobox. */ - open(nav?: {first?: boolean; last?: boolean}) { + open(nav?: {first?: boolean; last?: boolean; selected?: boolean}) { this.expanded.set(true); + const popupControls = this.inputs.popupControls(); + + if (popupControls instanceof ComboboxDialogPattern) { + return; + } + + const inputEl = this.inputs.inputEl(); + + if (inputEl && this.inputs.filterMode() === 'highlight') { + const isHighlighting = inputEl.selectionStart !== inputEl.value.length; + this.inputs.inputValue?.set(inputEl.value.slice(0, inputEl.selectionStart || 0)); + if (!isHighlighting) { + this.highlightedItem.set(undefined); + } + } if (nav?.first) { this.first(); @@ -382,26 +594,35 @@ export class ComboboxPattern, V> { if (nav?.last) { this.last(); } + if (nav?.selected) { + const selectedItem = popupControls + ?.items() + .find(i => popupControls?.getSelectedItems().includes(i)); + + if (selectedItem) { + popupControls?.focus(selectedItem); + } + } } /** Navigates to the next focusable item in the combobox popup. */ next() { - this._navigate(() => this.inputs.popupControls()?.next()); + this._navigate(() => this.listControls()?.next()); } /** Navigates to the previous focusable item in the combobox popup. */ prev() { - this._navigate(() => this.inputs.popupControls()?.prev()); + this._navigate(() => this.listControls()?.prev()); } /** Navigates to the first focusable item in the combobox popup. */ first() { - this._navigate(() => this.inputs.popupControls()?.first()); + this._navigate(() => this.listControls()?.first()); } /** Navigates to the last focusable item in the combobox popup. */ last() { - this._navigate(() => this.inputs.popupControls()?.last()); + this._navigate(() => this.listControls()?.last()); } /** Collapses the currently focused item in the combobox. */ @@ -418,7 +639,19 @@ export class ComboboxPattern, V> { /** Selects an item in the combobox popup. */ select(opts: {item?: T; commit?: boolean; close?: boolean} = {}) { - this.inputs.popupControls()?.select(opts.item); + const controls = this.listControls(); + + const item = opts.item ?? controls?.getActiveItem(); + + if (item?.disabled()) { + return; + } + + if (opts.item) { + controls?.focus(opts.item, {focusElement: false}); + } + + controls?.multi() ? controls.toggle(opts.item) : controls?.select(opts.item); if (opts.commit) { this.commit(); @@ -431,16 +664,18 @@ export class ComboboxPattern, V> { /** Updates the value of the input based on the currently selected item. */ commit() { const inputEl = this.inputs.inputEl(); - const item = this.inputs.popupControls()?.getSelectedItem(); + const selectedItems = this.listControls()?.getSelectedItems(); - if (inputEl && item) { - inputEl.value = item.searchTerm(); - this.inputs.inputValue?.set(item.searchTerm()); + if (!inputEl) { + return; + } - if (this.inputs.filterMode() === 'highlight') { - const length = inputEl.value.length; - inputEl.setSelectionRange(length, length); - } + inputEl.value = selectedItems?.map(i => i.searchTerm()).join(', ') || ''; + this.inputs.inputValue?.set(inputEl.value); + + if (this.inputs.filterMode() === 'highlight' && !this.readonly()) { + const length = inputEl.value.length; + inputEl.setSelectionRange(length, length); } } @@ -455,7 +690,7 @@ export class ComboboxPattern, V> { if (this.inputs.filterMode() === 'highlight') { // This is to handle when the user navigates back to the originally highlighted item. // E.g. User types "Al", highlights "Alice", then navigates down and back up to "Alice". - const selectedItem = this.inputs.popupControls()?.getSelectedItem(); + const selectedItem = this.listControls()?.getSelectedItems()[0]; if (!selectedItem) { return; @@ -470,3 +705,32 @@ export class ComboboxPattern, V> { } } } + +export class ComboboxDialogPattern { + id = () => this.inputs.id(); + + role = () => 'dialog' as const; + + keydown = computed(() => { + return new KeyboardEventManager().on('Escape', () => this.inputs.combobox.close()); + }); + + constructor( + readonly inputs: { + combobox: ComboboxPattern; + element: SignalLike; + id: SignalLike; + }, + ) {} + + onKeydown(event: KeyboardEvent) { + this.keydown().handle(event); + } + + onClick(event: MouseEvent) { + // The "click" event fires on the dialog when the user clicks outside of the dialog content. + if (event.target === this.inputs.element()) { + this.inputs.combobox.close(); + } + } +} diff --git a/src/aria/deferred-content/BUILD.bazel b/src/aria/private/deferred-content/BUILD.bazel similarity index 100% rename from src/aria/deferred-content/BUILD.bazel rename to src/aria/private/deferred-content/BUILD.bazel diff --git a/src/aria/deferred-content/deferred-content.spec.ts b/src/aria/private/deferred-content/deferred-content.spec.ts similarity index 100% rename from src/aria/deferred-content/deferred-content.spec.ts rename to src/aria/private/deferred-content/deferred-content.spec.ts diff --git a/src/aria/deferred-content/deferred-content.ts b/src/aria/private/deferred-content/deferred-content.ts similarity index 70% rename from src/aria/deferred-content/deferred-content.ts rename to src/aria/private/deferred-content/deferred-content.ts index 6a42d10ebb70..d6ee311fa768 100644 --- a/src/aria/deferred-content/deferred-content.ts +++ b/src/aria/private/deferred-content/deferred-content.ts @@ -14,6 +14,8 @@ import { signal, ViewContainerRef, model, + EmbeddedViewRef, + OnDestroy, } from '@angular/core'; /** @@ -41,10 +43,11 @@ export class DeferredContentAware { * ``` */ @Directive() -export class DeferredContent { +export class DeferredContent implements OnDestroy { private readonly _deferredContentAware = inject(DeferredContentAware, {optional: true}); private readonly _templateRef = inject(TemplateRef); private readonly _viewContainerRef = inject(ViewContainerRef); + private _currentViewRef: EmbeddedViewRef | null = null; private _isRendered = false; readonly deferredContentAware = signal(this._deferredContentAware); @@ -52,14 +55,28 @@ export class DeferredContent { constructor() { afterRenderEffect(() => { if (this.deferredContentAware()?.contentVisible()) { - if (this._isRendered) return; - this._viewContainerRef.clear(); - this._viewContainerRef.createEmbeddedView(this._templateRef); - this._isRendered = true; + if (!this._isRendered) { + this._destroyContent(); + this._currentViewRef = this._viewContainerRef.createEmbeddedView(this._templateRef); + this._isRendered = true; + } } else if (!this.deferredContentAware()?.preserveContent()) { - this._viewContainerRef.clear(); + this._destroyContent(); this._isRendered = false; } }); } + + ngOnDestroy(): void { + this._destroyContent(); + } + + private _destroyContent() { + const ref = this._currentViewRef; + + if (ref && !ref.destroyed) { + ref.destroy(); + this._currentViewRef = null; + } + } } diff --git a/src/aria/deferred-content/index.ts b/src/aria/private/deferred-content/index.ts similarity index 100% rename from src/aria/deferred-content/index.ts rename to src/aria/private/deferred-content/index.ts diff --git a/src/aria/ui-patterns/grid/BUILD.bazel b/src/aria/private/grid/BUILD.bazel similarity index 52% rename from src/aria/ui-patterns/grid/BUILD.bazel rename to src/aria/private/grid/BUILD.bazel index 7f3cf1c3a4cf..2546eeb29fbb 100644 --- a/src/aria/ui-patterns/grid/BUILD.bazel +++ b/src/aria/private/grid/BUILD.bazel @@ -12,9 +12,10 @@ ts_project( ], deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/event-manager", - "//src/aria/ui-patterns/behaviors/grid", - "//src/aria/ui-patterns/behaviors/list", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/event-manager", + "//src/aria/private/behaviors/grid", + "//src/aria/private/behaviors/list-focus", + "//src/aria/private/behaviors/list-navigation", + "//src/aria/private/behaviors/signal-like", ], ) diff --git a/src/aria/private/grid/cell.ts b/src/aria/private/grid/cell.ts new file mode 100644 index 000000000000..90e28a8917f6 --- /dev/null +++ b/src/aria/private/grid/cell.ts @@ -0,0 +1,322 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {KeyboardEventManager} from '../behaviors/event-manager'; +import {ListFocus} from '../behaviors/list-focus/list-focus'; +import {ListNavigation, ListNavigationInputs} from '../behaviors/list-navigation/list-navigation'; +import { + computed, + signal, + linkedSignal, + SignalLike, + WritableSignalLike, +} from '../behaviors/signal-like/signal-like'; +import {GridCell} from '../behaviors/grid'; +import type {GridPattern} from './grid'; +import type {GridRowPattern} from './row'; +import {GridCellWidgetPattern} from './widget'; + +/** The inputs for the `GridCellPattern`. */ +export interface GridCellInputs + extends + GridCell, + Omit< + ListNavigationInputs, + 'focusMode' | 'items' | 'activeItem' | 'softDisabled' | 'element' + > { + /** The `GridPattern` that this cell belongs to. */ + grid: SignalLike; + + /** The `GridRowPattern` that this cell belongs to. */ + row: SignalLike; + + /** The widget patterns contained within this cell, if any. */ + widgets: SignalLike; + + /** The index of this cell's row within the grid. */ + rowIndex: SignalLike; + + /** The index of this cell's column within the grid. */ + colIndex: SignalLike; + + /** A function that returns the cell widget associated with a given element. */ + getWidget: (e: Element | null) => GridCellWidgetPattern | undefined; +} + +/** The UI pattern for a grid cell. */ +export class GridCellPattern implements GridCell { + /** A unique identifier for the cell. */ + readonly id: SignalLike = () => this.inputs.id(); + + /** The html element that should receive focus. */ + readonly element: SignalLike = () => this.inputs.element(); + + /** Whether the cell has focus. */ + readonly isFocused: WritableSignalLike = signal(false); + + /** Whether the cell is selected. */ + readonly selected: WritableSignalLike; + + /** Whether the cell is selectable. */ + readonly selectable: SignalLike = () => this.inputs.selectable(); + + /** Whether a cell is disabled. */ + readonly disabled: SignalLike = () => this.inputs.disabled(); + + /** The number of rows the cell should span. */ + readonly rowSpan: SignalLike = () => this.inputs.rowSpan(); + + /** The number of columns the cell should span. */ + readonly colSpan: SignalLike = () => this.inputs.colSpan(); + + /** Whether the cell is active. */ + readonly active: SignalLike = computed(() => this.inputs.grid().activeCell() === this); + + /** Whether the cell is a selection anchor. */ + readonly anchor: SignalLike = computed(() => + this.inputs.grid().anchorCell() === this ? true : undefined, + ); + + /** The `aria-selected` attribute for the cell. */ + readonly ariaSelected: SignalLike = computed(() => + this.inputs.grid().inputs.enableSelection() && this.selectable() ? this.selected() : undefined, + ); + + /** The `aria-rowindex` attribute for the cell. */ + readonly ariaRowIndex: SignalLike = computed( + () => + this.inputs.row().rowIndex() ?? + this.inputs.rowIndex() ?? + this.inputs.grid().gridBehavior.rowIndex(this), + ); + + /** The `aria-colindex` attribute for the cell. */ + readonly ariaColIndex: SignalLike = computed( + () => this.inputs.colIndex() ?? this.inputs.grid().gridBehavior.colIndex(this), + ); + + /** The internal tab index calculation for the cell. */ + private readonly _tabIndex: SignalLike<-1 | 0> = computed(() => + this.inputs.grid().gridBehavior.cellTabIndex(this), + ); + + /** The tab index for the cell. If the cell contains a widget, the cell's tab index is -1. */ + readonly tabIndex: SignalLike<-1 | 0> = computed(() => { + if (this.singleWidgetMode() || this.navigationActivated()) { + return -1; + } + return this._tabIndex(); + }); + + // Single/Multi Widget Navigation Setup + + /** Whether the cell contains a single widget. */ + readonly singleWidgetMode: SignalLike = computed( + () => this.inputs.widgets().length === 1, + ); + + /** Whether the cell contains multiple widgets. */ + readonly multiWidgetMode: SignalLike = computed(() => this.inputs.widgets().length > 1); + + /** Whether navigation between widgets is disabled. */ + readonly navigationDisabled: SignalLike = computed( + () => !this.multiWidgetMode() || !this.active() || this.inputs.disabled(), + ); + + /** The focus behavior for the widgets in the cell. */ + readonly focusBehavior: ListFocus; + + /** The navigation behavior for the widgets in the cell. */ + readonly navigationBehavior: ListNavigation; + + /** The currently active widget in the cell. */ + readonly activeWidget: WritableSignalLike = linkedSignal(() => + this.inputs.widgets().length > 0 ? this.inputs.widgets()[0] : undefined, + ); + + /** Whether navigation between widgets is activated. */ + readonly navigationActivated: WritableSignalLike = signal(false); + + /** Whether any widget within the cell is activated. */ + readonly widgetActivated: SignalLike = computed(() => + this.inputs.widgets().some(w => w.isActivated()), + ); + + /** Whether the cell or widget inside the cell is activated. */ + readonly isActivated: SignalLike = computed( + () => this.navigationActivated() || this.widgetActivated(), + ); + + /** The key used to navigate to the previous widget. */ + readonly prevKey = computed(() => { + if (this.inputs.orientation() === 'vertical') { + return 'ArrowUp'; + } + return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; + }); + + /** The key used to navigate to the next widget. */ + readonly nextKey = computed(() => { + if (this.inputs.orientation() === 'vertical') { + return 'ArrowDown'; + } + return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; + }); + + /** The keyboard event manager for the cell. */ + readonly keydown = computed(() => { + const manager = new KeyboardEventManager(); + + // Before start list navigation. + if (!this.navigationActivated()) { + manager.on('Enter', () => this.startNavigation()); + return manager; + } + + // Start list navigation. + manager + .on('Escape', () => this.stopNavigation()) + .on(this.prevKey(), () => + this._advance(() => this.navigationBehavior.prev({focusElement: false})), + ) + .on(this.nextKey(), () => + this._advance(() => this.navigationBehavior.next({focusElement: false})), + ) + .on('Home', () => this._advance(() => this.navigationBehavior.next({focusElement: false}))) + .on('End', () => this._advance(() => this.navigationBehavior.next({focusElement: false}))); + + return manager; + }); + + constructor(readonly inputs: GridCellInputs) { + this.selected = inputs.selected; + + const listNavigationInputs: ListNavigationInputs = { + ...inputs, + items: inputs.widgets, + activeItem: this.activeWidget, + disabled: this.navigationDisabled, + focusMode: () => 'roving', + softDisabled: () => true, + }; + + this.focusBehavior = new ListFocus(listNavigationInputs); + this.navigationBehavior = new ListNavigation({ + ...listNavigationInputs, + focusManager: this.focusBehavior, + }); + } + + /** Handles keydown events for the cell. */ + onKeydown(event: KeyboardEvent): void { + if (this.disabled() || this.inputs.widgets().length === 0) return; + + // No navigation needed if single widget. + if (this.singleWidgetMode()) { + this.activeWidget()!.onKeydown(event); + return; + } + + // Focus is on the cell before the navigation starts. + if (!this.navigationActivated()) { + this.keydown().handle(event); + return; + } + + // Widget activate state can be changed during the widget keydown handling. + const widgetActivated = this.widgetActivated(); + + this.activeWidget()!.onKeydown(event); + + if (!widgetActivated) { + this.keydown().handle(event); + } + } + + /** Handles focusin events for the cell. */ + onFocusIn(event: FocusEvent): void { + this.isFocused.set(true); + + const focusTarget = event.target as Element | null; + const widget = this.inputs.getWidget(focusTarget); + if (!widget) return; + + // Pass down focusin event to the widget. + widget.onFocusIn(event); + + // Update internal states if the widget(or anything within the widget) is + // receiving focus by tabbing, pointer, or any programmatic control. + + // Update current active widget. + if (widget !== this.activeWidget()) { + this.navigationBehavior.goto(widget, {focusElement: false}); + } + + // Start widget navigation if multi widget. + if (this.multiWidgetMode()) { + this.navigationActivated.set(true); + } + } + + /** Handles focusout events for the cell. */ + onFocusOut(event: FocusEvent): void { + const blurTarget = event.target as Element | null; + const widget = this.inputs.getWidget(blurTarget); + + // Pass down focusout event to the widget. + widget?.onFocusOut(event); + + const focusTarget = event.relatedTarget as Element | null; + if (this.element().contains(focusTarget)) return; + + this.isFocused.set(false); + // Reset navigation state when focus leaving cell. + this.navigationActivated.set(false); + } + + /** Focuses the cell or the active widget. */ + focus(): void { + if (this.singleWidgetMode()) { + this.activeWidget()?.focus(); + } else { + this.element().focus(); + } + } + + /** Gets the tab index for the widget within the cell. */ + widgetTabIndex(): -1 | 0 { + if (this.singleWidgetMode()) { + return this._tabIndex(); + } + return this.navigationActivated() ? 0 : -1; + } + + /** Starts navigation between widgets. */ + startNavigation(): void { + if (this.navigationActivated()) return; + + this.navigationActivated.set(true); + this.navigationBehavior.first(); + } + + /** Stops navigation between widgets and restores focus to the cell. */ + stopNavigation(): void { + if (!this.navigationActivated()) return; + + this.navigationActivated.set(false); + this.element().focus(); + } + + /** Executes a navigation operation and focuses the new active widget. */ + private _advance(op: () => boolean): void { + const success = op(); + if (success) { + this.activeWidget()?.focus(); + } + } +} diff --git a/src/aria/private/grid/grid.ts b/src/aria/private/grid/grid.ts new file mode 100644 index 000000000000..dcaaf72262cc --- /dev/null +++ b/src/aria/private/grid/grid.ts @@ -0,0 +1,396 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {SignalLike, computed, signal, untracked} from '../behaviors/signal-like/signal-like'; +import {KeyboardEventManager, PointerEventManager, Modifier} from '../behaviors/event-manager'; +import {NavOptions, Grid, GridInputs as GridBehaviorInputs} from '../behaviors/grid'; +import type {GridRowPattern} from './row'; +import type {GridCellPattern} from './cell'; + +/** Represents the required inputs for the grid pattern. */ +export interface GridInputs extends Omit, 'cells'> { + /** The html element of the grid. */ + element: SignalLike; + + /** The rows that make up the grid. */ + rows: SignalLike; + + /** The direction that text is read based on the users locale. */ + textDirection: SignalLike<'rtl' | 'ltr'>; + + /** Whether selection is enabled for the grid. */ + enableSelection: SignalLike; + + /** Whether multiple cell in the grid can be selected. */ + multi: SignalLike; + + /** The selection strategy used by the grid. */ + selectionMode: SignalLike<'follow' | 'explicit'>; + + /** Whether enable range selection. */ + enableRangeSelection: SignalLike; + + /** A function that returns the grid cell associated with a given element. */ + getCell: (e: Element | null) => GridCellPattern | undefined; +} + +/** The UI pattern for a grid, handling keyboard navigation, focus, and selection. */ +export class GridPattern { + /** The underlying grid behavior that this pattern is built on. */ + readonly gridBehavior: Grid; + + /** The cells in the grid. */ + readonly cells = computed(() => this.gridBehavior.data.cells()); + + /** The tab index for the grid. */ + readonly tabIndex = computed(() => this.gridBehavior.gridTabIndex()); + + /** Whether the grid is disabled. */ + readonly disabled = computed(() => this.gridBehavior.gridDisabled()); + + /** The ID of the currently active descendant cell. */ + readonly activeDescendant = computed(() => this.gridBehavior.activeDescendant()); + + /** The currently active cell. */ + readonly activeCell = computed(() => this.gridBehavior.focusBehavior.activeCell()); + + /** The current selection anchor cell. */ + readonly anchorCell: SignalLike = computed(() => + this.inputs.enableSelection() && this.inputs.multi() + ? this.gridBehavior.selectionAnchorCell() + : undefined, + ); + + /** Whether to pause grid navigation and give the keyboard control to cell or widget. */ + readonly pauseNavigation: SignalLike = computed(() => + this.gridBehavior.data + .cells() + .flat() + .reduce((res, c) => res || c.isActivated(), false), + ); + + /** Whether the focus is in the grid. */ + readonly isFocused = signal(false); + + /** Whether the grid has been focused once. */ + readonly hasBeenFocused = signal(false); + + /** Whether the user is currently dragging to select a range of cells. */ + readonly dragging = signal(false); + + /** The key for navigating to the previous column. */ + readonly prevColKey = computed(() => + this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft', + ); + + /** The key for navigating to the next column. */ + readonly nextColKey = computed(() => + this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight', + ); + + /** The keydown event manager for the grid. */ + readonly keydown = computed(() => { + const manager = new KeyboardEventManager(); + + if (this.pauseNavigation()) { + return manager; + } + + // Navigation handlers. + const opts: NavOptions = { + selectOne: this.inputs.enableSelection() && this.inputs.selectionMode() === 'follow', + }; + manager + .on('ArrowUp', () => this.gridBehavior.up(opts)) + .on('ArrowDown', () => this.gridBehavior.down(opts)) + .on(this.prevColKey(), () => this.gridBehavior.left(opts)) + .on(this.nextColKey(), () => this.gridBehavior.right(opts)) + .on('Home', () => this.gridBehavior.firstInRow(opts)) + .on('End', () => this.gridBehavior.lastInRow(opts)) + .on([Modifier.Ctrl], 'Home', () => this.gridBehavior.first(opts)) + .on([Modifier.Ctrl], 'End', () => this.gridBehavior.last(opts)); + + // Basic explicit selection handlers. + if (this.inputs.enableSelection() && this.inputs.selectionMode() === 'explicit') { + manager.on(/Enter| /, () => + this.inputs.multi() ? this.gridBehavior.toggle() : this.gridBehavior.toggleOne(), + ); + } + + // Range selection handlers. + if (this.inputs.enableSelection() && this.inputs.enableRangeSelection()) { + manager + .on(Modifier.Shift, 'ArrowUp', () => this.gridBehavior.up({anchor: true})) + .on(Modifier.Shift, 'ArrowDown', () => this.gridBehavior.down({anchor: true})) + .on(Modifier.Shift, this.prevColKey(), () => this.gridBehavior.left({anchor: true})) + .on(Modifier.Shift, this.nextColKey(), () => this.gridBehavior.right({anchor: true})) + .on(Modifier.Shift, 'Home', () => this.gridBehavior.firstInRow({anchor: true})) + .on(Modifier.Shift, 'End', () => this.gridBehavior.lastInRow({anchor: true})) + .on([Modifier.Ctrl | Modifier.Shift], 'Home', () => this.gridBehavior.first({anchor: true})) + .on([Modifier.Ctrl | Modifier.Shift], 'End', () => this.gridBehavior.last({anchor: true})) + .on([Modifier.Ctrl, Modifier.Meta], 'A', () => { + if (this.gridBehavior.allSelected()) { + this.gridBehavior.deselectAll(); + } else { + this.gridBehavior.selectAll(); + } + }) + .on([Modifier.Shift], ' ', () => this.gridBehavior.selectRow()) + .on([Modifier.Ctrl, Modifier.Meta], ' ', () => this.gridBehavior.selectCol()); + } + + return manager; + }); + + /** The pointerdown event manager for the grid. */ + readonly pointerdown = computed(() => { + const manager = new PointerEventManager(); + + // Navigation without selection. + if (!this.inputs.enableSelection()) { + manager.on(e => { + const cell = this.inputs.getCell(e.target as Element); + if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return; + + this.gridBehavior.gotoCell(cell); + }); + } + + // Navigation with selection. + if (this.inputs.enableSelection()) { + manager.on(e => { + const cell = this.inputs.getCell(e.target as Element); + if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return; + + this.gridBehavior.gotoCell(cell, { + selectOne: this.inputs.selectionMode() === 'follow', + toggleOne: this.inputs.selectionMode() === 'explicit' && !this.inputs.multi(), + toggle: this.inputs.selectionMode() === 'explicit' && this.inputs.multi(), + }); + + if (this.inputs.multi() && this.inputs.enableRangeSelection()) { + this.dragging.set(true); + } + }); + + // Selection with modifier keys. + if (this.inputs.multi()) { + manager.on([Modifier.Ctrl, Modifier.Meta], e => { + const cell = this.inputs.getCell(e.target as Element); + if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return; + + this.gridBehavior.gotoCell(cell, {toggle: true}); + + if (this.inputs.enableRangeSelection()) { + this.dragging.set(true); + } + }); + + if (this.inputs.enableRangeSelection()) { + manager.on(Modifier.Shift, e => { + const cell = this.inputs.getCell(e.target as Element); + if (!cell) return; + + this.gridBehavior.gotoCell(cell, {anchor: true}); + this.dragging.set(true); + }); + } + } + } + + return manager; + }); + + /** The pointerup event manager for the grid. */ + readonly pointerup = computed(() => { + const manager = new PointerEventManager(); + + if (this.inputs.enableSelection() && this.inputs.enableRangeSelection()) { + manager.on([Modifier.Shift, Modifier.Ctrl, Modifier.Meta, Modifier.None], () => { + this.dragging.set(false); + }); + } + + return manager; + }); + + /** Indicates maybe the losing focus is caused by row/cell deletion. */ + private readonly _maybeDeletion = signal(false); + + /** Indicates the losing focus is certainly caused by row/cell deletion. */ + private readonly _deletion = signal(false); + + /** Whether the grid state is stale and needs to be reconciled. */ + private readonly _stateStale = signal(false); + + constructor(readonly inputs: GridInputs) { + this.gridBehavior = new Grid({ + ...inputs, + cells: computed(() => this.inputs.rows().map(row => row.inputs.cells())), + }); + } + + /** Handles keydown events on the grid. */ + onKeydown(event: KeyboardEvent) { + if (this.disabled()) return; + + this.activeCell()?.onKeydown(event); + this.keydown().handle(event); + } + + /** Handles pointerdown events on the grid. */ + onPointerdown(event: PointerEvent) { + if (this.disabled()) return; + + this.pointerdown().handle(event); + } + + /** Handles pointermove events on the grid. */ + onPointermove(event: PointerEvent) { + if ( + this.disabled() || + !this.inputs.enableSelection() || + !this.inputs.enableRangeSelection() || + !this.dragging() + ) { + return; + } + + const cell = this.inputs.getCell(event.target as Element); + + // Dragging anchor. + if (cell !== undefined) { + this.gridBehavior.gotoCell(cell, {anchor: true}); + } + } + + /** Handles pointerup events on the grid. */ + onPointerup(event: PointerEvent) { + if (this.disabled()) return; + + this.pointerup().handle(event); + } + + /** Handles focusin events on the grid. */ + onFocusIn(event: FocusEvent) { + this.isFocused.set(true); + this.hasBeenFocused.set(true); + + // Skip if in the middle of range selection. + if (this.dragging()) return; + + // Cell that receives focus. + const cell = this.inputs.getCell(event.target as Element | null); + if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return; + + // Pass down the focusin event to the cell. + cell.onFocusIn(event); + + // Update active cell state if the cell is receiving focus by + // tabbing, pointer, or any programmatic control into a widget inside the cell. + if (cell !== this.activeCell()) { + this.gridBehavior.gotoCell(cell); + } + } + + /** Handles focusout events on the grid. */ + onFocusOut(event: FocusEvent) { + // Pass down focusout event to the cell that loses focus. + const blurTarget = event.target as Element | null; + const cell = this.inputs.getCell(blurTarget); + + // Pass down the focusout event to the cell. + cell?.onFocusOut(event); + + const focusTarget = event.relatedTarget as Element | null; + if (this.inputs.element().contains(focusTarget)) return; + + // If a `relatedTarget`(focusing target) is null, then it can be caused by either + // - Clicking on a non-focusable element, or + // - The focused element is removed from the page. + if (focusTarget === null) { + this._maybeDeletion.set(true); + } + + this.isFocused.set(false); + } + + /** Sets the default active state of the grid before receiving focus the first time. */ + setDefaultStateEffect(): void { + if (this.hasBeenFocused()) return; + + this.gridBehavior.setDefaultState(); + } + + /** Resets the active state of the grid if it is empty or stale. */ + resetStateEffect(): void { + const hasReset = this.gridBehavior.resetState(); + + if (hasReset) { + // If the active state has been reset right after a focusout event, then + // we know it's caused by a row/cell deletion. + if (this._maybeDeletion()) { + this._deletion.set(true); + } else { + this._stateStale.set(true); + } + } + // Reset maybe deletion state. + this._maybeDeletion.set(false); + } + + /** Resets the focus to the active cell element or grid element. */ + resetFocusEffect(): void { + const stateStale = this._stateStale(); + if (!stateStale) return; + + const isFocused = untracked(() => this.isFocused()); + const isRoving = untracked(() => this.inputs.focusMode() === 'roving'); + const activeCell = untracked(() => this.activeCell()); + + if (isRoving && activeCell !== undefined && isFocused) { + if (!activeCell.isFocused()) { + activeCell.focus(); + } + } + + this._stateStale.set(false); + } + + /** Restore focus when a deletion happened. */ + restoreFocusEffect(): void { + const deletion = this._deletion(); + if (!deletion) return; + + const isRoving = untracked(() => this.inputs.focusMode() === 'roving'); + const activeCell = untracked(() => this.activeCell()); + + if (isRoving && activeCell !== undefined) { + if (!activeCell.isFocused()) { + activeCell.focus(); + } + } + + this._deletion.set(false); + } + + /** Sets focus when active cell changed. */ + focusEffect(): void { + const activeCell = this.activeCell(); + const gridFocused = untracked(() => this.isFocused()); + + if (activeCell === undefined || !gridFocused) return; + + const isRoving = untracked(() => this.inputs.focusMode() === 'roving'); + const cellFocused = untracked(() => activeCell.isFocused()); + + if (isRoving && !cellFocused) { + activeCell.focus(); + } + } +} diff --git a/src/aria/ui-patterns/grid/row.ts b/src/aria/private/grid/row.ts similarity index 100% rename from src/aria/ui-patterns/grid/row.ts rename to src/aria/private/grid/row.ts diff --git a/src/aria/private/grid/widget.ts b/src/aria/private/grid/widget.ts new file mode 100644 index 000000000000..b5e810b35f7a --- /dev/null +++ b/src/aria/private/grid/widget.ts @@ -0,0 +1,163 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {KeyboardEventManager, Modifier} from '../behaviors/event-manager'; +import {ListNavigationItem} from '../behaviors/list-navigation/list-navigation'; +import { + SignalLike, + computed, + signal, + WritableSignalLike, +} from '../behaviors/signal-like/signal-like'; +import type {GridCellPattern} from './cell'; + +/** The inputs for the `GridCellWidgetPattern`. */ +export interface GridCellWidgetInputs extends Omit { + /** The `GridCellPattern` that this widget belongs to. */ + cell: SignalLike; + + /** The html element that should receive focus. */ + element: SignalLike; + + /** The type of widget, which determines how it is activated. */ + widgetType: SignalLike<'simple' | 'complex' | 'editable'>; + + /** The element that will receive focus when the widget is activated. */ + focusTarget: SignalLike; +} + +/** The UI pattern for a widget inside a grid cell. */ +export class GridCellWidgetPattern implements ListNavigationItem { + /** A unique identifier for the widget. */ + readonly id: SignalLike = () => this.inputs.id(); + + /** The html element that should receive focus. */ + readonly element: SignalLike = () => this.inputs.element(); + + /** The element that should receive focus. */ + readonly widgetHost: SignalLike = computed( + () => this.inputs.focusTarget() ?? this.element(), + ); + + /** The index of the widget within the cell. */ + readonly index: SignalLike = computed(() => + this.inputs.cell().inputs.widgets().indexOf(this), + ); + + /** Whether the widget is disabled. */ + readonly disabled: SignalLike = computed( + () => this.inputs.disabled() || this.inputs.cell().disabled(), + ); + + /** The tab index for the widget. */ + readonly tabIndex: SignalLike<-1 | 0> = computed(() => this.inputs.cell().widgetTabIndex()); + + /** Whether the widget is the active item in the widget list. */ + readonly active: SignalLike = computed(() => this.inputs.cell().activeWidget() === this); + + /** Whether the widget is currently activated. */ + readonly isActivated: WritableSignalLike = signal(false); + + /** The last event that caused the widget to be activated. */ + readonly lastActivateEvent: WritableSignalLike = + signal(undefined); + + /** The last event that caused the widget to be deactivated. */ + readonly lastDeactivateEvent: WritableSignalLike = + signal(undefined); + + /** The keyboard event manager for the widget. */ + readonly keydown = computed(() => { + const manager = new KeyboardEventManager(); + + // Simple widget does not need to pause default grid behaviors. + if (this.inputs.widgetType() === 'simple') { + return manager; + } + + // If a widget is activated, only listen to events that exits activate state. + if (this.isActivated()) { + manager.on('Escape', e => { + this.deactivate(e); + this.focus(); + }); + + if (this.inputs.widgetType() === 'editable') { + manager.on('Enter', e => { + this.deactivate(e); + this.focus(); + }); + } + + return manager; + } + + // Enter key is used to activate widget for both complex and editable type. + manager.on('Enter', e => this.activate(e)); + + if (this.inputs.widgetType() === 'editable') { + manager.on([Modifier.Shift, Modifier.None], /^[a-zA-Z0-9]$/, e => this.activate(e), { + preventDefault: false, + }); + } + + return manager; + }); + + constructor(readonly inputs: GridCellWidgetInputs) {} + + /** Handles keydown events for the widget. */ + onKeydown(event: KeyboardEvent): void { + if (this.disabled()) return; + + this.keydown().handle(event); + } + + /** Handles focusin events for the widget. */ + onFocusIn(event: FocusEvent): void { + // Simple widget does not have activate state. + if (this.inputs.widgetType() === 'simple') return; + + // Set activate state if the focus is inside of widget. + const focusTarget = event.target as Element; + if (this.widgetHost().contains(focusTarget) && this.widgetHost() !== focusTarget) { + this.activate(event); + } + } + + /** Handles focusout events for the widget. */ + onFocusOut(event: FocusEvent): void { + const focusTarget = event.relatedTarget as Element; + if (this.widgetHost().contains(focusTarget)) return; + + // Reset states when focus leaving widget. + this.deactivate(event); + } + + /** Focuses the widget's host element. */ + focus(): void { + this.widgetHost().focus(); + } + + /** Activates the widget. */ + activate(event?: KeyboardEvent | FocusEvent): void { + if (this.isActivated()) return; + if (this.inputs.widgetType() === 'simple') return; + + this.isActivated.set(true); + this.lastActivateEvent.set(event); + } + + /** Deactivates the widget and restores focus to the widget's host element. */ + deactivate(event?: KeyboardEvent | FocusEvent): void { + if (!this.isActivated()) return; + + this.isActivated.set(false); + this.lastDeactivateEvent.set(event); + } +} diff --git a/src/aria/ui-patterns/index.ts b/src/aria/private/index.ts similarity index 100% rename from src/aria/ui-patterns/index.ts rename to src/aria/private/index.ts diff --git a/src/aria/ui-patterns/listbox/BUILD.bazel b/src/aria/private/listbox/BUILD.bazel similarity index 72% rename from src/aria/ui-patterns/listbox/BUILD.bazel rename to src/aria/private/listbox/BUILD.bazel index d30344d420aa..92feb7008ac3 100644 --- a/src/aria/ui-patterns/listbox/BUILD.bazel +++ b/src/aria/private/listbox/BUILD.bazel @@ -10,10 +10,10 @@ ts_project( ), deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/event-manager", - "//src/aria/ui-patterns/behaviors/list", - "//src/aria/ui-patterns/behaviors/signal-like", - "//src/aria/ui-patterns/combobox", + "//src/aria/private/behaviors/event-manager", + "//src/aria/private/behaviors/list", + "//src/aria/private/behaviors/signal-like", + "//src/aria/private/combobox", ], ) @@ -24,6 +24,7 @@ ng_project( deps = [ ":listbox", "//:node_modules/@angular/core", + "//src/aria/private/behaviors/signal-like", "//src/cdk/keycodes", "//src/cdk/testing/private", ], diff --git a/src/aria/ui-patterns/listbox/combobox-listbox.ts b/src/aria/private/listbox/combobox-listbox.ts similarity index 66% rename from src/aria/ui-patterns/listbox/combobox-listbox.ts rename to src/aria/private/listbox/combobox-listbox.ts index b331de3c358e..938cd3bd5a83 100644 --- a/src/aria/ui-patterns/listbox/combobox-listbox.ts +++ b/src/aria/private/listbox/combobox-listbox.ts @@ -6,9 +6,8 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed} from '@angular/core'; import {ListboxInputs, ListboxPattern} from './listbox'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; +import {SignalLike, computed} from '../behaviors/signal-like/signal-like'; import {OptionPattern} from './option'; import {ComboboxPattern, ComboboxListboxControls} from '../combobox/combobox'; @@ -28,17 +27,21 @@ export class ComboboxListboxPattern role = computed(() => 'listbox' as const); /** The id of the active (focused) item in the listbox. */ - activeId = computed(() => this.listBehavior.activedescendant()); + activeId = computed(() => this.listBehavior.activeDescendant()); /** The list of options in the listbox. */ items: SignalLike[]> = computed(() => this.inputs.items()); - /** The tabindex for the listbox. Always -1 because the combobox handles focus. */ - override tabindex: SignalLike<-1 | 0> = () => -1; + /** The tab index for the listbox. Always -1 because the combobox handles focus. */ + override tabIndex: SignalLike<-1 | 0> = () => -1; + + /** Whether multiple items in the list can be selected at once. */ + override multi = computed(() => { + return this.inputs.combobox()?.readonly() ? this.inputs.multi() : false; + }); constructor(override readonly inputs: ComboboxListboxInputs) { if (inputs.combobox()) { - inputs.multi = () => false; inputs.focusMode = () => 'activedescendant'; inputs.element = inputs.combobox()!.inputs.inputEl; } @@ -56,7 +59,12 @@ export class ComboboxListboxPattern override setDefaultState(): void {} /** Navigates to the specified item in the listbox. */ - focus = (item: OptionPattern) => this.listBehavior.goto(item); + focus = (item: OptionPattern, opts?: {focusElement?: boolean}) => { + this.listBehavior.goto(item, opts); + }; + + /** Navigates to the previous focusable item in the listbox. */ + getActiveItem = () => this.inputs.activeItem(); /** Navigates to the next focusable item in the listbox. */ next = () => this.listBehavior.next(); @@ -76,15 +84,28 @@ export class ComboboxListboxPattern /** Selects the specified item in the listbox. */ select = (item?: OptionPattern) => this.listBehavior.select(item); + /** Toggles the selection state of the given item in the listbox. */ + toggle = (item?: OptionPattern) => this.listBehavior.toggle(item); + /** Clears the selection in the listbox. */ clearSelection = () => this.listBehavior.deselectAll(); /** Retrieves the OptionPattern associated with a pointer event. */ getItem = (e: PointerEvent) => this._getItem(e); - /** Retrieves the currently selected item in the listbox. */ - getSelectedItem = () => this.inputs.items().find(i => i.selected()); + /** Retrieves the currently selected items in the listbox. */ + getSelectedItems = () => { + // NOTE: We need to do this funky for loop to preserve the order of the selected values. + const items = []; + for (const value of this.inputs.values()) { + const item = this.items().find(i => i.value() === value); + if (item) { + items.push(item); + } + } + return items; + }; /** Sets the value of the combobox listbox. */ - setValue = (value: V | undefined) => this.inputs.value.set(value ? [value] : []); + setValue = (value: V | undefined) => this.inputs.values.set(value ? [value] : []); } diff --git a/src/aria/ui-patterns/listbox/listbox.spec.ts b/src/aria/private/listbox/listbox.spec.ts similarity index 76% rename from src/aria/ui-patterns/listbox/listbox.spec.ts rename to src/aria/private/listbox/listbox.spec.ts index da3244c187b4..ff4fc0ba3844 100644 --- a/src/aria/ui-patterns/listbox/listbox.spec.ts +++ b/src/aria/private/listbox/listbox.spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {signal, WritableSignal} from '@angular/core'; +import {signal, WritableSignalLike} from '../behaviors/signal-like/signal-like'; import {ListboxInputs, ListboxPattern} from './listbox'; import {OptionPattern} from './option'; import {createKeyboardEvent} from '@angular/cdk/testing/private'; @@ -14,7 +14,7 @@ import {ModifierKeys} from '@angular/cdk/testing'; type TestInputs = ListboxInputs; type TestOption = OptionPattern & { - disabled: WritableSignal; + disabled: WritableSignalLike; }; type TestListbox = ListboxPattern; @@ -34,13 +34,13 @@ describe('Listbox Pattern', () => { return new ListboxPattern({ id: signal('listbox-1'), items: inputs.items, - value: inputs.value ?? signal([]), + values: inputs.values ?? signal([]), activeItem: signal(undefined), - typeaheadDelay: inputs.typeaheadDelay ?? signal(0.5), + typeaheadDelay: inputs.typeaheadDelay ?? signal(500), wrap: inputs.wrap ?? signal(true), readonly: inputs.readonly ?? signal(false), disabled: inputs.disabled ?? signal(false), - skipDisabled: inputs.skipDisabled ?? signal(true), + softDisabled: inputs.softDisabled ?? signal(true), multi: inputs.multi ?? signal(false), focusMode: inputs.focusMode ?? signal('roving'), textDirection: inputs.textDirection ?? signal('ltr'), @@ -174,45 +174,45 @@ describe('Listbox Pattern', () => { describe('follows focus & single select', () => { it('should select an option on navigation', () => { const {listbox} = getDefaultPatterns({ - value: signal(['Apple']), + values: signal(['Apple']), multi: signal(false), selectionMode: signal('follow'), }); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down()); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[1]); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); listbox.onKeydown(up()); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(end()); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[8]); - expect(listbox.inputs.value()).toEqual(['Cranberry']); + expect(listbox.inputs.values()).toEqual(['Cranberry']); listbox.onKeydown(home()); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should not be able to change selection when in readonly mode', () => { const {listbox} = getDefaultPatterns({ - value: signal(['Apple']), + values: signal(['Apple']), readonly: signal(true), multi: signal(false), selectionMode: signal('follow'), }); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[0]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down()); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[1]); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); }); @@ -221,7 +221,7 @@ describe('Listbox Pattern', () => { beforeEach(() => { listbox = getDefaultPatterns({ - value: signal([]), + values: signal([]), selectionMode: signal('explicit'), multi: signal(false), }).listbox; @@ -229,30 +229,30 @@ describe('Listbox Pattern', () => { it('should select an option on Space', () => { listbox.onKeydown(space()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should select an option on Enter', () => { listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should only allow one selected option', () => { listbox.onKeydown(enter()); listbox.onKeydown(down()); listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); }); it('should not be able to change selection when in readonly mode', () => { - const readonly = listbox.inputs.readonly as WritableSignal; + const readonly = listbox.inputs.readonly as WritableSignalLike; readonly.set(true); listbox.onKeydown(space()); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(down()); listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); }); @@ -262,7 +262,7 @@ describe('Listbox Pattern', () => { beforeEach(() => { const patterns = getDefaultPatterns({ - value: signal([]), + values: signal([]), selectionMode: signal('explicit'), multi: signal(true), }); @@ -272,37 +272,37 @@ describe('Listbox Pattern', () => { it('should select an option on Space', () => { listbox.onKeydown(space()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should select an option on Enter', () => { listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should allow multiple selected options', () => { listbox.onKeydown(enter()); listbox.onKeydown(down()); listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); }); it('should select a range of options on Shift + ArrowDown/ArrowUp', () => { listbox.onKeydown(shift()); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot', 'Banana']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should not allow wrapping while Shift is held down', () => { listbox.onKeydown(shift()); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should select a range of options on Shift + Space (or Enter)', () => { @@ -312,20 +312,20 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apricot', 'Banana', 'Blackberry']); + expect(listbox.inputs.values()).toEqual(['Apricot', 'Banana', 'Blackberry']); }); it('should deselect options outside the range on subsequent on Shift + Space (or Enter)', () => { listbox.onKeydown(down()); listbox.onKeydown(down()); listbox.onKeydown(space()); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.inputs.values()).toEqual(['Banana']); listbox.onKeydown(down()); listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Blackberry', 'Blueberry']); listbox.onKeydown(up()); listbox.onKeydown(up()); @@ -333,7 +333,7 @@ describe('Listbox Pattern', () => { listbox.onKeydown(up()); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Apricot', 'Apple']); }); it('should select the focused option and all options up to the first option on Ctrl + Shift + Home', () => { @@ -342,7 +342,7 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(home({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual(['Blackberry', 'Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Blackberry', 'Banana', 'Apricot', 'Apple']); }); it('should select the focused option and all options down to the last option on Ctrl + Shift + End', () => { @@ -353,51 +353,56 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(end({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual(['Cantaloupe', 'Cherry', 'Clementine', 'Cranberry']); + expect(listbox.inputs.values()).toEqual([ + 'Cantaloupe', + 'Cherry', + 'Clementine', + 'Cranberry', + ]); }); it('should not be able to change selection when in readonly mode', () => { - const readonly = listbox.inputs.readonly as WritableSignal; + const readonly = listbox.inputs.readonly as WritableSignalLike; readonly.set(true); listbox.onKeydown(space()); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(down()); listbox.onKeydown(enter()); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(shift()); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(end({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(home({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should not change the selected state of disabled options on Shift + ArrowUp / ArrowDown', () => { - (listbox.inputs.skipDisabled as WritableSignal).set(false); + (listbox.inputs.softDisabled as WritableSignalLike).set(true); options[1].disabled.set(true); listbox.onKeydown(shift()); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Banana']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should select all options on Ctrl + A', () => { - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(a({control: true})); - expect(listbox.inputs.value()).toEqual([ + expect(listbox.inputs.values()).toEqual([ 'Apple', 'Apricot', 'Banana', @@ -411,10 +416,10 @@ describe('Listbox Pattern', () => { }); it('should deselect all options on Ctrl + A if all options are selected', () => { - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onKeydown(a({control: true})); listbox.onKeydown(a({control: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); }); @@ -424,7 +429,7 @@ describe('Listbox Pattern', () => { beforeEach(() => { const patterns = getDefaultPatterns({ - value: signal(['Apple']), + values: signal(['Apple']), multi: signal(true), selectionMode: signal('follow'), }); @@ -433,25 +438,25 @@ describe('Listbox Pattern', () => { }); it('should select an option on navigation', () => { - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); listbox.onKeydown(up()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(end()); - expect(listbox.inputs.value()).toEqual(['Cranberry']); + expect(listbox.inputs.values()).toEqual(['Cranberry']); listbox.onKeydown(home()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should navigate without selecting an option if the Ctrl key is pressed', () => { - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(up({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(end({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(home({control: true})); }); @@ -459,26 +464,26 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down({control: true})); listbox.onKeydown(down({control: true})); listbox.onKeydown(space({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Banana']); }); it('should select a range of options on Shift + ArrowDown/ArrowUp', () => { listbox.onKeydown(shift()); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); listbox.onKeydown(down({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot', 'Banana']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should not allow wrapping while Shift is held down', () => { listbox.listBehavior.deselectAll(); listbox.onKeydown(shift()); listbox.onKeydown(up({shift: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should select a range of options on Shift + Space (or Enter)', () => { @@ -487,19 +492,19 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down({control: true})); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Apricot', 'Banana', 'Blackberry']); + expect(listbox.inputs.values()).toEqual(['Apricot', 'Banana', 'Blackberry']); }); it('should deselect options outside the range on subsequent on Shift + Space (or Enter)', () => { listbox.onKeydown(down()); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.inputs.values()).toEqual(['Banana']); listbox.onKeydown(down({control: true})); listbox.onKeydown(down({control: true})); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Blackberry', 'Blueberry']); listbox.onKeydown(up({control: true})); listbox.onKeydown(up({control: true})); @@ -507,7 +512,7 @@ describe('Listbox Pattern', () => { listbox.onKeydown(up({control: true})); listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Apricot', 'Apple']); }); it('should select the focused option and all options up to the first option on Ctrl + Shift + Home', () => { @@ -516,7 +521,7 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(home({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual(['Blackberry', 'Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Blackberry', 'Banana', 'Apricot', 'Apple']); }); it('should select the focused option and all options down to the last option on Ctrl + Shift + End', () => { @@ -527,38 +532,43 @@ describe('Listbox Pattern', () => { listbox.onKeydown(down()); listbox.onKeydown(shift()); listbox.onKeydown(end({control: true, shift: true})); - expect(listbox.inputs.value()).toEqual(['Cantaloupe', 'Cherry', 'Clementine', 'Cranberry']); + expect(listbox.inputs.values()).toEqual([ + 'Cantaloupe', + 'Cherry', + 'Clementine', + 'Cranberry', + ]); }); it('should not be able to change selection when in readonly mode', () => { - const readonly = listbox.inputs.readonly as WritableSignal; + const readonly = listbox.inputs.readonly as WritableSignalLike; readonly.set(true); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(up()); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(space({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should not select disabled options', () => { options[2].disabled.set(true); - (listbox.inputs.skipDisabled as WritableSignal).set(false); - expect(listbox.inputs.value()).toEqual(['Apple']); + (listbox.inputs.softDisabled as WritableSignalLike).set(true); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); listbox.onKeydown(down()); - expect(listbox.inputs.value()).toEqual(['Blackberry']); + expect(listbox.inputs.values()).toEqual(['Blackberry']); }); it('should deselect all except one option on Ctrl + A if all options are selected', () => { listbox.onKeydown(a({control: true})); listbox.onKeydown(a({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); }); }); @@ -579,7 +589,7 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); }); @@ -590,17 +600,17 @@ describe('Listbox Pattern', () => { selectionMode: signal('explicit'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should deselect a selected option on click', () => { const {listbox, options} = getDefaultPatterns({ multi: signal(false), - value: signal(['Apple']), + values: signal(['Apple']), selectionMode: signal('explicit'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); }); @@ -611,17 +621,17 @@ describe('Listbox Pattern', () => { selectionMode: signal('explicit'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); it('should deselect a selected option on click', () => { const {listbox, options} = getDefaultPatterns({ multi: signal(true), - value: signal(['Apple']), + values: signal(['Apple']), selectionMode: signal('explicit'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should select options from anchor on shift + click', () => { @@ -632,7 +642,12 @@ describe('Listbox Pattern', () => { listbox.onPointerdown(click(options, 2)); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 5, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry', 'Cantaloupe']); + expect(listbox.inputs.values()).toEqual([ + 'Banana', + 'Blackberry', + 'Blueberry', + 'Cantaloupe', + ]); }); it('should deselect options outside the range on subsequent shift + clicks', () => { @@ -643,9 +658,14 @@ describe('Listbox Pattern', () => { listbox.onPointerdown(click(options, 2)); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 5, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry', 'Cantaloupe']); + expect(listbox.inputs.values()).toEqual([ + 'Banana', + 'Blackberry', + 'Blueberry', + 'Cantaloupe', + ]); listbox.onPointerdown(click(options, 0, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Apricot', 'Apple']); }); }); @@ -656,11 +676,11 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onPointerdown(click(options, 1)); - expect(listbox.inputs.value()).toEqual(['Apricot']); + expect(listbox.inputs.values()).toEqual(['Apricot']); listbox.onPointerdown(click(options, 2)); - expect(listbox.inputs.value()).toEqual(['Banana']); + expect(listbox.inputs.values()).toEqual(['Banana']); }); it('should select an unselected option on ctrl + click', () => { @@ -669,11 +689,11 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onPointerdown(click(options, 1, {control: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); listbox.onPointerdown(click(options, 2, {control: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot', 'Banana']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot', 'Banana']); }); it('should deselect a selected option on ctrl + click', () => { @@ -682,9 +702,9 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onPointerdown(click(options, 0, {control: true})); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should select a range of options on shift + click', () => { @@ -695,7 +715,12 @@ describe('Listbox Pattern', () => { listbox.onPointerdown(click(options, 2)); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 5, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry', 'Cantaloupe']); + expect(listbox.inputs.values()).toEqual([ + 'Banana', + 'Blackberry', + 'Blueberry', + 'Cantaloupe', + ]); }); it('should deselect options outside the range on subsequent shift + clicks', () => { @@ -706,40 +731,45 @@ describe('Listbox Pattern', () => { listbox.onPointerdown(click(options, 2)); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 5, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry', 'Cantaloupe']); + expect(listbox.inputs.values()).toEqual([ + 'Banana', + 'Blackberry', + 'Blueberry', + 'Cantaloupe', + ]); listbox.onPointerdown(click(options, 0, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Apricot', 'Apple']); }); it('should select a range up to but not including a disabled option on shift + click', () => { const {listbox, options} = getDefaultPatterns({ multi: signal(true), - skipDisabled: signal(false), + softDisabled: signal(true), selectionMode: signal('follow'), }); options[2].disabled.set(true); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 2, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Apricot']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Apricot']); expect(listbox.inputs.activeItem()).toEqual(options[2]); }); it('should do nothing on click if the option is disabled', () => { const {listbox, options} = getDefaultPatterns({ multi: signal(true), - skipDisabled: signal(true), + softDisabled: signal(false), selectionMode: signal('follow'), }); options[2].disabled.set(true); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down({control: true})); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onPointerdown(click(options, 2)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); }); }); @@ -749,11 +779,11 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onPointerdown(click(options, 1)); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); listbox.onPointerdown(click(options, 2)); - expect(listbox.inputs.value()).toEqual([]); + expect(listbox.inputs.values()).toEqual([]); }); it('should maintain the range selection between pointer and keyboard', () => { @@ -767,9 +797,9 @@ describe('Listbox Pattern', () => { listbox.onKeydown(shift()); listbox.onKeydown(space({shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Blackberry', 'Blueberry']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Blackberry', 'Blueberry']); listbox.onPointerdown(click(options, 0, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Banana', 'Apricot', 'Apple']); + expect(listbox.inputs.values()).toEqual(['Banana', 'Apricot', 'Apple']); }); it('should select a range from the currently focused option', () => { @@ -778,12 +808,12 @@ describe('Listbox Pattern', () => { selectionMode: signal('follow'), }); listbox.onPointerdown(click(options, 0)); - expect(listbox.inputs.value()).toEqual(['Apple']); + expect(listbox.inputs.values()).toEqual(['Apple']); listbox.onKeydown(down({control: true})); listbox.onKeydown(down({control: true})); listbox.onKeydown(shift()); listbox.onPointerdown(click(options, 4, {shift: true})); - expect(listbox.inputs.value()).toEqual(['Apple', 'Banana', 'Blackberry', 'Blueberry']); + expect(listbox.inputs.values()).toEqual(['Apple', 'Banana', 'Blackberry', 'Blueberry']); }); }); @@ -796,7 +826,7 @@ describe('Listbox Pattern', () => { it('should set the active index to the first focusable option', () => { const {listbox, options} = getDefaultPatterns({ - skipDisabled: signal(true), + softDisabled: signal(false), }); options[0].disabled.set(true); listbox.setDefaultState(); @@ -805,8 +835,8 @@ describe('Listbox Pattern', () => { it('should set the active index to the first selected option', () => { const {listbox} = getDefaultPatterns({ - value: signal(['Banana']), - skipDisabled: signal(true), + values: signal(['Banana']), + softDisabled: signal(false), }); listbox.setDefaultState(); expect(listbox.inputs.activeItem()).toBe(listbox.inputs.items()[2]); @@ -814,8 +844,8 @@ describe('Listbox Pattern', () => { it('should set the active index to the first focusable selected option', () => { const {listbox, options} = getDefaultPatterns({ - value: signal(['Banana', 'Blackberry']), - skipDisabled: signal(true), + values: signal(['Banana', 'Blackberry']), + softDisabled: signal(false), }); options[2].disabled.set(true); listbox.setDefaultState(); @@ -824,8 +854,8 @@ describe('Listbox Pattern', () => { it('should set the active index to the first option if no selected option is focusable', () => { const {listbox, options} = getDefaultPatterns({ - value: signal(['Banana']), - skipDisabled: signal(true), + values: signal(['Banana']), + softDisabled: signal(false), }); options[2].disabled.set(true); listbox.setDefaultState(); diff --git a/src/aria/ui-patterns/listbox/listbox.ts b/src/aria/private/listbox/listbox.ts similarity index 95% rename from src/aria/ui-patterns/listbox/listbox.ts rename to src/aria/private/listbox/listbox.ts index 5f5c034e4866..081a3dd069c3 100644 --- a/src/aria/ui-patterns/listbox/listbox.ts +++ b/src/aria/private/listbox/listbox.ts @@ -8,8 +8,7 @@ import {OptionPattern} from './option'; import {KeyboardEventManager, PointerEventManager, Modifier} from '../behaviors/event-manager'; -import {computed, signal} from '@angular/core'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; +import {computed, signal, SignalLike} from '../behaviors/signal-like/signal-like'; import {List, ListInputs} from '../behaviors/list/list'; /** Represents the required inputs for a listbox. */ @@ -34,11 +33,11 @@ export class ListboxPattern { /** Whether the listbox is readonly. */ readonly: SignalLike; - /** The tabindex of the listbox. */ - tabindex: SignalLike<-1 | 0> = computed(() => this.listBehavior.tabindex()); + /** The tab index of the listbox. */ + tabIndex: SignalLike<-1 | 0> = computed(() => this.listBehavior.tabIndex()); /** The id of the current active item. */ - activedescendant = computed(() => this.listBehavior.activedescendant()); + activeDescendant = computed(() => this.listBehavior.activeDescendant()); /** Whether multiple items in the list can be selected at once. */ multi: SignalLike; @@ -199,9 +198,9 @@ export class ListboxPattern { validate(): string[] { const violations: string[] = []; - if (!this.inputs.multi() && this.inputs.value().length > 1) { + if (!this.inputs.multi() && this.inputs.values().length > 1) { violations.push( - `A single-select listbox should not have multiple selected options. Selected options: ${this.inputs.value().join(', ')}`, + `A single-select listbox should not have multiple selected options. Selected options: ${this.inputs.values().join(', ')}`, ); } diff --git a/src/aria/ui-patterns/listbox/option.ts b/src/aria/private/listbox/option.ts similarity index 85% rename from src/aria/ui-patterns/listbox/option.ts rename to src/aria/private/listbox/option.ts index 8ea16149d004..69930a3ec06b 100644 --- a/src/aria/ui-patterns/listbox/option.ts +++ b/src/aria/private/listbox/option.ts @@ -6,8 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed} from '@angular/core'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; +import {computed, SignalLike} from '../behaviors/signal-like/signal-like'; import {List, ListInputs, ListItem} from '../behaviors/list/list'; /** @@ -39,7 +38,7 @@ export class OptionPattern { active = computed(() => this.listbox()?.inputs.activeItem() === this); /** Whether the option is selected. */ - selected = computed(() => this.listbox()?.inputs.value().includes(this.value())); + selected = computed(() => this.listbox()?.inputs.values().includes(this.value())); /** Whether the option is selectable. */ selectable = () => true; @@ -53,11 +52,11 @@ export class OptionPattern { /** A reference to the parent listbox. */ listbox: SignalLike | undefined>; - /** The tabindex of the option. */ - tabindex = computed(() => this.listbox()?.listBehavior.getItemTabindex(this)); + /** The tab index of the option. */ + tabIndex = computed(() => this.listbox()?.listBehavior.getItemTabindex(this)); /** The html element that should receive focus. */ - element: SignalLike; + element: SignalLike; constructor(args: OptionInputs) { this.id = args.id; diff --git a/src/aria/ui-patterns/menu/BUILD.bazel b/src/aria/private/menu/BUILD.bazel similarity index 68% rename from src/aria/ui-patterns/menu/BUILD.bazel rename to src/aria/private/menu/BUILD.bazel index 6609d161f54d..dc1c20d548aa 100644 --- a/src/aria/ui-patterns/menu/BUILD.bazel +++ b/src/aria/private/menu/BUILD.bazel @@ -9,10 +9,10 @@ ts_project( ], deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/event-manager", - "//src/aria/ui-patterns/behaviors/expansion", - "//src/aria/ui-patterns/behaviors/list", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/event-manager", + "//src/aria/private/behaviors/expansion", + "//src/aria/private/behaviors/list", + "//src/aria/private/behaviors/signal-like", ], ) @@ -25,7 +25,7 @@ ng_project( deps = [ ":menu", "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/signal-like", "//src/cdk/keycodes", "//src/cdk/testing/private", ], diff --git a/src/aria/ui-patterns/menu/menu.spec.ts b/src/aria/private/menu/menu.spec.ts similarity index 68% rename from src/aria/ui-patterns/menu/menu.spec.ts rename to src/aria/private/menu/menu.spec.ts index 689af41216f0..b01aff0a9cc8 100644 --- a/src/aria/ui-patterns/menu/menu.spec.ts +++ b/src/aria/private/menu/menu.spec.ts @@ -6,16 +6,16 @@ * found in the LICENSE file at https://angular.dev/license */ -import {signal, WritableSignal} from '@angular/core'; +import {signal, WritableSignalLike} from '../behaviors/signal-like/signal-like'; import {MenuPattern, MenuBarPattern, MenuItemPattern, MenuTriggerPattern} from './menu'; import {createKeyboardEvent} from '@angular/cdk/testing/private'; import {ModifierKeys} from '@angular/cdk/testing'; -import {fakeAsync, tick} from '@angular/core/testing'; // Test types type TestMenuItem = MenuItemPattern & { - disabled: WritableSignal; - submenu: WritableSignal | undefined>; + inputs: { + disabled: WritableSignalLike; + }; }; // Keyboard event helpers @@ -37,32 +37,35 @@ function clickMenuItem(items: MenuItemPattern[], index: number, mods?: Modi } as unknown as PointerEvent; } -function getMenuTriggerPattern() { +function getMenuTriggerPattern(opts?: {textDirection: 'ltr' | 'rtl'}) { const element = signal(document.createElement('button')); const submenu = signal | undefined>(undefined); const trigger = new MenuTriggerPattern({ + textDirection: signal(opts?.textDirection || 'ltr'), element, - submenu, + menu: submenu, + disabled: signal(false), }); return trigger; } -function getMenuBarPattern(values: string[]) { +function getMenuBarPattern(values: string[], opts?: {textDirection: 'ltr' | 'rtl'}) { const items = signal([]); const menubar = new MenuBarPattern({ items: items, activeItem: signal(undefined), orientation: signal('horizontal'), - textDirection: signal('ltr'), + textDirection: signal(opts?.textDirection || 'ltr'), multi: signal(false), selectionMode: signal('explicit'), - value: signal([]), + values: signal([]), wrap: signal(true), - typeaheadDelay: signal(0.5), - skipDisabled: signal(true), + typeaheadDelay: signal(500), + softDisabled: signal(true), focusMode: signal('activedescendant'), element: signal(document.createElement('div')), + disabled: signal(false), }); items.set( @@ -87,6 +90,7 @@ function getMenuBarPattern(values: string[]) { function getMenuPattern( parent: undefined | MenuItemPattern | MenuTriggerPattern, values: string[], + opts?: {textDirection: 'ltr' | 'rtl'}, ) { const items = signal([]); @@ -95,15 +99,17 @@ function getMenuPattern( items: items, parent: signal(parent) as any, activeItem: signal(undefined), - typeaheadDelay: signal(0.5), + typeaheadDelay: signal(500), wrap: signal(true), - skipDisabled: signal(true), + softDisabled: signal(true), multi: signal(false), focusMode: signal('activedescendant'), - textDirection: signal('ltr'), + textDirection: signal(opts?.textDirection || 'ltr'), orientation: signal('vertical'), selectionMode: signal('explicit'), element: signal(document.createElement('div')), + expansionDelay: signal(0), + disabled: signal(false), }); items.set( @@ -123,10 +129,14 @@ function getMenuPattern( }), ); - if (parent) { - (parent.submenu as WritableSignal>).set(menu); + if (parent instanceof MenuTriggerPattern) { + (parent.menu as WritableSignalLike>).set(menu); + parent.inputs.element()?.appendChild(menu.inputs.element()!); + } else if (parent instanceof MenuItemPattern) { + (parent.submenu as WritableSignalLike>).set(menu); parent.inputs.element()?.appendChild(menu.inputs.element()!); } + menu.inputs.activeItem.set(items()[0]); return menu; } @@ -173,22 +183,26 @@ describe('Standalone Menu Pattern', () => { }); describe('Typeahead', () => { - it('should move the active item to the next item that starts with the typed character', fakeAsync(() => { + function delay(amount: number) { + return new Promise(resolve => setTimeout(resolve, amount)); + } + + it('should move the active item to the next item that starts with the typed character', async () => { const menu = getMenuPattern(undefined, ['Apple', 'Banana', 'Cherry']); const items = menu.inputs.items(); const b = createKeyboardEvent('keydown', 66, 'b'); menu.onKeydown(b); - tick(500); + await delay(500); expect(menu.inputs.activeItem()).toBe(items[1]); const c = createKeyboardEvent('keydown', 67, 'c'); menu.onKeydown(c); - tick(500); + await delay(500); expect(menu.inputs.activeItem()).toBe(items[2]); - })); + }); - it('should support multi-character typeahead', fakeAsync(() => { + it('should support multi-character typeahead', async () => { const menu = getMenuPattern(undefined, ['Cabbage', 'Chard', 'Cherry', 'Cilantro']); const c = createKeyboardEvent('keydown', 67, 'c'); @@ -204,202 +218,229 @@ describe('Standalone Menu Pattern', () => { menu.onKeydown(e); expect(menu.inputs.activeItem()?.value()).toBe('Cherry'); - tick(500); + await delay(500); menu.onKeydown(c); expect(menu.inputs.activeItem()?.value()).toBe('Cilantro'); - })); + }); - it('should wrap when reaching the end of the list during typeahead', fakeAsync(() => { + it('should wrap when reaching the end of the list during typeahead', async () => { const menu = getMenuPattern(undefined, ['Apple', 'Banana', 'Avocado']); const items = menu.inputs.items(); menu.inputs.activeItem.set(items[1]); const a = createKeyboardEvent('keydown', 65, 'a'); menu.onKeydown(a); - tick(500); + await delay(500); expect(menu.inputs.activeItem()).toBe(items[2]); menu.onKeydown(a); - tick(500); + await delay(500); expect(menu.inputs.activeItem()).toBe(items[0]); - })); + }); - it('should not move the active item if no item matches the typed character', fakeAsync(() => { + it('should not move the active item if no item matches the typed character', async () => { const menu = getMenuPattern(undefined, ['Apple', 'Banana', 'Cherry']); const items = menu.inputs.items(); menu.inputs.activeItem.set(items[0]); const z = createKeyboardEvent('keydown', 90, 'z'); menu.onKeydown(z); - tick(500); + await delay(500); expect(menu.inputs.activeItem()).toBe(items[0]); - })); + }); }); }); describe('Selection', () => { it('should select an item on click', () => { const items = menu.inputs.items(); - menu.inputs.onSubmit = jasmine.createSpy('onSubmit'); + menu.inputs.onSelect = jasmine.createSpy('onSelect'); menu.onClick(clickMenuItem(items, 1)); - expect(menu.inputs.onSubmit).toHaveBeenCalledWith('b'); + expect(menu.inputs.onSelect).toHaveBeenCalledWith('b'); }); it('should select an item on enter', () => { const items = menu.inputs.items(); menu.inputs.activeItem.set(items[1]); - menu.inputs.onSubmit = jasmine.createSpy('onSubmit'); + menu.inputs.onSelect = jasmine.createSpy('onSelect'); menu.onKeydown(enter()); - expect(menu.inputs.onSubmit).toHaveBeenCalledWith('b'); + expect(menu.inputs.onSelect).toHaveBeenCalledWith('b'); }); it('should select an item on space', () => { const items = menu.inputs.items(); menu.inputs.activeItem.set(items[1]); - menu.inputs.onSubmit = jasmine.createSpy('onSubmit'); + menu.inputs.onSelect = jasmine.createSpy('onSelect'); menu.onKeydown(space()); - expect(menu.inputs.onSubmit).toHaveBeenCalledWith('b'); + expect(menu.inputs.onSelect).toHaveBeenCalledWith('b'); }); it('should not select a disabled item', () => { const items = menu.inputs.items() as TestMenuItem[]; - items[1].disabled.set(true); + items[1].inputs.disabled.set(true); menu.inputs.activeItem.set(items[1]); - menu.inputs.onSubmit = jasmine.createSpy('onSubmit'); + menu.inputs.onSelect = jasmine.createSpy('onSelect'); menu.onClick(clickMenuItem(items, 1)); - expect(menu.inputs.onSubmit).not.toHaveBeenCalled(); + expect(menu.inputs.onSelect).not.toHaveBeenCalled(); menu.onKeydown(enter()); - expect(menu.inputs.onSubmit).not.toHaveBeenCalled(); + expect(menu.inputs.onSelect).not.toHaveBeenCalled(); menu.onKeydown(space()); - expect(menu.inputs.onSubmit).not.toHaveBeenCalled(); + expect(menu.inputs.onSelect).not.toHaveBeenCalled(); }); }); describe('Expansion and Collapse', () => { it('should be expanded by default', () => { - expect(menu.isVisible()).toBe(true); - expect(submenu.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu.visible()).toBe(false); }); it('should expand submenu on click', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); it('should open submenu on arrow right', () => { menu.onKeydown(right()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); it('should close submenu on arrow left', () => { menu.onKeydown(right()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(left()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close submenu on click outside', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onFocusOut(new FocusEvent('focusout', {relatedTarget: null})); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should expand submenu on enter', () => { menu.onKeydown(enter()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); it('should expand submenu on space', () => { menu.onKeydown(space()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); it('should close submenu on escape', () => { menu.onKeydown(right()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(escape()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close submenu on arrow left', () => { menu.onKeydown(right()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(left()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); - it('should open submenu on mouseover', () => { + it('should open submenu on mouseover', async () => { const menuItem = menu.inputs.items()[0]; menu.onMouseOver({target: menuItem.element()} as unknown as MouseEvent); - expect(submenu.isVisible()).toBe(true); + await new Promise(resolve => setTimeout(resolve, 0)); + expect(submenu.visible()).toBe(true); }); it('should close on selecting an item on click', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onClick(clickMenuItem(submenu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close on selecting an item on enter', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(enter()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close on selecting an item on space', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(space()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close on focus out from the menu', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onFocusOut(new FocusEvent('focusout', {relatedTarget: null})); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); - it('should close a submenu on focus out', () => { + it('should close a submenu on focus out', async () => { const parentMenuItem = menu.inputs.items()[0]; menu.onMouseOver({target: parentMenuItem.element()} as unknown as MouseEvent); - expect(submenu.isVisible()).toBe(true); + await new Promise(resolve => setTimeout(resolve, 0)); + expect(submenu.visible()).toBe(true); expect(submenu.isFocused()).toBe(false); submenu.onFocusOut(new FocusEvent('focusout', {relatedTarget: document.body})); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); - it('should close an unfocused submenu on mouse out', () => { + it('should close an unfocused submenu on mouse out', async () => { menu.onMouseOver({target: menu.inputs.items()[0].element()} as unknown as MouseEvent); - expect(submenu.isVisible()).toBe(true); + await new Promise(resolve => setTimeout(resolve, 0)); + expect(submenu.visible()).toBe(true); submenu.onMouseOut({relatedTarget: document.body} as unknown as MouseEvent); - expect(submenu.isVisible()).toBe(false); + await new Promise(resolve => setTimeout(resolve, 0)); + expect(submenu.visible()).toBe(false); }); - it('should not close an unfocused submenu on mouse out if the parent menu is hovered', () => { + it('should not close an unfocused submenu on mouse out if the parent menu is hovered', async () => { const parentMenuItem = menu.inputs.items()[0]; menu.onMouseOver({target: parentMenuItem.element()} as unknown as MouseEvent); - expect(submenu.isVisible()).toBe(true); + await new Promise(resolve => setTimeout(resolve, 0)); + expect(submenu.visible()).toBe(true); submenu.onMouseOut({relatedTarget: parentMenuItem.element()} as unknown as MouseEvent); - expect(submenu.isVisible()).toBe(true); + await new Promise(resolve => setTimeout(resolve, 0)); + expect(submenu.visible()).toBe(true); + }); + }); + + describe('RTL', () => { + beforeEach(() => { + const opts = {textDirection: 'rtl' as const}; + menu = getMenuPattern(undefined, ['a', 'b', 'c'], opts); + submenu = getMenuPattern(menu.inputs.items()[0], ['d', 'e'], opts); + }); + + it('should open submenu on arrow left', () => { + menu.onKeydown(left()); + expect(submenu.visible()).toBe(true); + }); + + it('should close submenu on arrow right', () => { + menu.onKeydown(left()); + expect(submenu.visible()).toBe(true); + + submenu.onKeydown(right()); + expect(submenu.visible()).toBe(false); }); }); }); @@ -445,118 +486,118 @@ describe('Menu Trigger Pattern', () => { describe('Expansion and Collapse', () => { it('should be closed by default', () => { expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); + expect(submenu?.visible()).toBe(false); }); it('should open on click', () => { trigger.onClick(); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); }); it('should close on second click', () => { trigger.onClick(); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); + expect(menu.visible()).toBe(true); trigger.onClick(); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); }); it('should open on arrow down', () => { trigger.onKeydown(down()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); }); it('should open on arrow up', () => { trigger.onKeydown(up()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); }); it('should open on space', () => { trigger.onKeydown(space()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); }); it('should open on enter', () => { trigger.onKeydown(enter()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); }); it('should close on escape', () => { trigger.onKeydown(down()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); + expect(menu.visible()).toBe(true); menu.onKeydown(escape()); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); }); it('should close on selecting an item on click', () => { trigger.onClick(); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); menu.onClick(clickMenuItem(menu.inputs.items(), 0)); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(true); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(true); submenu?.onClick(clickMenuItem(submenu.inputs.items(), 0)); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); + expect(submenu?.visible()).toBe(false); }); it('should close on selecting an item on enter', () => { trigger.onKeydown(down()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); menu.onKeydown(right()); - expect(submenu?.isVisible()).toBe(true); + expect(submenu?.visible()).toBe(true); submenu?.onKeydown(enter()); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); + expect(submenu?.visible()).toBe(false); }); it('should close on selecting an item on space', () => { trigger.onKeydown(down()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); menu.onKeydown(right()); - expect(submenu?.isVisible()).toBe(true); + expect(submenu?.visible()).toBe(true); submenu?.onKeydown(space()); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); + expect(submenu?.visible()).toBe(false); }); it('should close the trigger on focus out from the menu', () => { trigger.onKeydown(down()); menu.onFocusOut(new FocusEvent('focusout', {relatedTarget: null})); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); + expect(submenu?.visible()).toBe(false); }); }); }); @@ -580,7 +621,7 @@ describe('Menu Bar Pattern', () => { menubar.inputs.activeItem.set(menubarItems[0]); menubar.onKeydown(down()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menuA.inputs.activeItem()).toBe(menuA.inputs.items()[0]); }); @@ -589,7 +630,7 @@ describe('Menu Bar Pattern', () => { menubar.inputs.activeItem.set(menubarItems[0]); menubar.onKeydown(up()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menuA.inputs.activeItem()).toBe(menuA.inputs.items()[1]); }); @@ -598,7 +639,7 @@ describe('Menu Bar Pattern', () => { menubar.inputs.activeItem.set(menubarItems[0]); menubar.onKeydown(enter()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menuA.inputs.activeItem()).toBe(menuA.inputs.items()[0]); }); @@ -607,45 +648,45 @@ describe('Menu Bar Pattern', () => { menubar.inputs.activeItem.set(menubarItems[0]); menubar.onKeydown(space()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menuA.inputs.activeItem()).toBe(menuA.inputs.items()[0]); }); it('should navigate to a menubar item on mouse over', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); - expect(menuB.isVisible()).toBe(false); + expect(menuA.visible()).toBe(true); + expect(menuB.visible()).toBe(false); const mouseOverEvent = {target: menubarItems[1].element()} as unknown as MouseEvent; menubar.onMouseOver(mouseOverEvent); - expect(menuA.isVisible()).toBe(false); - expect(menuB.isVisible()).toBe(true); + expect(menuA.visible()).toBe(false); + expect(menuB.visible()).toBe(true); expect(menubar.inputs.activeItem()).toBe(menubarItems[1]); }); it('should focus the first item of the next menubar item on arrow right', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); // open menuA - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(right()); - expect(menuA.isVisible()).toBe(false); - expect(menuB.isVisible()).toBe(true); + expect(menuA.visible()).toBe(false); + expect(menuB.visible()).toBe(true); expect(menuB.inputs.activeItem()).toBe(menuB.inputs.items()[0]); }); it('should focus the first item of the previous menubar item on arrow left', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 1)); // open menuB - expect(menuB.isVisible()).toBe(true); + expect(menuB.visible()).toBe(true); menuB.onKeydown(left()); - expect(menuB.isVisible()).toBe(false); - expect(menuA.isVisible()).toBe(true); + expect(menuB.visible()).toBe(false); + expect(menuA.visible()).toBe(true); expect(menuA.inputs.activeItem()).toBe(menuA.inputs.items()[0]); }); }); @@ -657,9 +698,9 @@ describe('Menu Bar Pattern', () => { expect(menubarItems[1].expanded()).toBe(false); expect(menubarItems[2].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); - expect(menuB.isVisible()).toBe(false); - expect(menuC.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); + expect(menuB.visible()).toBe(false); + expect(menuC.visible()).toBe(false); }); it('should expand on click', () => { @@ -670,9 +711,9 @@ describe('Menu Bar Pattern', () => { expect(menubarItems[1].expanded()).toBe(false); expect(menubarItems[2].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(true); - expect(menuB.isVisible()).toBe(false); - expect(menuC.isVisible()).toBe(false); + expect(menuA.visible()).toBe(true); + expect(menuB.visible()).toBe(false); + expect(menuC.visible()).toBe(false); }); it('should collapse on second click', () => { @@ -680,12 +721,12 @@ describe('Menu Bar Pattern', () => { menubar.onClick(clickMenuItem(menubarItems, 0)); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menubar.onClick(clickMenuItem(menubarItems, 0)); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should expand on arrow down', () => { @@ -694,7 +735,7 @@ describe('Menu Bar Pattern', () => { menubar.onKeydown(down()); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); }); it('should expand on arrow up', () => { @@ -703,7 +744,7 @@ describe('Menu Bar Pattern', () => { menubar.onKeydown(up()); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); }); it('should expand on space', () => { @@ -712,7 +753,7 @@ describe('Menu Bar Pattern', () => { menubar.onKeydown(space()); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); }); it('should expand on enter', () => { @@ -721,84 +762,84 @@ describe('Menu Bar Pattern', () => { menubar.onKeydown(enter()); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); }); it('should close on escape', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(escape()); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should close on selecting an item on click', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onClick(clickMenuItem(menuA.inputs.items(), 0)); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should close on selecting an item on enter', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(enter()); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should close on selecting an item on space', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(space()); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should close on focus out from the menu', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onFocusOut(new FocusEvent('focusout', {relatedTarget: null})); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should close on arrow right on a leaf menu item', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(right()); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); expect(menubarItems[0].expanded()).toBe(false); }); it('should close on arrow left on a root menu item', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 1)); - expect(menuB.isVisible()).toBe(true); + expect(menuB.visible()).toBe(true); menuB.onKeydown(left()); - expect(menuB.isVisible()).toBe(false); + expect(menuB.visible()).toBe(false); expect(menubarItems[1].expanded()).toBe(false); }); @@ -808,7 +849,7 @@ describe('Menu Bar Pattern', () => { menuA.onKeydown(right()); - expect(menuB.isVisible()).toBe(true); + expect(menuB.visible()).toBe(true); expect(menubarItems[1].expanded()).toBe(true); expect(menubar.inputs.activeItem()).toBe(menubarItems[1]); }); @@ -819,9 +860,63 @@ describe('Menu Bar Pattern', () => { menuB.onKeydown(left()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menubarItems[0].expanded()).toBe(true); expect(menubar.inputs.activeItem()).toBe(menubarItems[0]); }); + + describe('RTL', () => { + beforeEach(() => { + const opts = {textDirection: 'rtl' as const}; + menubar = getMenuBarPattern(['a', 'b', 'c'], opts); + menuA = getMenuPattern(menubar.inputs.items()[0], ['apple', 'avocado'], opts); + menuB = getMenuPattern(menubar.inputs.items()[1], ['banana', 'blueberry'], opts); + menuC = getMenuPattern(menubar.inputs.items()[2], ['cherry', 'cranberry'], opts); + }); + + it('should close on arrow left on a leaf menu item', () => { + const menubarItems = menubar.inputs.items(); + menubar.onClick(clickMenuItem(menubarItems, 0)); + expect(menuA.visible()).toBe(true); + + menuA.onKeydown(left()); + + expect(menuA.visible()).toBe(false); + expect(menubarItems[0].expanded()).toBe(false); + }); + + it('should close on arrow right on a root menu item', () => { + const menubarItems = menubar.inputs.items(); + menubar.onClick(clickMenuItem(menubarItems, 1)); + expect(menuB.visible()).toBe(true); + + menuB.onKeydown(right()); + + expect(menuB.visible()).toBe(false); + expect(menubarItems[1].expanded()).toBe(false); + }); + + it('should expand the next menu bar item on arrow left on a leaf menu item', () => { + const menubarItems = menubar.inputs.items(); + menubar.onClick(clickMenuItem(menubarItems, 0)); + + menuA.onKeydown(left()); + + expect(menuB.visible()).toBe(true); + expect(menubarItems[1].expanded()).toBe(true); + expect(menubar.inputs.activeItem()).toBe(menubarItems[1]); + }); + + it('should expand the previous menu bar item on arrow right on a root menu item', () => { + const menubarItems = menubar.inputs.items(); + menubar.onClick(clickMenuItem(menubarItems, 1)); + + menuB.onKeydown(right()); + + expect(menuA.visible()).toBe(true); + expect(menubarItems[0].expanded()).toBe(true); + expect(menubar.inputs.activeItem()).toBe(menubarItems[0]); + }); + }); }); }); diff --git a/src/aria/ui-patterns/menu/menu.ts b/src/aria/private/menu/menu.ts similarity index 75% rename from src/aria/ui-patterns/menu/menu.ts rename to src/aria/private/menu/menu.ts index 08f2e96167de..df03df9d979c 100644 --- a/src/aria/ui-patterns/menu/menu.ts +++ b/src/aria/private/menu/menu.ts @@ -6,23 +6,24 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed, Signal, signal} from '@angular/core'; import {KeyboardEventManager} from '../behaviors/event-manager'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; +import {computed, signal, SignalLike} from '../behaviors/signal-like/signal-like'; import {List, ListInputs, ListItem} from '../behaviors/list/list'; /** The inputs for the MenuBarPattern class. */ -export interface MenuBarInputs extends Omit, V>, 'disabled'> { +export interface MenuBarInputs extends ListInputs, V> { /** The menu items contained in the menu. */ items: SignalLike[]>; /** Callback function triggered when a menu item is selected. */ - onSubmit?: (value: V) => void; + onSelect?: (value: V) => void; + + /** The text direction of the menu bar. */ + textDirection: SignalLike<'ltr' | 'rtl'>; } /** The inputs for the MenuPattern class. */ -export interface MenuInputs - extends Omit, V>, 'value' | 'disabled'> { +export interface MenuInputs extends Omit, V>, 'values'> { /** The unique ID of the menu. */ id: SignalLike; @@ -33,7 +34,13 @@ export interface MenuInputs parent: SignalLike | MenuItemPattern | undefined>; /** Callback function triggered when a menu item is selected. */ - onSubmit?: (value: V) => void; + onSelect?: (value: V) => void; + + /** The text direction of the menu bar. */ + textDirection: SignalLike<'ltr' | 'rtl'>; + + /** The delay in milliseconds before expanding sub-menus on hover. */ + expansionDelay: SignalLike; } /** The inputs for the MenuTriggerPattern class. */ @@ -41,11 +48,14 @@ export interface MenuTriggerInputs { /** A reference to the menu trigger element. */ element: SignalLike; - /** A reference to the submenu associated with the menu trigger. */ - submenu: SignalLike | undefined>; + /** A reference to the menu associated with the trigger. */ + menu: SignalLike | undefined>; - /** Callback function triggered when a menu item is selected. */ - onSubmit?: (value: V) => void; + /** The text direction of the menu bar. */ + textDirection: SignalLike<'ltr' | 'rtl'>; + + /** Whether the menu trigger is disabled. */ + disabled: SignalLike; } /** The inputs for the MenuItemPattern class. */ @@ -65,8 +75,11 @@ export class MenuPattern { /** The role of the menu. */ role = () => 'menu'; + /** Whether the menu is disabled. */ + disabled = () => this.inputs.disabled(); + /** Whether the menu is visible. */ - isVisible = computed(() => (this.inputs.parent() ? !!this.inputs.parent()?.expanded() : true)); + visible = computed(() => (this.inputs.parent() ? !!this.inputs.parent()?.expanded() : true)); /** Controls list behavior for the menu items. */ listBehavior: List, V>; @@ -77,6 +90,18 @@ export class MenuPattern { /** Whether the menu has received focus. */ hasBeenFocused = signal(false); + /** Whether the menu trigger has been hovered. */ + hasBeenHovered = signal(false); + + /** Timeout used to open sub-menus on hover. */ + _openTimeout: any; + + /** Timeout used to close sub-menus on hover out. */ + _closeTimeout: any; + + /** The tab index of the menu. */ + tabIndex = () => this.listBehavior.tabIndex(); + /** Whether the menu should be focused on mouse over. */ shouldFocus = computed(() => { const root = this.root(); @@ -109,8 +134,8 @@ export class MenuPattern { typeaheadRegexp = /^.$/; /** The root of the menu. */ - root: Signal | MenuBarPattern | MenuPattern | undefined> = computed( - () => { + root: SignalLike | MenuBarPattern | MenuPattern | undefined> = + computed(() => { const parent = this.inputs.parent(); if (!parent) { @@ -128,8 +153,7 @@ export class MenuPattern { } return grandparent?.root(); - }, - ); + }); /** Handles keyboard events for the menu. */ keydownManager = computed(() => { @@ -150,15 +174,14 @@ export class MenuPattern { this.id = inputs.id; this.listBehavior = new List, V>({ ...inputs, - value: signal([]), - disabled: () => false, + values: signal([]), }); } /** Sets the default state for the menu. */ setDefaultState() { if (!this.inputs.parent()) { - this.inputs.activeItem.set(this.inputs.items()[0]); + this.listBehavior.goto(this.inputs.items()[0], {focusElement: false}); } } @@ -169,33 +192,66 @@ export class MenuPattern { /** Handles mouseover events for the menu. */ onMouseOver(event: MouseEvent) { - if (!this.isVisible()) { + if (!this.visible()) { return; } + this.hasBeenHovered.set(true); const item = this.inputs.items().find(i => i.element()?.contains(event.target as Node)); if (!item) { return; } + const parent = this.inputs.parent(); const activeItem = this?.inputs.activeItem(); + if (parent instanceof MenuItemPattern) { + const grandparent = parent.inputs.parent(); + if (grandparent instanceof MenuPattern) { + grandparent._clearTimeouts(); + grandparent.listBehavior.goto(parent, {focusElement: false}); + } + } + if (activeItem && activeItem !== item) { - activeItem.close(); + this._closeItem(activeItem); } - if (item.expanded() && item.submenu()?.inputs.activeItem()) { - item.submenu()?.inputs.activeItem()?.close(); - item.submenu()?.listBehavior.unfocus(); + if (item.expanded()) { + this._clearCloseTimeout(); } - item.open(); + this._openItem(item); this.listBehavior.goto(item, {focusElement: this.shouldFocus()}); } + /** Closes the specified menu item after a delay. */ + private _closeItem(item: MenuItemPattern) { + this._clearOpenTimeout(); + + if (!this._closeTimeout) { + this._closeTimeout = setTimeout(() => { + item.close(); + this._closeTimeout = undefined; + }, this.inputs.expansionDelay()); + } + } + + /** Opens the specified menu item after a delay. */ + private _openItem(item: MenuItemPattern) { + this._clearOpenTimeout(); + + this._openTimeout = setTimeout(() => { + item.open(); + this._openTimeout = undefined; + }, this.inputs.expansionDelay()); + } + /** Handles mouseout events for the menu. */ onMouseOut(event: MouseEvent) { + this._clearOpenTimeout(); + if (this.isFocused()) { return; } @@ -251,7 +307,7 @@ export class MenuPattern { if (parent instanceof MenuItemPattern) { const grandparent = parent.inputs.parent(); const siblings = grandparent?.inputs.items().filter(i => i !== parent); - const item = siblings?.find(i => i.element().contains(relatedTarget)); + const item = siblings?.find(i => i.element()?.contains(relatedTarget)); if (item) { return; @@ -259,7 +315,7 @@ export class MenuPattern { } if ( - this.isVisible() && + this.visible() && !parentEl?.contains(relatedTarget) && !this.inputs.element()?.contains(relatedTarget) ) { @@ -308,14 +364,18 @@ export class MenuPattern { const isMenuBar = root instanceof MenuBarPattern; const isMenuTrigger = root instanceof MenuTriggerPattern; - if (!item.submenu() && (isMenuTrigger || isMenuBar)) { + if (!item.submenu() && isMenuTrigger) { root.close({refocus: true}); - root?.inputs.onSubmit?.(item.value()); + } + + if (!item.submenu() && isMenuBar) { + root.close(); + root?.inputs.onSelect?.(item.value()); } if (!item.submenu() && isMenu) { root.inputs.activeItem()?.close({refocus: true}); - root?.inputs.onSubmit?.(item.value()); + root?.inputs.onSelect?.(item.value()); } } } @@ -344,6 +404,11 @@ export class MenuPattern { } } + /** Closes the menu. */ + close() { + this.inputs.parent()?.close(); + } + /** Closes the menu and all parent menus. */ closeAll() { const root = this.root(); @@ -360,6 +425,28 @@ export class MenuPattern { root.inputs.activeItem()?.close({refocus: true}); } } + + /** Clears any open or close timeouts for sub-menus. */ + _clearTimeouts() { + this._clearOpenTimeout(); + this._clearCloseTimeout(); + } + + /** Clears the open timeout. */ + _clearOpenTimeout() { + if (this._openTimeout) { + clearTimeout(this._openTimeout); + this._openTimeout = undefined; + } + } + + /** Clears the close timeout. */ + _clearCloseTimeout() { + if (this._closeTimeout) { + clearTimeout(this._closeTimeout); + this._closeTimeout = undefined; + } + } } /** The menubar ui pattern class. */ @@ -367,6 +454,9 @@ export class MenuBarPattern { /** Controls list behavior for the menu items. */ listBehavior: List, V>; + /** The tab index of the menu. */ + tabIndex = () => this.listBehavior.tabIndex(); + /** The key used to navigate to the next item. */ private _nextKey = computed(() => { return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; @@ -389,6 +479,9 @@ export class MenuBarPattern { /** Whether the menubar has been focused. */ hasBeenFocused = signal(false); + /** Whether the menubar is disabled. */ + disabled = () => this.inputs.disabled(); + /** Handles keyboard events for the menu. */ keydownManager = computed(() => { return new KeyboardEventManager() @@ -404,7 +497,7 @@ export class MenuBarPattern { }); constructor(readonly inputs: MenuBarInputs) { - this.listBehavior = new List, V>({...inputs, disabled: () => false}); + this.listBehavior = new List, V>(inputs); } /** Sets the default state for the menubar. */ @@ -505,17 +598,23 @@ export class MenuTriggerPattern { /** Whether the menu is expanded. */ expanded = signal(false); + /** Whether the menu trigger has received focus. */ + hasBeenFocused = signal(false); + /** The role of the menu trigger. */ role = () => 'button'; /** Whether the menu trigger has a popup. */ hasPopup = () => true; - /** The submenu associated with the trigger. */ - submenu: SignalLike | undefined>; + /** The menu associated with the trigger. */ + menu: SignalLike | undefined>; + + /** The tab index of the menu trigger. */ + tabIndex = computed(() => (this.expanded() && this.menu()?.inputs.activeItem() ? -1 : 0)); - /** The tabindex of the menu trigger. */ - tabindex = computed(() => (this.expanded() && this.submenu()?.inputs.activeItem() ? -1 : 0)); + /** Whether the menu trigger is disabled. */ + disabled = () => this.inputs.disabled(); /** Handles keyboard events for the menu trigger. */ keydownManager = computed(() => { @@ -528,17 +627,26 @@ export class MenuTriggerPattern { }); constructor(readonly inputs: MenuTriggerInputs) { - this.submenu = this.inputs.submenu; + this.menu = this.inputs.menu; } /** Handles keyboard events for the menu trigger. */ onKeydown(event: KeyboardEvent) { - this.keydownManager().handle(event); + if (!this.inputs.disabled()) { + this.keydownManager().handle(event); + } } /** Handles click events for the menu trigger. */ onClick() { - this.expanded() ? this.close() : this.open({first: true}); + if (!this.inputs.disabled()) { + this.expanded() ? this.close() : this.open({first: true}); + } + } + + /** Handles focusin events for the menu trigger. */ + onFocusIn() { + this.hasBeenFocused.set(true); } /** Handles focusout events for the menu trigger. */ @@ -549,7 +657,7 @@ export class MenuTriggerPattern { if ( this.expanded() && !element?.contains(relatedTarget) && - !this.inputs.submenu()?.inputs.element()?.contains(relatedTarget) + !this.inputs.menu()?.inputs.element()?.contains(relatedTarget) ) { this.close(); } @@ -560,22 +668,22 @@ export class MenuTriggerPattern { this.expanded.set(true); if (opts?.first) { - this.inputs.submenu()?.first(); + this.inputs.menu()?.first(); } else if (opts?.last) { - this.inputs.submenu()?.last(); + this.inputs.menu()?.last(); } } /** Closes the menu. */ close(opts: {refocus?: boolean} = {}) { this.expanded.set(false); - this.submenu()?.listBehavior.unfocus(); + this.menu()?.listBehavior.unfocus(); if (opts.refocus) { this.inputs.element()?.focus(); } - let menuitems = this.inputs.submenu()?.inputs.items() ?? []; + let menuitems = this.inputs.menu()?.inputs.items() ?? []; while (menuitems.length) { const menuitem = menuitems.pop(); @@ -595,19 +703,22 @@ export class MenuItemPattern implements ListItem { id: SignalLike; /** Whether the menu item is disabled. */ - disabled: SignalLike; + disabled = () => this.inputs.parent()?.disabled() || this.inputs.disabled(); /** The search term for the menu item. */ searchTerm: SignalLike; /** The element of the menu item. */ - element: SignalLike; + element: SignalLike; /** Whether the menu item is active. */ - isActive = computed(() => this.inputs.parent()?.inputs.activeItem() === this); + active = computed(() => this.inputs.parent()?.inputs.activeItem() === this); - /** The tabindex of the menu item. */ - tabindex = computed(() => { + /** Whether the menu item has received focus. */ + hasBeenFocused = signal(false); + + /** The tab index of the menu item. */ + tabIndex = computed(() => { if (this.submenu() && this.submenu()?.inputs.activeItem()) { return -1; } @@ -642,7 +753,6 @@ export class MenuItemPattern implements ListItem { this.id = inputs.id; this.value = inputs.value; this.element = inputs.element; - this.disabled = inputs.disabled; this.submenu = this.inputs.submenu; this.searchTerm = inputs.searchTerm; this.selectable = computed(() => !this.submenu()); @@ -650,6 +760,10 @@ export class MenuItemPattern implements ListItem { /** Opens the submenu. */ open(opts?: {first?: boolean; last?: boolean}) { + if (this.disabled()) { + return; + } + this._expanded.set(true); if (opts?.first) { @@ -675,6 +789,17 @@ export class MenuItemPattern implements ListItem { menuitem?._expanded.set(false); menuitem?.inputs.parent()?.listBehavior.unfocus(); menuitems = menuitems.concat(menuitem?.submenu()?.inputs.items() ?? []); + + const parent = menuitem?.inputs.parent(); + + if (parent instanceof MenuPattern) { + parent._clearTimeouts(); + } } } + + /** Handles focusin events for the menu item. */ + onFocusIn() { + this.hasBeenFocused.set(true); + } } diff --git a/src/aria/ui-patterns/public-api.ts b/src/aria/private/public-api.ts similarity index 86% rename from src/aria/ui-patterns/public-api.ts rename to src/aria/private/public-api.ts index 90367fef69f0..ed8716c7b67b 100644 --- a/src/aria/ui-patterns/public-api.ts +++ b/src/aria/private/public-api.ts @@ -11,9 +11,6 @@ export * from './listbox/listbox'; export * from './listbox/option'; export * from './listbox/combobox-listbox'; export * from './menu/menu'; -export * from './radio-group/radio-group'; -export * from './radio-group/radio-button'; -export * from './radio-group/toolbar-radio-group'; export * from './behaviors/signal-like/signal-like'; export * from './tabs/tabs'; export * from './toolbar/toolbar'; @@ -27,3 +24,4 @@ export * from './grid/grid'; export * from './grid/row'; export * from './grid/cell'; export * from './grid/widget'; +export * from './deferred-content'; diff --git a/src/aria/ui-patterns/tabs/BUILD.bazel b/src/aria/private/tabs/BUILD.bazel similarity index 62% rename from src/aria/ui-patterns/tabs/BUILD.bazel rename to src/aria/private/tabs/BUILD.bazel index fbd6d5598c61..891074f610e6 100644 --- a/src/aria/ui-patterns/tabs/BUILD.bazel +++ b/src/aria/private/tabs/BUILD.bazel @@ -9,11 +9,12 @@ ts_project( ], deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/event-manager", - "//src/aria/ui-patterns/behaviors/expansion", - "//src/aria/ui-patterns/behaviors/label", - "//src/aria/ui-patterns/behaviors/list", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/event-manager", + "//src/aria/private/behaviors/expansion", + "//src/aria/private/behaviors/label", + "//src/aria/private/behaviors/list-focus", + "//src/aria/private/behaviors/list-navigation", + "//src/aria/private/behaviors/signal-like", ], ) @@ -26,7 +27,7 @@ ng_project( deps = [ ":tabs", "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/signal-like", "//src/cdk/keycodes", "//src/cdk/testing/private", ], diff --git a/src/aria/private/tabs/tabs.spec.ts b/src/aria/private/tabs/tabs.spec.ts new file mode 100644 index 000000000000..71129712e423 --- /dev/null +++ b/src/aria/private/tabs/tabs.spec.ts @@ -0,0 +1,394 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + TabInputs, + TabPattern, + TabListInputs, + TabListPattern, + TabPanelInputs, + TabPanelPattern, +} from './tabs'; +import {signal, SignalLike, WritableSignalLike} from '../behaviors/signal-like/signal-like'; +import {createKeyboardEvent} from '@angular/cdk/testing/private'; +import {ModifierKeys} from '@angular/cdk/testing'; + +// Converts the SignalLike type to WritableSignalLike type for controlling test inputs. +type WritableSignalOverrides = { + [K in keyof O as O[K] extends SignalLike ? K : never]: O[K] extends SignalLike + ? WritableSignalLike + : never; +}; + +type TestTabListInputs = TabListInputs & WritableSignalOverrides; +type TestTabInputs = TabInputs & WritableSignalOverrides; +type TestTabPanelInputs = TabPanelInputs & WritableSignalOverrides; + +const up = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 38, 'ArrowUp', mods); +const down = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 40, 'ArrowDown', mods); +const left = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 37, 'ArrowLeft', mods); +const right = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 39, 'ArrowRight', mods); +const home = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 36, 'Home', mods); +const end = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 35, 'End', mods); +const space = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 32, ' ', mods); +const enter = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 13, 'Enter', mods); + +function createTabElement(): HTMLElement { + const element = document.createElement('div'); + element.role = 'tab'; + return element; +} + +describe('Tabs Pattern', () => { + let tabListInputs: TestTabListInputs; + let tabListPattern: TabListPattern; + let tabInputs: TestTabInputs[]; + let tabPatterns: TabPattern[]; + let tabPanelInputs: TestTabPanelInputs[]; + let tabPanelPatterns: TabPanelPattern[]; + + beforeEach(() => { + // Initiate TabListPattern. + tabListInputs = { + orientation: signal('horizontal'), + wrap: signal(true), + textDirection: signal('ltr'), + selectionMode: signal('follow'), + focusMode: signal('roving'), + disabled: signal(false), + activeItem: signal(undefined), + softDisabled: signal(true), + items: signal([]), + element: signal(document.createElement('div')), + }; + tabListPattern = new TabListPattern(tabListInputs); + + // Initiate a list of TabPatterns. + tabInputs = [ + { + tablist: signal(tabListPattern), + tabpanel: signal(undefined), + id: signal('tab-1-id'), + element: signal(createTabElement()), + disabled: signal(false), + value: signal('tab-1'), + expanded: signal(false), + }, + { + tablist: signal(tabListPattern), + tabpanel: signal(undefined), + id: signal('tab-2-id'), + element: signal(createTabElement()), + disabled: signal(false), + value: signal('tab-2'), + expanded: signal(false), + }, + { + tablist: signal(tabListPattern), + tabpanel: signal(undefined), + id: signal('tab-3-id'), + element: signal(createTabElement()), + disabled: signal(false), + value: signal('tab-3'), + expanded: signal(false), + }, + ]; + tabPatterns = [ + new TabPattern(tabInputs[0]), + new TabPattern(tabInputs[1]), + new TabPattern(tabInputs[2]), + ]; + + // Initiate a list of TabPanelPatterns. + tabPanelInputs = [ + { + id: signal('tabpanel-1-id'), + tab: signal(undefined), + value: signal('tab-1'), + }, + { + id: signal('tabpanel-2-id'), + tab: signal(undefined), + value: signal('tab-2'), + }, + { + id: signal('tabpanel-3-id'), + tab: signal(undefined), + value: signal('tab-3'), + }, + ]; + tabPanelPatterns = [ + new TabPanelPattern(tabPanelInputs[0]), + new TabPanelPattern(tabPanelInputs[1]), + new TabPanelPattern(tabPanelInputs[2]), + ]; + + // Binding between tabs and tabpanels. + tabInputs[0].tabpanel.set(tabPanelPatterns[0]); + tabInputs[1].tabpanel.set(tabPanelPatterns[1]); + tabInputs[2].tabpanel.set(tabPanelPatterns[2]); + tabPanelInputs[0].tab.set(tabPatterns[0]); + tabPanelInputs[1].tab.set(tabPatterns[1]); + tabPanelInputs[2].tab.set(tabPatterns[2]); + tabListInputs.items.set(tabPatterns); + tabListInputs.activeItem.set(tabPatterns[0]); + }); + + describe('TabListPattern', () => { + describe('#open', () => { + it('should open a tab with value', () => { + expect(tabListPattern.selectedTab()).toBeUndefined(); + tabListPattern.open('tab-1'); + expect(tabListPattern.selectedTab()!.value()).toBe('tab-1'); + }); + + it('should open a tab with tab pattern instance', () => { + expect(tabListPattern.selectedTab()).toBeUndefined(); + tabListPattern.open(tabPatterns[0]); + expect(tabListPattern.selectedTab()).toBe(tabPatterns[0]); + }); + + it('should open the active tab', () => { + expect(tabListPattern.selectedTab()).toBeUndefined(); + expect(tabListPattern.activeTab()).toBe(tabPatterns[0]); + tabListPattern.open(); + expect(tabListPattern.selectedTab()).toBe(tabPatterns[0]); + }); + }); + + describe('#setDefaultState', () => { + it('should not set activeIndex if there are no tabs', () => { + tabListInputs.items.set([]); + tabListInputs.activeItem.set(tabPatterns[10]); + tabListPattern.setDefaultState(); + expect(tabListInputs.activeItem()).toBe(tabPatterns[10]); + }); + + it('should not set activeIndex if no tabs are focusable', () => { + tabListInputs.softDisabled.set(false); + tabInputs.forEach(input => input.disabled.set(true)); + tabListInputs.activeItem.set(tabPatterns[10]); + tabListPattern.setDefaultState(); + expect(tabListInputs.activeItem()).toBe(tabPatterns[10]); + }); + + it('should set activeIndex to the first focusable tab if no tabs are selected', () => { + tabListInputs.softDisabled.set(false); + tabListInputs.activeItem.set(tabPatterns[2]); + tabListPattern.selectedTab.set(undefined); + tabInputs[0].disabled.set(true); + tabListPattern.setDefaultState(); + expect(tabListInputs.activeItem()).toBe(tabPatterns[1]); + }); + + it('should set activeIndex to the first focusable and selected tab', () => { + tabListInputs.activeItem.set(tabPatterns[0]); + tabListPattern.selectedTab.set(tabPatterns[2]); + tabListPattern.setDefaultState(); + expect(tabListInputs.activeItem()).toBe(tabPatterns[2]); + }); + + it('should set activeIndex to the first focusable tab when the selected tab is not focusable', () => { + tabListInputs.softDisabled.set(false); + tabListPattern.selectedTab.set(tabPatterns[1]); + tabInputs[1].disabled.set(true); + tabListPattern.setDefaultState(); + expect(tabListInputs.activeItem()).toBe(tabPatterns[0]); + }); + }); + + describe('Keyboard Navigation', () => { + it('does not handle keyboard event if a tablist is disabled.', () => { + expect(tabPatterns[1].active()).toBeFalse(); + tabListInputs.disabled.set(true); + tabListPattern.onKeydown(right()); + expect(tabPatterns[1].active()).toBeFalse(); + }); + + it('skips the disabled tab when `softDisabled` is set to false.', () => { + tabListInputs.softDisabled.set(false); + tabInputs[1].disabled.set(true); + tabListPattern.onKeydown(right()); + expect(tabPatterns[0].active()).toBeFalse(); + expect(tabPatterns[1].active()).toBeFalse(); + expect(tabPatterns[2].active()).toBeTrue(); + }); + + it('does not skip the disabled tab when `softDisabled` is set to true.', () => { + tabInputs[1].disabled.set(true); + tabListPattern.onKeydown(right()); + expect(tabPatterns[0].active()).toBeFalse(); + expect(tabPatterns[1].active()).toBeTrue(); + expect(tabPatterns[2].active()).toBeFalse(); + }); + + it('selects a tab by focus if `selectionMode` is "follow".', () => { + tabListPattern.onKeydown(space()); + expect(tabPatterns[0].selected()).toBeTrue(); + expect(tabPatterns[1].selected()).toBeFalse(); + tabListPattern.onKeydown(right()); + expect(tabPatterns[0].selected()).toBeFalse(); + expect(tabPatterns[1].selected()).toBeTrue(); + }); + + it('selects a tab by enter key if `selectionMode` is "explicit".', () => { + tabListInputs.selectionMode.set('explicit'); + tabListPattern.onKeydown(space()); + expect(tabPatterns[0].selected()).toBeTrue(); + expect(tabPatterns[1].selected()).toBeFalse(); + tabListPattern.onKeydown(right()); + expect(tabPatterns[0].selected()).toBeTrue(); + expect(tabPatterns[1].selected()).toBeFalse(); + tabListPattern.onKeydown(enter()); + expect(tabPatterns[0].selected()).toBeFalse(); + expect(tabPatterns[1].selected()).toBeTrue(); + }); + + it('selects a tab by space key if `selectionMode` is "explicit".', () => { + tabListInputs.selectionMode.set('explicit'); + tabListPattern.onKeydown(space()); + expect(tabPatterns[0].selected()).toBeTrue(); + expect(tabPatterns[1].selected()).toBeFalse(); + tabListPattern.onKeydown(right()); + expect(tabPatterns[0].selected()).toBeTrue(); + expect(tabPatterns[1].selected()).toBeFalse(); + tabListPattern.onKeydown(space()); + expect(tabPatterns[0].selected()).toBeFalse(); + expect(tabPatterns[1].selected()).toBeTrue(); + }); + + it('uses left key to navigate to the previous tab when `orientation` is set to "horizontal".', () => { + tabListInputs.activeItem.set(tabPatterns[1]); + expect(tabPatterns[1].active()).toBeTrue(); + tabListPattern.onKeydown(left()); + expect(tabPatterns[0].active()).toBeTrue(); + }); + + it('uses right key to navigate to the next tab when `orientation` is set to "horizontal".', () => { + tabListInputs.activeItem.set(tabPatterns[1]); + expect(tabPatterns[1].active()).toBeTrue(); + tabListPattern.onKeydown(right()); + expect(tabPatterns[2].active()).toBeTrue(); + }); + + it('uses up key to navigate to the previous tab when `orientation` is set to "vertical".', () => { + tabListInputs.orientation.set('vertical'); + tabListInputs.activeItem.set(tabPatterns[1]); + expect(tabPatterns[1].active()).toBeTrue(); + tabListPattern.onKeydown(up()); + expect(tabPatterns[0].active()).toBeTrue(); + }); + + it('uses down key to navigate to the next tab when `orientation` is set to "vertical".', () => { + tabListInputs.orientation.set('vertical'); + tabListInputs.activeItem.set(tabPatterns[1]); + expect(tabPatterns[1].active()).toBeTrue(); + tabListPattern.onKeydown(down()); + expect(tabPatterns[2].active()).toBeTrue(); + }); + + it('uses home key to navigate to the first tab.', () => { + tabListInputs.activeItem.set(tabPatterns[1]); + expect(tabPatterns[1].active()).toBeTrue(); + tabListPattern.onKeydown(home()); + expect(tabPatterns[0].active()).toBeTrue(); + }); + + it('uses end key to navigate to the last tab.', () => { + tabListInputs.activeItem.set(tabPatterns[1]); + expect(tabPatterns[1].active()).toBeTrue(); + tabListPattern.onKeydown(end()); + expect(tabPatterns[2].active()).toBeTrue(); + }); + + it('moves to the last tab from first tab when navigating to the previous tab if `wrap` is set to true', () => { + expect(tabPatterns[0].active()).toBeTrue(); + tabListPattern.onKeydown(left()); + expect(tabPatterns[2].active()).toBeTrue(); + }); + + it('moves to the first tab from last tab when navigating to the next tab if `wrap` is set to true', () => { + tabListPattern.onKeydown(end()); + expect(tabPatterns[2].active()).toBeTrue(); + tabListPattern.onKeydown(right()); + expect(tabPatterns[0].active()).toBeTrue(); + }); + + it('stays on the first tab when navigating to the previous tab if `wrap` is set to false', () => { + tabListInputs.wrap.set(false); + expect(tabPatterns[0].active()).toBeTrue(); + tabListPattern.onKeydown(left()); + expect(tabPatterns[0].active()).toBeTrue(); + }); + + it('stays on the last tab when navigating to the next tab if `wrap` is set to false', () => { + tabListInputs.wrap.set(false); + tabListPattern.onKeydown(end()); + expect(tabPatterns[2].active()).toBeTrue(); + tabListPattern.onKeydown(right()); + expect(tabPatterns[2].active()).toBeTrue(); + }); + + it('changes the navigation direction with `rtl` mode.', () => { + tabListInputs.textDirection.set('rtl'); + tabListInputs.activeItem.set(tabPatterns[1]); + tabListPattern.onKeydown(left()); + expect(tabPatterns[2].active()).toBeTrue(); + }); + }); + }); + + describe('TabPattern', () => { + it('gets a controlled tabpanel id from a tab', () => { + expect(tabPanelPatterns[0].id()).toBe('tabpanel-1-id'); + expect(tabPatterns[0].controls()).toBe('tabpanel-1-id'); + expect(tabPanelPatterns[1].id()).toBe('tabpanel-2-id'); + expect(tabPatterns[1].controls()).toBe('tabpanel-2-id'); + expect(tabPanelPatterns[2].id()).toBe('tabpanel-3-id'); + expect(tabPatterns[2].controls()).toBe('tabpanel-3-id'); + }); + + describe('#open', () => { + it('should open the current tab', () => { + expect(tabListPattern.selectedTab()).toBeUndefined(); + tabPatterns[0].open(); + expect(tabListPattern.selectedTab()).toBe(tabPatterns[0]); + }); + }); + }); + + describe('TabPanelPattern', () => { + it('should set a tabpanel to be not hidden if a tab is opened', () => { + tabPatterns[0].open(); + expect(tabPatterns[0].selected()).toBeTrue(); + expect(tabPanelPatterns[0].hidden()).toBeFalse(); + }); + + it('sets a tabpanel to be hidden if a tab is not opened', () => { + expect(tabPatterns[1].selected()).toBeFalse(); + expect(tabPanelPatterns[1].hidden()).toBeTrue(); + }); + + it('should set a tabpanel tab index to 0 if the tab is opened', () => { + tabPatterns[0].open(); + expect(tabPatterns[0].tabIndex()).toBe(0); + }); + + it('should set a tabpanel tab index to -1 if the tab is not opened', () => { + tabPatterns[0].open(); + expect(tabPatterns[1].tabIndex()).toBe(-1); + expect(tabPatterns[2].tabIndex()).toBe(-1); + }); + + it('should set a tabpanel aria-labelledby pointing to its tab id', () => { + expect(tabPanelPatterns[0].labelledBy()).toBe('tab-1-id'); + expect(tabPanelPatterns[1].labelledBy()).toBe('tab-2-id'); + expect(tabPanelPatterns[2].labelledBy()).toBe('tab-3-id'); + }); + }); +}); diff --git a/src/aria/ui-patterns/tabs/tabs.ts b/src/aria/private/tabs/tabs.ts similarity index 52% rename from src/aria/ui-patterns/tabs/tabs.ts rename to src/aria/private/tabs/tabs.ts index 95f593009343..22cf46091efd 100644 --- a/src/aria/ui-patterns/tabs/tabs.ts +++ b/src/aria/private/tabs/tabs.ts @@ -6,104 +6,99 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed} from '@angular/core'; import {KeyboardEventManager, PointerEventManager} from '../behaviors/event-manager'; +import {ExpansionItem, ListExpansionInputs, ListExpansion} from '../behaviors/expansion/expansion'; import { - ExpansionItem, - ExpansionControl, - ListExpansionInputs, - ListExpansion, -} from '../behaviors/expansion/expansion'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; + SignalLike, + computed, + signal, + WritableSignalLike, +} from '../behaviors/signal-like/signal-like'; import {LabelControl, LabelControlOptionalInputs} from '../behaviors/label/label'; -import {List, ListInputs, ListItem} from '../behaviors/list/list'; +import {ListFocus} from '../behaviors/list-focus/list-focus'; +import { + ListNavigationItem, + ListNavigation, + ListNavigationInputs, +} from '../behaviors/list-navigation/list-navigation'; /** The required inputs to tabs. */ export interface TabInputs - extends Omit, 'searchTerm' | 'index' | 'selectable'>, - Omit { + extends Omit, Omit { /** The parent tablist that controls the tab. */ tablist: SignalLike; /** The remote tabpanel controlled by the tab. */ tabpanel: SignalLike; + + /** The remote tabpanel unique identifier. */ + value: SignalLike; } /** A tab in a tablist. */ export class TabPattern { - /** Controls expansion for this tab. */ - readonly expansion: ExpansionControl; - /** A global unique identifier for the tab. */ - readonly id: SignalLike; + readonly id: SignalLike = () => this.inputs.id(); /** The index of the tab. */ readonly index = computed(() => this.inputs.tablist().inputs.items().indexOf(this)); - /** A local unique identifier for the tab. */ - readonly value: SignalLike; + /** The remote tabpanel unique identifier. */ + readonly value: SignalLike = () => this.inputs.value(); /** Whether the tab is disabled. */ - readonly disabled: SignalLike; + readonly disabled: SignalLike = () => this.inputs.disabled(); /** The html element that should receive focus. */ - readonly element: SignalLike; + readonly element: SignalLike = () => this.inputs.element()!; - /** Whether the tab is selectable. */ - readonly selectable = () => true; + /** Whether this tab has expandable panel. */ + readonly expandable: SignalLike = () => true; - /** The text used by the typeahead search. */ - readonly searchTerm = () => ''; // Unused because tabs do not support typeahead. - - /** Whether this tab has expandable content. */ - readonly expandable = computed(() => this.expansion.expandable()); - - /** The unique identifier used by the expansion behavior. */ - readonly expansionId = computed(() => this.expansion.expansionId()); - - /** Whether the tab is expanded. */ - readonly expanded = computed(() => this.expansion.isExpanded()); + /** Whether the tab panel is expanded. */ + readonly expanded: WritableSignalLike; /** Whether the tab is active. */ readonly active = computed(() => this.inputs.tablist().inputs.activeItem() === this); /** Whether the tab is selected. */ - readonly selected = computed(() => !!this.inputs.tablist().inputs.value().includes(this.value())); + readonly selected = computed(() => this.inputs.tablist().selectedTab() === this); - /** The tabindex of the tab. */ - readonly tabindex = computed(() => this.inputs.tablist().listBehavior.getItemTabindex(this)); + /** The tab index of the tab. */ + readonly tabIndex = computed(() => this.inputs.tablist().focusBehavior.getItemTabIndex(this)); /** The id of the tabpanel associated with the tab. */ readonly controls = computed(() => this.inputs.tabpanel()?.id()); constructor(readonly inputs: TabInputs) { - this.id = inputs.id; - this.value = inputs.value; - this.disabled = inputs.disabled; - this.element = inputs.element; - this.expansion = new ExpansionControl({ - ...inputs, - expansionId: inputs.value, - expandable: () => true, - expansionManager: inputs.tablist().expansionManager, - }); + this.expanded = inputs.expanded; + } + + /** Opens the tab. */ + open(): boolean { + return this.inputs.tablist().open(this); } } /** The required inputs for the tabpanel. */ export interface TabPanelInputs extends LabelControlOptionalInputs { + /** A global unique identifier for the tabpanel. */ id: SignalLike; + + /** The tab that controls this tabpanel. */ tab: SignalLike; + + /** A local unique identifier for the tabpanel. */ value: SignalLike; } /** A tabpanel associated with a tab. */ export class TabPanelPattern { /** A global unique identifier for the tabpanel. */ - readonly id: SignalLike; + readonly id: SignalLike = () => this.inputs.id(); /** A local unique identifier for the tabpanel. */ - readonly value: SignalLike; + readonly value: SignalLike = () => this.inputs.value(); /** Controls label for this tabpanel. */ readonly labelManager: LabelControl; @@ -111,8 +106,8 @@ export class TabPanelPattern { /** Whether the tabpanel is hidden. */ readonly hidden = computed(() => this.inputs.tab()?.expanded() === false); - /** The tabindex of this tabpanel. */ - readonly tabindex = computed(() => (this.hidden() ? -1 : 0)); + /** The tab index of this tabpanel. */ + readonly tabIndex = computed(() => (this.hidden() ? -1 : 0)); /** The aria-labelledby value for this tabpanel. */ readonly labelledBy = computed(() => @@ -122,8 +117,6 @@ export class TabPanelPattern { ); constructor(readonly inputs: TabPanelInputs) { - this.id = inputs.id; - this.value = inputs.value; this.labelManager = new LabelControl({ ...inputs, defaultLabelledBy: computed(() => (this.inputs.tab() ? [this.inputs.tab()!.id()] : [])), @@ -132,28 +125,42 @@ export class TabPanelPattern { } /** The required inputs for the tablist. */ -export type TabListInputs = Omit, 'multi' | 'typeaheadDelay'> & - Omit; +export interface TabListInputs + extends + Omit, 'multi'>, + Omit { + /** The selection strategy used by the tablist. */ + selectionMode: SignalLike<'follow' | 'explicit'>; +} /** Controls the state of a tablist. */ export class TabListPattern { - /** The list behavior for the tablist. */ - readonly listBehavior: List; + /** The list focus behavior for the tablist. */ + readonly focusBehavior: ListFocus; + + /** The list navigation behavior for the tablist. */ + readonly navigationBehavior: ListNavigation; /** Controls expansion for the tablist. */ - readonly expansionManager: ListExpansion; + readonly expansionBehavior: ListExpansion; + + /** The currently active tab. */ + readonly activeTab: SignalLike = () => this.inputs.activeItem(); + + /** The currently selected tab. */ + readonly selectedTab: WritableSignalLike = signal(undefined); /** Whether the tablist is vertically or horizontally oriented. */ - readonly orientation: SignalLike<'vertical' | 'horizontal'>; + readonly orientation: SignalLike<'vertical' | 'horizontal'> = () => this.inputs.orientation(); /** Whether the tablist is disabled. */ - readonly disabled: SignalLike; + readonly disabled: SignalLike = () => this.inputs.disabled(); - /** The tabindex of the tablist. */ - readonly tabindex = computed(() => this.listBehavior.tabindex()); + /** The tab index of the tablist. */ + readonly tabIndex = computed(() => this.focusBehavior.getListTabIndex()); /** The id of the current active tab. */ - readonly activedescendant = computed(() => this.listBehavior.activedescendant()); + readonly activeDescendant = computed(() => this.focusBehavior.getActiveDescendant()); /** Whether selection should follow focus. */ readonly followFocus = computed(() => this.inputs.selectionMode() === 'follow'); @@ -177,35 +184,36 @@ export class TabListPattern { /** The keydown event manager for the tablist. */ readonly keydown = computed(() => { return new KeyboardEventManager() - .on(this.prevKey, () => this.listBehavior.prev({select: this.followFocus()})) - .on(this.nextKey, () => this.listBehavior.next({select: this.followFocus()})) - .on('Home', () => this.listBehavior.first({select: this.followFocus()})) - .on('End', () => this.listBehavior.last({select: this.followFocus()})) - .on(' ', () => this.listBehavior.select()) - .on('Enter', () => this.listBehavior.select()); + .on(this.prevKey, () => + this._navigate(() => this.navigationBehavior.prev(), this.followFocus()), + ) + .on(this.nextKey, () => + this._navigate(() => this.navigationBehavior.next(), this.followFocus()), + ) + .on('Home', () => this._navigate(() => this.navigationBehavior.first(), this.followFocus())) + .on('End', () => this._navigate(() => this.navigationBehavior.last(), this.followFocus())) + .on(' ', () => this.open()) + .on('Enter', () => this.open()); }); /** The pointerdown event manager for the tablist. */ readonly pointerdown = computed(() => { return new PointerEventManager().on(e => - this.listBehavior.goto(this._getItem(e)!, {select: true}), + this._navigate(() => this.navigationBehavior.goto(this._getItem(e)!), true), ); }); constructor(readonly inputs: TabListInputs) { - this.disabled = inputs.disabled; - this.orientation = inputs.orientation; + this.focusBehavior = new ListFocus(inputs); - this.listBehavior = new List({ + this.navigationBehavior = new ListNavigation({ ...inputs, - multi: () => false, - typeaheadDelay: () => 0, // Tabs do not support typeahead. + focusManager: this.focusBehavior, }); - this.expansionManager = new ListExpansion({ + this.expansionBehavior = new ListExpansion({ ...inputs, multiExpandable: () => false, - expandedIds: this.inputs.value, }); } @@ -221,7 +229,7 @@ export class TabListPattern { let firstItem: TabPattern | undefined; for (const item of this.inputs.items()) { - if (!this.listBehavior.isFocusable(item)) continue; + if (!this.focusBehavior.isFocusable(item)) continue; if (firstItem === undefined) { firstItem = item; @@ -251,6 +259,37 @@ export class TabListPattern { } } + /** Opens the tab by given value. */ + open(value: string): boolean; + + /** Opens the given tab or the current active tab. */ + open(tab?: TabPattern): boolean; + + open(tab: TabPattern | string | undefined): boolean { + tab ??= this.activeTab(); + + if (typeof tab === 'string') { + tab = this.inputs.items().find(t => t.value() === tab); + } + + if (tab === undefined) return false; + + const success = this.expansionBehavior.open(tab); + if (success) { + this.selectedTab.set(tab); + } + + return success; + } + + /** Executes a navigation operation and expand the active tab if needed. */ + private _navigate(op: () => boolean, shouldExpand: boolean = false): void { + const success = op(); + if (success && shouldExpand) { + this.open(); + } + } + /** Returns the tab item associated with the given pointer event. */ private _getItem(e: PointerEvent) { if (!(e.target instanceof HTMLElement)) { diff --git a/src/aria/ui-patterns/toolbar/BUILD.bazel b/src/aria/private/toolbar/BUILD.bazel similarity index 71% rename from src/aria/ui-patterns/toolbar/BUILD.bazel rename to src/aria/private/toolbar/BUILD.bazel index 1c3d9d978ebe..6c2dd3d6221b 100644 --- a/src/aria/ui-patterns/toolbar/BUILD.bazel +++ b/src/aria/private/toolbar/BUILD.bazel @@ -11,9 +11,9 @@ ts_project( ], deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/event-manager", - "//src/aria/ui-patterns/behaviors/list", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/event-manager", + "//src/aria/private/behaviors/list", + "//src/aria/private/behaviors/signal-like", ], ) @@ -24,8 +24,7 @@ ng_project( deps = [ ":toolbar", "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", - "//src/aria/ui-patterns/radio-group", + "//src/aria/private/behaviors/signal-like", "//src/cdk/keycodes", "//src/cdk/testing/private", ], diff --git a/src/aria/private/toolbar/toolbar-widget-group.ts b/src/aria/private/toolbar/toolbar-widget-group.ts new file mode 100644 index 000000000000..c59eeb231204 --- /dev/null +++ b/src/aria/private/toolbar/toolbar-widget-group.ts @@ -0,0 +1,45 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {ListItem} from '../behaviors/list/list'; +import {SignalLike} from '../behaviors/signal-like/signal-like'; +import type {ToolbarPattern} from './toolbar'; + +/** Represents the required inputs for a toolbar widget group. */ +export interface ToolbarWidgetGroupInputs, V> { + /** A reference to the parent toolbar. */ + toolbar: SignalLike | undefined>; + + /** Whether the widget group is disabled. */ + disabled: SignalLike; + + /** The list of items within the widget group. */ + items: SignalLike; + + /** Whether the group allows multiple widgets to be selected. */ + multi: SignalLike; +} + +/** A group of widgets within a toolbar that provides nested navigation. */ +export class ToolbarWidgetGroupPattern, V> { + /** Whether the widget is disabled. */ + readonly disabled = () => this.inputs.disabled(); + + /** A reference to the parent toolbar. */ + readonly toolbar = () => this.inputs.toolbar(); + + /** Whether the group allows multiple widgets to be selected. */ + readonly multi = () => this.inputs.multi(); + + readonly searchTerm = () => ''; // Unused because toolbar does not support typeahead. + readonly value = () => '' as V; // Unused because toolbar does not support selection. + readonly selectable = () => true; // Unused because toolbar does not support selection. + readonly element = () => undefined; // Unused because toolbar does not focus the group element. + + constructor(readonly inputs: ToolbarWidgetGroupInputs) {} +} diff --git a/src/aria/ui-patterns/toolbar/toolbar-widget.ts b/src/aria/private/toolbar/toolbar-widget.ts similarity index 51% rename from src/aria/ui-patterns/toolbar/toolbar-widget.ts rename to src/aria/private/toolbar/toolbar-widget.ts index e86247481968..28cfbc9edfd4 100644 --- a/src/aria/ui-patterns/toolbar/toolbar-widget.ts +++ b/src/aria/private/toolbar/toolbar-widget.ts @@ -6,39 +6,47 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed} from '@angular/core'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; +import {SignalLike, computed} from '../behaviors/signal-like/signal-like'; import {ListItem} from '../behaviors/list/list'; import type {ToolbarPattern} from './toolbar'; +import {ToolbarWidgetGroupPattern} from './toolbar-widget-group'; /** Represents the required inputs for a toolbar widget in a toolbar. */ -export interface ToolbarWidgetInputs - extends Omit, 'searchTerm' | 'value' | 'index' | 'selectable'> { +export interface ToolbarWidgetInputs extends Omit< + ListItem, + 'searchTerm' | 'index' | 'selectable' +> { /** A reference to the parent toolbar. */ toolbar: SignalLike>; + + /** A reference to the parent widget group. */ + group: SignalLike, V> | undefined>; } export class ToolbarWidgetPattern implements ListItem { /** A unique identifier for the widget. */ - readonly id: SignalLike; + readonly id = () => this.inputs.id(); /** The html element that should receive focus. */ - readonly element: SignalLike; + readonly element = () => this.inputs.element(); /** Whether the widget is disabled. */ - readonly disabled: SignalLike; + readonly disabled = () => this.inputs.disabled() || this.group()?.disabled() || false; /** A reference to the parent toolbar. */ - readonly toolbar: SignalLike>; + readonly group = () => this.inputs.group(); + + /** A reference to the toolbar containing the widget. */ + readonly toolbar = () => this.inputs.toolbar(); - /** The tabindex of the widgdet. */ - readonly tabindex = computed(() => this.toolbar().listBehavior.getItemTabindex(this)); + /** The tabindex of the widget. */ + readonly tabIndex = computed(() => this.toolbar().listBehavior.getItemTabindex(this)); /** The text used by the typeahead search. */ readonly searchTerm = () => ''; // Unused because toolbar does not support typeahead. /** The value associated with the widget. */ - readonly value = () => '' as V; // Unused because toolbar does not support selection. + readonly value = () => this.inputs.value(); /** Whether the widget is selectable. */ readonly selectable = () => true; // Unused because toolbar does not support selection. @@ -46,13 +54,13 @@ export class ToolbarWidgetPattern implements ListItem { /** The position of the widget within the toolbar. */ readonly index = computed(() => this.toolbar().inputs.items().indexOf(this) ?? -1); + /** Whether the widget is selected (only relevant in a selection group). */ + readonly selected = computed(() => + this.toolbar().listBehavior.inputs.values().includes(this.value()), + ); + /** Whether the widget is currently the active one (focused). */ - readonly active = computed(() => this.toolbar().inputs.activeItem() === this); - - constructor(readonly inputs: ToolbarWidgetInputs) { - this.id = inputs.id; - this.element = inputs.element; - this.disabled = inputs.disabled; - this.toolbar = inputs.toolbar; - } + readonly active: SignalLike = computed(() => this.toolbar().activeItem() === this); + + constructor(readonly inputs: ToolbarWidgetInputs) {} } diff --git a/src/aria/private/toolbar/toolbar.spec.ts b/src/aria/private/toolbar/toolbar.spec.ts new file mode 100644 index 000000000000..318ec4bb3af5 --- /dev/null +++ b/src/aria/private/toolbar/toolbar.spec.ts @@ -0,0 +1,1374 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {ToolbarInputs, ToolbarPattern} from './toolbar'; +import {ToolbarWidgetPattern} from './toolbar-widget'; +import {ToolbarWidgetGroupPattern} from './toolbar-widget-group'; +import {createKeyboardEvent} from '@angular/cdk/testing/private'; +import { + SignalLike, + computed, + signal, + WritableSignalLike, +} from '../behaviors/signal-like/signal-like'; +import {ModifierKeys} from '@angular/cdk/testing'; + +// Test types +type TestWidget = ToolbarWidgetPattern & { + inputs: {disabled: WritableSignalLike}; +}; + +type TestWidgetGroup = ToolbarWidgetGroupPattern, string> & { + disabled: WritableSignalLike; + items: WritableSignalLike; +}; + +type TestItem = TestWidget; + +type TestInputs = { + readonly [K in keyof ToolbarInputs]: WritableSignalLike< + ToolbarInputs[K] extends SignalLike ? T : never + >; +}; + +// Keyboard event helpers +const up = () => createKeyboardEvent('keydown', 38, 'ArrowUp'); +const down = () => createKeyboardEvent('keydown', 40, 'ArrowDown'); +const home = () => createKeyboardEvent('keydown', 36, 'Home'); +const end = () => createKeyboardEvent('keydown', 35, 'End'); +const enter = () => createKeyboardEvent('keydown', 13, 'Enter'); +const right = () => createKeyboardEvent('keydown', 39, 'ArrowRight'); +const left = () => createKeyboardEvent('keydown', 37, 'ArrowLeft'); +const space = () => createKeyboardEvent('keydown', 32, ' '); + +function clickItem(item: ToolbarWidgetPattern, mods?: ModifierKeys) { + return { + target: item.element(), + shiftKey: mods?.shift, + ctrlKey: mods?.control, + } as unknown as PointerEvent; +} + +function getToolbarPattern( + inputs: Partial<{ + [K in keyof TestInputs]: TestInputs[K] extends WritableSignalLike ? T : never; + }>, + items: WritableSignalLike, +) { + const element = signal(document.createElement('div')); + const activeItem = signal(undefined); + + const allItems = computed(() => { + const flatItems: ToolbarWidgetPattern[] = []; + for (const item of items()) { + if (item instanceof ToolbarWidgetGroupPattern) { + flatItems.push(...item.inputs.items()); + } else { + flatItems.push(item); + } + } + return flatItems; + }); + + const toolbar = new ToolbarPattern({ + element, + items, + activeItem, + values: signal([]), + wrap: signal(inputs.wrap ?? true), + disabled: signal(inputs.disabled ?? false), + softDisabled: signal(inputs.softDisabled ?? true), + textDirection: signal(inputs.textDirection ?? 'ltr'), + orientation: signal(inputs.orientation ?? 'horizontal'), + getItem: (e: Element) => allItems().find(i => i.element() === e), + }); + + return {toolbar, element, activeItem}; +} + +function getWidgetPattern( + value: string, + toolbar: ToolbarPattern, + group?: ToolbarWidgetGroupPattern, string>, +): TestWidget { + const element = signal(document.createElement('button')); + const widget = new ToolbarWidgetPattern({ + id: signal(`widget-${value}`), + element, + disabled: signal(false), + value: signal(value), + group: signal(group), + toolbar: signal(toolbar), + }); + return widget as TestWidget; +} + +function getWidgetGroupPattern(id: string, toolbar: ToolbarPattern): TestWidgetGroup { + const disabled = signal(false); + const items = signal([]); + + const group = new ToolbarWidgetGroupPattern, string>({ + disabled, + toolbar: signal(toolbar), + items, + multi: signal(false), + }); + + (group as TestWidgetGroup).disabled = disabled; + (group as TestWidgetGroup).items = items; + return group as TestWidgetGroup; +} + +function getPatterns( + inputs: Partial<{ + [K in keyof TestInputs]: TestInputs[K] extends WritableSignalLike ? T : never; + }> = {}, +) { + const items = signal([]); + const {toolbar} = getToolbarPattern(inputs, items); + + const group0 = getWidgetGroupPattern('group 0', toolbar); + const group1 = getWidgetGroupPattern('group 1', toolbar); + + items.set([ + getWidgetPattern('item 0', toolbar), + getWidgetPattern('item 1', toolbar), + getWidgetPattern('item 2', toolbar, group0), + getWidgetPattern('item 3', toolbar, group0), + getWidgetPattern('item 4', toolbar, group0), + getWidgetPattern('item 5', toolbar), + getWidgetPattern('item 6', toolbar, group1), + getWidgetPattern('item 7', toolbar, group1), + getWidgetPattern('item 8', toolbar, group1), + ]); + + // [ [ group 0 ] [ group 1 ]] + // [item 0, item 1, [item 2, item 3, item 4], item 5, [item 6, item 7, item 8]] + + (group0.inputs.items as WritableSignalLike).set(items().slice(2, 5) as TestWidget[]); + (group1.inputs.items as WritableSignalLike).set(items().slice(6, 9) as TestWidget[]); + + toolbar.setDefaultState(); + return {toolbar, items: items(), group0, group1}; +} + +describe('Toolbar Pattern', () => { + function getItem(toolbar: ToolbarPattern, value: string) { + return toolbar.inputs.items().find(item => item.value() === value)!; + } + + describe('Navigation', () => { + describe('with horizontal orientation', () => { + it('should navigate on click', () => { + const {toolbar} = getPatterns(); + const item5 = getItem(toolbar, 'item 5'); + toolbar.onClick(clickItem(item5)); + expect(toolbar.activeItem()?.value()).toBe('item 5'); + }); + + describe('with ltr text direction', () => { + it('should navigate next on ArrowRight', () => { + const {toolbar} = getPatterns(); + toolbar.onKeydown(right()); // Item 0 -> Item 1 + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate prev on ArrowLeft', () => { + const {toolbar} = getPatterns(); + toolbar.onKeydown(right()); // Item 0 -> Item 1 + toolbar.onKeydown(left()); // Item 1 -> Item 0 + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should not navigate next on ArrowDown when not in a widget group', () => { + const {toolbar} = getPatterns(); + toolbar.onKeydown(down()); // Item 0 -> Item 0 + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should not navigate prev on ArrowUp when not in a widget group', () => { + const {toolbar} = getPatterns(); + toolbar.onKeydown(right()); // Item 0 -> Item 1 + toolbar.onKeydown(up()); // Item 1 -> Item 1 + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate next in a widget group on ArrowDown', () => { + const {toolbar} = getPatterns(); + + toolbar.onKeydown(right()); // Item 0 -> Item 1 + toolbar.onKeydown(right()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(down()); // Item 2 -> Item 3 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 3'); + }); + + it('should navigate prev in a widget group on ArrowUp', () => { + const {toolbar} = getPatterns(); + + toolbar.onKeydown(right()); // Item 0 -> Item 1 + toolbar.onKeydown(right()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(down()); // Item 2 -> Item 3 (Group 0) + toolbar.onKeydown(up()); // Item 3 -> Item 2 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 2'); + }); + + it('should navigate last to first in a widget group on ArrowDown', () => { + const {toolbar} = getPatterns(); + + toolbar.onKeydown(right()); // Item 0 -> Item 1 + toolbar.onKeydown(right()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(down()); // Item 2 -> Item 3 (Group 0) + toolbar.onKeydown(down()); // Item 3 -> Item 4 (Group 0) + toolbar.onKeydown(down()); // Item 4 -> Item 2 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 2'); + }); + + it('should navigate first to last in a widget group on ArrowUp', () => { + const {toolbar} = getPatterns(); + + toolbar.onKeydown(right()); // Item 0 -> Item 1 + toolbar.onKeydown(right()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(up()); // Item 2 -> Item 4 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 4'); + }); + + describe('with wrap false', () => { + it('should not wrap from last to first', () => { + const {toolbar} = getPatterns({wrap: false}); + toolbar.onKeydown(end()); + toolbar.onKeydown(right()); + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should not wrap from first to last', () => { + const {toolbar} = getPatterns({wrap: false}); + toolbar.onKeydown(left()); + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + }); + + describe('with softDisabled true', () => { + it('should not skip disabled items when navigating next', () => { + const {toolbar, items} = getPatterns({softDisabled: true}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(right()); // Item 0 -> Item 1 (disabled) + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should not skip disabled items when navigating prev', () => { + const {toolbar, items} = getPatterns({softDisabled: true}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(right()); // Item 0 -> Item 1 (disabled) + toolbar.onKeydown(right()); // Item 1 -> Item 2 + toolbar.onKeydown(left()); // Item 2 -> Item 1 (disabled) + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should not skip disabled groups when navigating next', () => { + const {toolbar, group0} = getPatterns({softDisabled: true}); + group0.disabled.set(true); + + toolbar.onKeydown(right()); // Item 0 -> Item 1 + toolbar.onKeydown(right()); // Item 1 -> Item 2 + expect(toolbar.activeItem()?.value()).toBe('item 2'); + }); + + it('should not skip disabled groups when navigating prev', () => { + const {toolbar, group0} = getPatterns({softDisabled: true}); + group0.disabled.set(true); + toolbar.onKeydown(left()); // Item 0 -> Item 8 + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should navigate to the last item on End', () => { + const {toolbar, items} = getPatterns({softDisabled: true}); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should navigate to the first item on Home', () => { + const {toolbar, items} = getPatterns({softDisabled: true}); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); // Item 0 -> Item 8 + toolbar.onKeydown(home()); // Item 8 -> Item 0 + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + describe('with wrap true', () => { + it('should wrap from last to first', () => { + const {toolbar, items} = getPatterns({softDisabled: true, wrap: true}); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(right()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should wrap from first to last', () => { + const {toolbar, items} = getPatterns({softDisabled: true, wrap: true}); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(left()); + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + }); + }); + + describe('with softDisabled false', () => { + it('should not navigate to disabled items on click', () => { + const {toolbar, items} = getPatterns({softDisabled: false}); + items[1].inputs.disabled.set(true); + + toolbar.onClick(clickItem(items[1])); + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should skip disabled items when navigating next', () => { + const {toolbar, items} = getPatterns({softDisabled: false}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(right()); // Item 0 -> Item 2 (skips Item 1) + expect(toolbar.activeItem()?.value()).toBe('item 2'); + }); + + it('should skip disabled items when navigating prev', () => { + const {toolbar, items} = getPatterns({softDisabled: false}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(right()); // Item 0 -> Item 2 + toolbar.onKeydown(left()); // Item 2 -> Item 0 (skips Item 1) + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should not navigate to items in disabled groups on click', () => { + const {toolbar, group0} = getPatterns({softDisabled: false}); + group0.disabled.set(true); + const item2 = getItem(toolbar, 'item 2'); + toolbar.onClick(clickItem(item2)); + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should skip disabled groups when navigating next', () => { + const {toolbar, group0} = getPatterns({softDisabled: false}); + group0.disabled.set(true); + + toolbar.onKeydown(right()); // Item 0 -> Item 1 + toolbar.onKeydown(right()); // Item 1 -> Item 5 (skips Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 5'); + }); + + it('should skip disabled groups when navigating prev', () => { + const {toolbar, group0, group1} = getPatterns({softDisabled: false}); + group0.disabled.set(true); + group1.disabled.set(true); + + toolbar.onKeydown(left()); // Item 0 -> Item 5 (skips Group 1) + toolbar.onKeydown(left()); // Item 5 -> Item 1 (skips Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate to the last focusable item on End', () => { + const {toolbar, items} = getPatterns({softDisabled: false}); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + expect(toolbar.activeItem()?.value()).toBe('item 7'); + }); + + it('should navigate to the first focusable item on Home', () => { + const {toolbar, items} = getPatterns({softDisabled: false}); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(home()); + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + describe('with wrap true', () => { + it('should wrap from last to first focusable item', () => { + const {toolbar, items} = getPatterns({softDisabled: false, wrap: true}); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(right()); + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should wrap from first to last focusable item', () => { + const {toolbar, items} = getPatterns({softDisabled: false, wrap: true}); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(home()); + toolbar.onKeydown(left()); + + expect(toolbar.activeItem()?.value()).toBe('item 7'); + }); + }); + + describe('with wrap false', () => { + it('should not wrap from last to first focusable item', () => { + const {toolbar, items} = getPatterns({softDisabled: false, wrap: false}); + items[items.length - 1].inputs.disabled.set(true); + toolbar.onKeydown(end()); + toolbar.onKeydown(right()); + + expect(toolbar.activeItem()?.value()).toBe('item 7'); + }); + + it('should not wrap from first to last focusable item', () => { + const {toolbar, items} = getPatterns({softDisabled: false, wrap: false}); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(home()); + toolbar.onKeydown(left()); + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + }); + }); + }); + + describe('with rtl text direction', () => { + it('should navigate on click', () => { + const {toolbar} = getPatterns({textDirection: 'rtl'}); + const item5 = getItem(toolbar, 'item 5'); + toolbar.onClick(clickItem(item5)); + expect(toolbar.activeItem()?.value()).toBe('item 5'); + }); + + it('should navigate next on ArrowLeft', () => { + const {toolbar} = getPatterns({textDirection: 'rtl'}); + toolbar.onKeydown(left()); // Item 0 -> Item 1 + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate prev on ArrowRight', () => { + const {toolbar} = getPatterns({textDirection: 'rtl'}); + toolbar.onKeydown(left()); // Item 0 -> Item 1 + toolbar.onKeydown(right()); // Item 1 -> Item 0 + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should not navigate next on ArrowDown when not in a widget group', () => { + const {toolbar} = getPatterns({textDirection: 'rtl'}); + toolbar.onKeydown(up()); // Item 0 -> Item 0 + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should not navigate prev on ArrowUp when not in a widget group', () => { + const {toolbar} = getPatterns({textDirection: 'rtl'}); + toolbar.onKeydown(left()); // Item 0 -> Item 1 + toolbar.onKeydown(down()); // Item 1 -> Item 1 + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate next in a widget group on ArrowDown', () => { + const {toolbar} = getPatterns({textDirection: 'rtl'}); + + toolbar.onKeydown(left()); // Item 0 -> Item 1 + toolbar.onKeydown(left()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(down()); // Item 2 -> Item 3 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 3'); + }); + + it('should navigate prev in a widget group on ArrowUp', () => { + const {toolbar} = getPatterns({textDirection: 'rtl'}); + + toolbar.onKeydown(left()); // Item 0 -> Item 1 + toolbar.onKeydown(left()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(down()); // Item 2 -> Item 3 (Group 0) + toolbar.onKeydown(up()); // Item 3 -> Item 2 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 2'); + }); + + it('should navigate first to last in a widget group on ArrowUp', () => { + const {toolbar} = getPatterns({textDirection: 'rtl'}); + + toolbar.onKeydown(left()); // Item 0 -> Item 1 + toolbar.onKeydown(left()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(up()); // Item 2 -> Item 4 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 4'); + }); + + it('should navigate last to first in a widget group on ArrowDown', () => { + const {toolbar} = getPatterns({textDirection: 'rtl'}); + + toolbar.onKeydown(left()); // Item 0 -> Item 1 + toolbar.onKeydown(left()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(down()); // Item 2 -> Item 3 (Group 0) + toolbar.onKeydown(down()); // Item 3 -> Item 4 (Group 0) + toolbar.onKeydown(down()); // Item 4 -> Item 2 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 2'); + }); + + describe('with softDisabled true', () => { + it('should not skip disabled items when navigating next', () => { + const {toolbar, items} = getPatterns({softDisabled: true, textDirection: 'rtl'}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(left()); // Item 0 -> Item 1 (disabled) + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should not skip disabled items when navigating prev', () => { + const {toolbar, items} = getPatterns({softDisabled: true, textDirection: 'rtl'}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(left()); // Item 0 -> Item 1 (disabled) + toolbar.onKeydown(left()); // Item 1 -> Item 2 + toolbar.onKeydown(right()); // Item 2 -> Item 1 (disabled) + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate to the last item on End', () => { + const {toolbar, items} = getPatterns({softDisabled: true, textDirection: 'rtl'}); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should navigate to the first item on Home', () => { + const {toolbar, items} = getPatterns({softDisabled: true, textDirection: 'rtl'}); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(left()); // Item 0 -> Item 1 + toolbar.onKeydown(home()); // Item 1 -> Item 0 + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + describe('with wrap true', () => { + it('should wrap from last to first', () => { + const {toolbar, items} = getPatterns({ + wrap: true, + softDisabled: true, + textDirection: 'rtl', + }); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(left()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should wrap from first to last', () => { + const {toolbar, items} = getPatterns({ + wrap: true, + softDisabled: true, + textDirection: 'rtl', + }); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(right()); + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + }); + + describe('with wrap false', () => { + it('should not wrap from last to first', () => { + const {toolbar} = getPatterns({ + wrap: false, + softDisabled: true, + textDirection: 'rtl', + }); + toolbar.onKeydown(end()); + toolbar.onKeydown(left()); + + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should not wrap from first to last', () => { + const {toolbar} = getPatterns({ + wrap: false, + softDisabled: true, + textDirection: 'rtl', + }); + toolbar.onKeydown(home()); + toolbar.onKeydown(right()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + }); + }); + + describe('with softDisabled false', () => { + it('should skip disabled items when navigating next', () => { + const {toolbar, items} = getPatterns({softDisabled: false, textDirection: 'rtl'}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(left()); // Item 0 -> Item 2 (skips Item 1) + expect(toolbar.activeItem()?.value()).toBe('item 2'); + }); + + it('should skip disabled items when navigating prev', () => { + const {toolbar, items} = getPatterns({softDisabled: false, textDirection: 'rtl'}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(left()); // Item 0 -> Item 2 + toolbar.onKeydown(right()); // Item 2 -> Item 0 (skips Item 1) + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should navigate to the last focusable item on End', () => { + const {toolbar, items} = getPatterns({softDisabled: false, textDirection: 'rtl'}); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + expect(toolbar.activeItem()?.value()).toBe('item 7'); + }); + + it('should navigate to the first focusable item on Home', () => { + const {toolbar, items} = getPatterns({softDisabled: false, textDirection: 'rtl'}); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(home()); + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + describe('with wrap true', () => { + it('should wrap from last to first focusable item', () => { + const {toolbar, items} = getPatterns({ + softDisabled: false, + wrap: true, + textDirection: 'rtl', + }); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(left()); + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should wrap from first to last focusable item', () => { + const {toolbar, items} = getPatterns({ + softDisabled: false, + wrap: true, + textDirection: 'rtl', + }); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(home()); + toolbar.onKeydown(right()); + + expect(toolbar.activeItem()?.value()).toBe('item 7'); + }); + }); + + describe('with wrap false', () => { + it('should not wrap from last to first focusable item', () => { + const {toolbar} = getPatterns({ + softDisabled: false, + wrap: false, + textDirection: 'rtl', + }); + toolbar.onKeydown(end()); + toolbar.onKeydown(left()); + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should not wrap from first to last focusable item', () => { + const {toolbar, items} = getPatterns({ + softDisabled: false, + wrap: false, + textDirection: 'rtl', + }); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(home()); + toolbar.onKeydown(right()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + }); + }); + }); + }); + + describe('with vertical orientation', () => { + describe('with ltr text direction', () => { + it('should navigate next on ArrowDown', () => { + const {toolbar} = getPatterns({orientation: 'vertical'}); + toolbar.onKeydown(down()); // Item 0 -> Item 1 + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate prev on ArrowUp', () => { + const {toolbar} = getPatterns({orientation: 'vertical'}); + toolbar.onKeydown(down()); // Item 0 -> Item 1 + toolbar.onKeydown(up()); // Item 1 -> Item 0 + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should not navigate next on ArrowRight when not in a widget group', () => { + const {toolbar} = getPatterns({orientation: 'vertical'}); + toolbar.onKeydown(right()); // Item 0 -> Item 0 + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should not navigate prev on ArrowLeft when not in a widget group', () => { + const {toolbar} = getPatterns({orientation: 'vertical'}); + toolbar.onKeydown(down()); // Item 0 -> Item 1 + toolbar.onKeydown(left()); // Item 1 -> Item 1 + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate next in a widget group on ArrowRight', () => { + const {toolbar} = getPatterns({orientation: 'vertical'}); + + toolbar.onKeydown(down()); + toolbar.onKeydown(down()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(right()); // Item 2 -> Item 3 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 3'); + }); + + it('should navigate prev in a widget group on ArrowLeft', () => { + const {toolbar} = getPatterns({orientation: 'vertical'}); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 + toolbar.onKeydown(down()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(right()); // Item 2 -> Item 3 (Group 0) + toolbar.onKeydown(left()); // Item 3 -> Item 2 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 2'); + }); + + it('should navigate last to first in a widget group on ArrowRight', () => { + const {toolbar} = getPatterns({orientation: 'vertical'}); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 + toolbar.onKeydown(down()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(right()); // Item 2 -> Item 3 (Group 0) + toolbar.onKeydown(right()); // Item 3 -> Item 4 (Group 0) + toolbar.onKeydown(right()); // Item 4 -> Item 2 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 2'); + }); + + it('should navigate first to last in a widget group on ArrowLeft', () => { + const {toolbar} = getPatterns({orientation: 'vertical'}); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 + toolbar.onKeydown(down()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(left()); // Item 2 -> Item 4 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 4'); + }); + + describe('with softDisabled true', () => { + it('should not skip disabled items when navigating next', () => { + const {toolbar, items} = getPatterns({softDisabled: true, orientation: 'vertical'}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 (disabled) + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should not skip disabled items when navigating prev', () => { + const {toolbar, items} = getPatterns({softDisabled: true, orientation: 'vertical'}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 (disabled) + toolbar.onKeydown(down()); // Item 1 -> Item 2 + toolbar.onKeydown(up()); // Item 2 -> Item 1 (disabled) + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate to the last item on End', () => { + const {toolbar, items} = getPatterns({softDisabled: true, orientation: 'vertical'}); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should navigate to the first item on Home', () => { + const {toolbar, items} = getPatterns({softDisabled: true, orientation: 'vertical'}); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 + toolbar.onKeydown(home()); // Item 1 -> Item 0 + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + describe('with wrap true', () => { + it('should wrap from last to first', () => { + const {toolbar, items} = getPatterns({ + softDisabled: true, + wrap: true, + orientation: 'vertical', + }); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(down()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should wrap from first to last', () => { + const {toolbar, items} = getPatterns({ + softDisabled: true, + wrap: true, + orientation: 'vertical', + }); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(home()); + toolbar.onKeydown(up()); + + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + }); + + describe('with wrap false', () => { + it('should not wrap from last to first', () => { + const {toolbar} = getPatterns({ + softDisabled: true, + wrap: false, + orientation: 'vertical', + }); + toolbar.onKeydown(end()); + toolbar.onKeydown(down()); + + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should not wrap from first to last', () => { + const {toolbar} = getPatterns({ + softDisabled: true, + wrap: false, + orientation: 'vertical', + }); + toolbar.onKeydown(home()); + toolbar.onKeydown(up()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + }); + }); + + describe('with softDisabled false', () => { + it('should skip disabled items when navigating next', () => { + const {toolbar, items} = getPatterns({softDisabled: false, orientation: 'vertical'}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(down()); // Item 0 -> Item 2 (skips Item 1) + + expect(toolbar.activeItem()).toBe(items[2]); + }); + + it('should skip disabled items when navigating prev', () => { + const {toolbar, items} = getPatterns({softDisabled: false, orientation: 'vertical'}); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(down()); // Item 0 -> Item 2 + toolbar.onKeydown(up()); // Item 2 -> Item 0 (skips Item 1) + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should navigate to the last focusable item on End', () => { + const {toolbar, items} = getPatterns({softDisabled: false, orientation: 'vertical'}); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + expect(toolbar.activeItem()?.value()).toBe('item 7'); + }); + + it('should navigate to the first focusable item on Home', () => { + const {toolbar, items} = getPatterns({softDisabled: false, orientation: 'vertical'}); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(home()); + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + describe('with wrap true', () => { + it('should wrap from last to first focusable item', () => { + const {toolbar, items} = getPatterns({ + softDisabled: false, + wrap: true, + orientation: 'vertical', + }); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(down()); + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should wrap from first to last focusable item', () => { + const {toolbar, items} = getPatterns({ + softDisabled: false, + wrap: true, + orientation: 'vertical', + }); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(home()); + toolbar.onKeydown(up()); + + expect(toolbar.activeItem()?.value()).toBe('item 7'); + }); + }); + + describe('with wrap false', () => { + it('should not wrap from last to first focusable item', () => { + const {toolbar} = getPatterns({ + softDisabled: false, + wrap: false, + orientation: 'vertical', + }); + toolbar.onKeydown(end()); + toolbar.onKeydown(down()); + + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should not wrap from first to last focusable item', () => { + const {toolbar, items} = getPatterns({ + softDisabled: false, + wrap: false, + orientation: 'vertical', + }); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(home()); + toolbar.onKeydown(up()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + }); + }); + }); + + describe('with rtl text direction', () => { + it('should navigate next on ArrowDown', () => { + const {toolbar} = getPatterns({orientation: 'vertical', textDirection: 'rtl'}); + toolbar.onKeydown(down()); // Item 0 -> Item 1 + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate prev on ArrowUp', () => { + const {toolbar} = getPatterns({orientation: 'vertical', textDirection: 'rtl'}); + toolbar.onKeydown(down()); // Item 0 -> Item 1 + toolbar.onKeydown(up()); // Item 1 -> Item 0 + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should navigate last to first in a widget group on ArrowLeft', () => { + const {toolbar} = getPatterns({orientation: 'vertical', textDirection: 'rtl'}); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 + toolbar.onKeydown(down()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(left()); // Item 2 -> Item 3 (Group 0) + toolbar.onKeydown(left()); // Item 3 -> Item 4 (Group 0) + toolbar.onKeydown(left()); // Item 4 -> Item 2 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 2'); + }); + + it('should navigate first to last in a widget group on ArrowRight', () => { + const {toolbar} = getPatterns({orientation: 'vertical', textDirection: 'rtl'}); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 + toolbar.onKeydown(down()); // Item 1 -> Item 2 (Group 0) + toolbar.onKeydown(right()); // Item 2 -> Item 4 (Group 0) + + expect(toolbar.activeItem()?.value()).toBe('item 4'); + }); + + describe('with softDisabled true', () => { + it('should not skip disabled items when navigating next', () => { + const {toolbar, items} = getPatterns({ + softDisabled: true, + orientation: 'vertical', + textDirection: 'rtl', + }); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 (disabled) + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should not skip disabled items when navigating prev', () => { + const {toolbar, items} = getPatterns({ + softDisabled: true, + orientation: 'vertical', + textDirection: 'rtl', + }); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 (disabled) + toolbar.onKeydown(down()); // Item 1 -> Item 2 + toolbar.onKeydown(up()); // Item 2 -> Item 1 (disabled) + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should navigate to the last item on End', () => { + const {toolbar, items} = getPatterns({ + softDisabled: true, + orientation: 'vertical', + textDirection: 'rtl', + }); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should navigate to the first item on Home', () => { + const {toolbar, items} = getPatterns({ + softDisabled: true, + orientation: 'vertical', + textDirection: 'rtl', + }); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(down()); // Item 0 -> Item 1 + toolbar.onKeydown(home()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + describe('with wrap true', () => { + it('should wrap from last to first', () => { + const {toolbar, items} = getPatterns({ + softDisabled: true, + wrap: true, + orientation: 'vertical', + textDirection: 'rtl', + }); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(down()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should wrap from first to last', () => { + const {toolbar, items} = getPatterns({ + softDisabled: true, + wrap: true, + orientation: 'vertical', + textDirection: 'rtl', + }); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(home()); + toolbar.onKeydown(up()); + + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + }); + + describe('with wrap false', () => { + it('should not wrap from last to first', () => { + const {toolbar} = getPatterns({ + softDisabled: true, + wrap: false, + orientation: 'vertical', + textDirection: 'rtl', + }); + toolbar.onKeydown(end()); + toolbar.onKeydown(down()); + + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should not wrap from first to last', () => { + const {toolbar} = getPatterns({ + softDisabled: true, + wrap: false, + orientation: 'vertical', + textDirection: 'rtl', + }); + toolbar.onKeydown(home()); + toolbar.onKeydown(up()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + }); + }); + + describe('with softDisabled false', () => { + it('should skip disabled items when navigating next', () => { + const {toolbar, items} = getPatterns({ + softDisabled: false, + orientation: 'vertical', + textDirection: 'rtl', + }); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(down()); // Item 0 -> Item 2 (skips Item 1) + + expect(toolbar.activeItem()).toBe(items[2]); + }); + + it('should skip disabled items when navigating prev', () => { + const {toolbar, items} = getPatterns({ + softDisabled: false, + orientation: 'vertical', + textDirection: 'rtl', + }); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(down()); // Item 0 -> Item 2 + toolbar.onKeydown(up()); // Item 2 -> Item 0 (skips Item 1) + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + + it('should navigate to the last focusable item on End', () => { + const {toolbar, items} = getPatterns({ + softDisabled: false, + orientation: 'vertical', + textDirection: 'rtl', + }); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + expect(toolbar.activeItem()).toBe(items[items.length - 2]); + }); + + it('should navigate to the first focusable item on Home', () => { + const {toolbar, items} = getPatterns({ + softDisabled: false, + textDirection: 'rtl', + orientation: 'vertical', + }); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(home()); + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + describe('with wrap true', () => { + it('should wrap from last to first focusable item', () => { + const {toolbar, items} = getPatterns({ + wrap: true, + softDisabled: false, + textDirection: 'rtl', + orientation: 'vertical', + }); + items[0].inputs.disabled.set(true); + + toolbar.onKeydown(end()); + toolbar.onKeydown(down()); + + expect(toolbar.activeItem()?.value()).toBe('item 1'); + }); + + it('should wrap from first to last focusable item', () => { + const {toolbar, items} = getPatterns({ + wrap: true, + softDisabled: false, + textDirection: 'rtl', + orientation: 'vertical', + }); + items[items.length - 1].inputs.disabled.set(true); + + toolbar.onKeydown(home()); + toolbar.onKeydown(up()); + + expect(toolbar.activeItem()).toBe(items[items.length - 2]); + }); + }); + + describe('with wrap false', () => { + it('should not wrap from last to first focusable item', () => { + const {toolbar} = getPatterns({ + wrap: false, + softDisabled: false, + textDirection: 'rtl', + orientation: 'vertical', + }); + toolbar.onKeydown(end()); + toolbar.onKeydown(down()); + + expect(toolbar.activeItem()?.value()).toBe('item 8'); + }); + + it('should not wrap from first to last focusable item', () => { + const {toolbar, items} = getPatterns({ + wrap: false, + softDisabled: false, + textDirection: 'rtl', + orientation: 'vertical', + }); + items[1].inputs.disabled.set(true); + + toolbar.onKeydown(home()); + toolbar.onKeydown(up()); + + expect(toolbar.activeItem()?.value()).toBe('item 0'); + }); + }); + }); + }); + }); + + describe('with disabled toolbar', () => { + it('should not navigate on any key press', () => { + const {toolbar} = getPatterns({disabled: true}); + const initialActiveItem = toolbar.activeItem(); + + toolbar.onKeydown(right()); + expect(toolbar.activeItem()).toBe(initialActiveItem); + + toolbar.onKeydown(left()); + expect(toolbar.activeItem()).toBe(initialActiveItem); + + toolbar.onKeydown(up()); + expect(toolbar.activeItem()).toBe(initialActiveItem); + + toolbar.onKeydown(down()); + expect(toolbar.activeItem()).toBe(initialActiveItem); + + toolbar.onKeydown(home()); + expect(toolbar.activeItem()).toBe(initialActiveItem); + + toolbar.onKeydown(end()); + expect(toolbar.activeItem()).toBe(initialActiveItem); + }); + }); + }); + + describe('Selection', () => { + it('should toggle the active item on Enter', () => { + const {toolbar} = getPatterns(); + expect(getItem(toolbar, 'item 0').selected()).toBeFalse(); + toolbar.onKeydown(enter()); + expect(getItem(toolbar, 'item 0').selected()).toBeTrue(); + toolbar.onKeydown(enter()); + expect(getItem(toolbar, 'item 0').selected()).toBeFalse(); + }); + + it('should toggle the active item on Space', () => { + const {toolbar} = getPatterns(); + expect(getItem(toolbar, 'item 0').selected()).toBeFalse(); + toolbar.onKeydown(space()); + expect(getItem(toolbar, 'item 0').selected()).toBeTrue(); + toolbar.onKeydown(space()); + expect(getItem(toolbar, 'item 0').selected()).toBeFalse(); + }); + + it('should toggle the active item on click', () => { + const {toolbar, items} = getPatterns(); + expect(getItem(toolbar, 'item 0').selected()).toBeFalse(); + toolbar.onClick(clickItem(items[0])); + expect(getItem(toolbar, 'item 0').selected()).toBeTrue(); + toolbar.onClick(clickItem(items[0])); + expect(getItem(toolbar, 'item 0').selected()).toBeFalse(); + }); + + it('should be able to select multiple items in the toolbar', () => { + const {toolbar} = getPatterns(); + expect(getItem(toolbar, 'item 0').selected()).toBeFalse(); + expect(getItem(toolbar, 'item 1').selected()).toBeFalse(); + + // Select first item + toolbar.onKeydown(enter()); + expect(getItem(toolbar, 'item 0').selected()).toBeTrue(); + expect(getItem(toolbar, 'item 1').selected()).toBeFalse(); + + // Navigate to and select second item + toolbar.onKeydown(right()); + toolbar.onKeydown(space()); + expect(getItem(toolbar, 'item 0').selected()).toBeTrue(); + expect(getItem(toolbar, 'item 1').selected()).toBeTrue(); + }); + + it('should not be able to select multiple items in a group', () => { + const {toolbar} = getPatterns(); + expect(getItem(toolbar, 'item 2').selected()).toBeFalse(); + expect(getItem(toolbar, 'item 3').selected()).toBeFalse(); + + // Navigate to and select first item in group + toolbar.onKeydown(right()); + toolbar.onKeydown(right()); + toolbar.onKeydown(enter()); + expect(getItem(toolbar, 'item 2').selected()).toBeTrue(); + expect(getItem(toolbar, 'item 3').selected()).toBeFalse(); + + // Navigate to and select second item in group + toolbar.onKeydown(right()); + toolbar.onKeydown(enter()); + expect(getItem(toolbar, 'item 2').selected()).toBeFalse(); + expect(getItem(toolbar, 'item 3').selected()).toBeTrue(); + }); + + it('should not select disabled items', () => { + const {toolbar, items} = getPatterns(); + items[1].inputs.disabled.set(true); + + // Navigate to disabled item + toolbar.onKeydown(right()); + expect(toolbar.activeItem()?.value()).toBe('item 1'); + + // Try to select disabled item + toolbar.onKeydown(enter()); + expect(getItem(toolbar, 'item 1').selected()).toBeFalse(); + }); + + it('should not select items in a disabled group', () => { + const {toolbar, items, group0} = getPatterns(); + group0.disabled.set(true); + + toolbar.onClick(clickItem(items[2])); + expect(toolbar.activeItem()?.value()).toBe('item 2'); + expect(getItem(toolbar, 'item 2').selected()).toBeFalse(); + + toolbar.onKeydown(right()); + toolbar.onKeydown(enter()); + expect(toolbar.activeItem()?.value()).toBe('item 3'); + expect(getItem(toolbar, 'item 3').selected()).toBeFalse(); + }); + }); +}); diff --git a/src/aria/private/toolbar/toolbar.ts b/src/aria/private/toolbar/toolbar.ts new file mode 100644 index 000000000000..b39abaf06411 --- /dev/null +++ b/src/aria/private/toolbar/toolbar.ts @@ -0,0 +1,201 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {computed, SignalLike} from '../behaviors/signal-like/signal-like'; +import {KeyboardEventManager} from '../behaviors/event-manager'; +import {List, ListInputs} from '../behaviors/list/list'; +import {ToolbarWidgetPattern} from './toolbar-widget'; + +/** Represents the required inputs for a toolbar. */ +export type ToolbarInputs = Omit< + ListInputs, V>, + 'multi' | 'typeaheadDelay' | 'selectionMode' | 'focusMode' +> & { + /** A function that returns the toolbar item associated with a given element. */ + getItem: (e: Element) => ToolbarWidgetPattern | undefined; +}; + +/** Controls the state of a toolbar. */ +export class ToolbarPattern { + /** The list behavior for the toolbar. */ + readonly listBehavior: List, V>; + + /** Whether the tablist is vertically or horizontally oriented. */ + readonly orientation: SignalLike<'vertical' | 'horizontal'>; + + /** Whether disabled items in the group should be focusable. */ + readonly softDisabled: SignalLike; + + /** Whether the toolbar is disabled. */ + readonly disabled = computed(() => this.listBehavior.disabled()); + + /** The tab index of the toolbar (if using activedescendant). */ + readonly tabIndex = computed(() => this.listBehavior.tabIndex()); + + /** The id of the current active widget (if using activedescendant). */ + readonly activeDescendant = computed(() => this.listBehavior.activeDescendant()); + + /** The currently active item in the toolbar. */ + readonly activeItem = () => this.listBehavior.inputs.activeItem(); + + /** The key used to navigate to the previous widget. */ + private readonly _prevKey = computed(() => { + if (this.inputs.orientation() === 'vertical') { + return 'ArrowUp'; + } + return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; + }); + + /** The key used to navigate to the next widget. */ + private readonly _nextKey = computed(() => { + if (this.inputs.orientation() === 'vertical') { + return 'ArrowDown'; + } + return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; + }); + + /** The alternate key used to navigate to the previous widget. */ + private readonly _altPrevKey = computed(() => { + if (this.inputs.orientation() === 'vertical') { + return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; + } + return 'ArrowUp'; + }); + + /** The alternate key used to navigate to the next widget. */ + private readonly _altNextKey = computed(() => { + if (this.inputs.orientation() === 'vertical') { + return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; + } + return 'ArrowDown'; + }); + + /** The keydown event manager for the toolbar. */ + private readonly _keydown = computed(() => { + const manager = new KeyboardEventManager(); + + return manager + .on(this._nextKey, () => this.listBehavior.next()) + .on(this._prevKey, () => this.listBehavior.prev()) + .on(this._altNextKey, () => this._groupNext()) + .on(this._altPrevKey, () => this._groupPrev()) + .on(' ', () => this.select()) + .on('Enter', () => this.select()) + .on('Home', () => this.listBehavior.first()) + .on('End', () => this.listBehavior.last()); + }); + + /** Navigates to the next widget in a widget group. */ + private _groupNext() { + const currGroup = this.inputs.activeItem()?.group(); + const nextGroup = this.listBehavior.navigationBehavior.peekNext()?.group(); + + if (!currGroup) { + return; + } + + if (currGroup !== nextGroup) { + this.listBehavior.goto( + this.listBehavior.navigationBehavior.peekFirst(currGroup.inputs.items())!, + ); + + return; + } + + this.listBehavior.next(); + } + + /** Navigates to the previous widget in a widget group. */ + private _groupPrev() { + const currGroup = this.inputs.activeItem()?.group(); + const nextGroup = this.listBehavior.navigationBehavior.peekPrev()?.group(); + + if (!currGroup) { + return; + } + + if (currGroup !== nextGroup) { + this.listBehavior.goto( + this.listBehavior.navigationBehavior.peekLast(currGroup.inputs.items())!, + ); + + return; + } + + this.listBehavior.prev(); + } + + /** Navigates to the widget targeted by a pointer event. */ + private _goto(e: MouseEvent) { + const item = this.inputs.getItem(e.target as Element); + + if (item) { + this.listBehavior.goto(item); + this.select(); + } + } + + select() { + const group = this.inputs.activeItem()?.group(); + + if (!group?.multi()) { + group?.inputs.items().forEach(i => this.listBehavior.deselect(i)); + } + + this.listBehavior.toggle(); + } + + constructor(readonly inputs: ToolbarInputs) { + this.orientation = inputs.orientation; + this.softDisabled = inputs.softDisabled; + + this.listBehavior = new List({ + ...inputs, + multi: () => true, + focusMode: () => 'roving', + selectionMode: () => 'explicit', + typeaheadDelay: () => 0, // Toolbar widgets do not support typeahead. + }); + } + + /** Handles keydown events for the toolbar. */ + onKeydown(event: KeyboardEvent) { + if (this.disabled()) return; + this._keydown().handle(event); + } + + onPointerdown(event: PointerEvent) { + event.preventDefault(); + } + + /** Handles click events for the toolbar. */ + onClick(event: MouseEvent) { + if (this.disabled()) return; + this._goto(event); + } + + /** + * Sets the toolbar to its default initial state. + * + * Sets the active index to the selected widget if one exists and is focusable. + * Otherwise, sets the active index to the first focusable widget. + */ + setDefaultState() { + const firstItem = this.listBehavior.navigationBehavior.peekFirst(this.inputs.items()); + + if (firstItem) { + this.inputs.activeItem.set(firstItem); + } + } + + /** Validates the state of the toolbar and returns a list of accessibility violations. */ + validate(): string[] { + const violations: string[] = []; + return violations; + } +} diff --git a/src/aria/ui-patterns/tree/BUILD.bazel b/src/aria/private/tree/BUILD.bazel similarity index 66% rename from src/aria/ui-patterns/tree/BUILD.bazel rename to src/aria/private/tree/BUILD.bazel index 4d82175fc3bf..6f1779bf56d2 100644 --- a/src/aria/ui-patterns/tree/BUILD.bazel +++ b/src/aria/private/tree/BUILD.bazel @@ -10,11 +10,11 @@ ts_project( ], deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/event-manager", - "//src/aria/ui-patterns/behaviors/expansion", - "//src/aria/ui-patterns/behaviors/list", - "//src/aria/ui-patterns/behaviors/signal-like", - "//src/aria/ui-patterns/combobox", + "//src/aria/private/behaviors/event-manager", + "//src/aria/private/behaviors/expansion", + "//src/aria/private/behaviors/list", + "//src/aria/private/behaviors/signal-like", + "//src/aria/private/combobox", ], ) @@ -27,7 +27,7 @@ ng_project( deps = [ ":tree", "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", + "//src/aria/private/behaviors/signal-like", "//src/cdk/keycodes", "//src/cdk/testing/private", ], diff --git a/src/aria/ui-patterns/tree/combobox-tree.ts b/src/aria/private/tree/combobox-tree.ts similarity index 74% rename from src/aria/ui-patterns/tree/combobox-tree.ts rename to src/aria/private/tree/combobox-tree.ts index 70fed29206c3..ee45cd82fb51 100644 --- a/src/aria/ui-patterns/tree/combobox-tree.ts +++ b/src/aria/private/tree/combobox-tree.ts @@ -6,9 +6,8 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed} from '@angular/core'; import {TreeInputs, TreePattern, TreeItemPattern} from './tree'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; +import {computed, SignalLike} from '../behaviors/signal-like/signal-like'; import {ComboboxPattern, ComboboxTreeControls} from '../combobox/combobox'; export type ComboboxTreeInputs = TreeInputs & { @@ -27,13 +26,16 @@ export class ComboboxTreePattern role = () => 'tree' as const; /* The id of the active (focused) item in the tree. */ - activeId = computed(() => this.listBehavior.activedescendant()); + activeId = computed(() => this.listBehavior.activeDescendant()); + + /** Returns the currently active (focused) item in the tree. */ + getActiveItem = () => this.inputs.activeItem(); /** The list of items in the tree. */ items = computed(() => this.inputs.allItems()); - /** The tabindex for the tree. Always -1 because the combobox handles focus. */ - override tabindex: SignalLike<-1 | 0> = () => -1; + /** The tab index for the tree. Always -1 because the combobox handles focus. */ + override tabIndex: SignalLike<-1 | 0> = () => -1; constructor(override readonly inputs: ComboboxTreeInputs) { if (inputs.combobox()) { @@ -76,17 +78,20 @@ export class ComboboxTreePattern /** Selects the specified item in the tree or the current active item if not provided. */ select = (item?: TreeItemPattern) => this.listBehavior.select(item); + /** Toggles the selection state of the given item in the tree or the current active item if not provided. */ + toggle = (item?: TreeItemPattern) => this.listBehavior.toggle(item); + /** Clears the selection in the tree. */ clearSelection = () => this.listBehavior.deselectAll(); /** Retrieves the TreeItemPattern associated with a pointer event. */ getItem = (e: PointerEvent) => this._getItem(e); - /** Retrieves the currently selected item in the tree */ - getSelectedItem = () => this.inputs.allItems().find(i => i.selected()); + /** Retrieves the currently selected items in the tree */ + getSelectedItems = () => this.inputs.allItems().filter(item => item.selected()); /** Sets the value of the combobox tree. */ - setValue = (value: V | undefined) => this.inputs.value.set(value ? [value] : []); + setValue = (value: V | undefined) => this.inputs.values.set(value ? [value] : []); /** Expands the currently focused item if it is expandable. */ expandItem = () => this.expand(); @@ -100,8 +105,13 @@ export class ComboboxTreePattern } /** Expands all of the tree items. */ - expandAll = () => this.items().forEach(item => item.expansion.open()); + expandAll = () => this.items().forEach(item => this.expansionBehavior.open(item)); /** Collapses all of the tree items. */ - collapseAll = () => this.items().forEach(item => item.expansion.close()); + collapseAll = () => this.items().forEach(item => item.expansionBehavior.close(item)); + + /** Whether the currently active item is selectable. */ + isItemSelectable = (item: TreeItemPattern | undefined = this.inputs.activeItem()) => { + return item ? item.selectable() : false; + }; } diff --git a/src/aria/ui-patterns/tree/tree.spec.ts b/src/aria/private/tree/tree.spec.ts similarity index 76% rename from src/aria/ui-patterns/tree/tree.spec.ts rename to src/aria/private/tree/tree.spec.ts index 844881aa6645..8fdc395c2837 100644 --- a/src/aria/ui-patterns/tree/tree.spec.ts +++ b/src/aria/private/tree/tree.spec.ts @@ -6,16 +6,15 @@ * found in the LICENSE file at https://angular.dev/license */ -import {WritableSignal, signal} from '@angular/core'; import {TreeInputs, TreeItemInputs, TreeItemPattern, TreePattern} from './tree'; import {createKeyboardEvent} from '@angular/cdk/testing/private'; import {ModifierKeys} from '@angular/cdk/testing'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; +import {WritableSignalLike, signal, SignalLike} from '../behaviors/signal-like/signal-like'; // Converts the SignalLike type to WritableSignal type for controlling test inputs. type WritableSignalOverrides = { [K in keyof O as O[K] extends SignalLike ? K : never]: O[K] extends SignalLike - ? WritableSignal + ? WritableSignalLike : never; }; @@ -58,6 +57,7 @@ interface TestTreeItem { children?: TestTreeItem[]; disabled: boolean; selectable: boolean; + expanded: boolean; } describe('Tree Pattern', () => { @@ -86,6 +86,7 @@ describe('Tree Pattern', () => { element: signal(element), disabled: signal(node.disabled), selectable: signal(node.selectable), + expanded: signal(node.expanded), searchTerm: signal(String(node.value)), parent: signal(parent), hasChildren: signal((node.children ?? []).length > 0), @@ -120,18 +121,20 @@ describe('Tree Pattern', () => { { value: 'Item 0', children: [ - {value: 'Item 0-0', disabled: false, selectable: true}, - {value: 'Item 0-1', disabled: false, selectable: true}, + {value: 'Item 0-0', disabled: false, selectable: true, expanded: false}, + {value: 'Item 0-1', disabled: false, selectable: true, expanded: false}, ], disabled: false, selectable: true, + expanded: false, }, - {value: 'Item 1', disabled: false, selectable: true}, + {value: 'Item 1', disabled: false, selectable: true, expanded: false}, { value: 'Item 2', - children: [{value: 'Item 2-0', disabled: false, selectable: true}], + children: [{value: 'Item 2-0', disabled: false, selectable: true, expanded: false}], disabled: false, selectable: true, + expanded: false, }, ]; @@ -147,10 +150,10 @@ describe('Tree Pattern', () => { multi: signal(false), orientation: signal('vertical'), selectionMode: signal('follow'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -201,10 +204,10 @@ describe('Tree Pattern', () => { multi: signal(false), orientation: signal('vertical'), selectionMode: signal('follow'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(true), currentType: signal('page'), @@ -215,7 +218,7 @@ describe('Tree Pattern', () => { it('should have undefined selected state', () => { const {allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); expect(item0.selected()).toBeUndefined(); }); @@ -224,11 +227,11 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); expect(item0.current()).toBe('page'); expect(item1.current()).toBeUndefined(); - treeInputs.value.set(['Item 1']); + treeInputs.values.set(['Item 1']); treeInputs.currentType.set('step'); expect(item0.current()).toBeUndefined(); expect(item1.current()).toBe('step'); @@ -237,7 +240,7 @@ describe('Tree Pattern', () => { it('should have undefined current state when non-selectable', () => { const {allItems, itemPatternInputsMap} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); expect(item0.current()).toBe('page'); itemPatternInputsMap.get(item0.id())!.selectable.set(false); expect(item0.current()).toBeUndefined(); @@ -257,10 +260,10 @@ describe('Tree Pattern', () => { multi: signal(false), orientation: signal('vertical'), selectionMode: signal('explicit'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -282,10 +285,10 @@ describe('Tree Pattern', () => { expect(item1.active()).toBe(true); }); - it('should correctly compute tabindex state', () => { + it('should correctly compute tab index state', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - expect(item0.tabindex()).toBe(tree.listBehavior.getItemTabindex(item0)); + expect(item0.tabIndex()).toBe(tree.listBehavior.getItemTabindex(item0)); }); it('should navigate next on ArrowDown (vertical)', () => { @@ -384,12 +387,12 @@ describe('Tree Pattern', () => { expect(tree.activeItem()).toBe(item2); }); - it('should skip disabled items when skipDisabled is true', () => { - treeInputs.skipDisabled.set(true); + it('should skip disabled items when softDisabled is false', () => { + treeInputs.softDisabled.set(false); const localTreeExample: TestTreeItem[] = [ - {value: 'Item A', disabled: false, selectable: true}, - {value: 'Item B', disabled: true, selectable: true}, - {value: 'Item C', disabled: false, selectable: true}, + {value: 'Item A', disabled: false, selectable: true, expanded: false}, + {value: 'Item B', disabled: true, selectable: true, expanded: false}, + {value: 'Item C', disabled: false, selectable: true, expanded: false}, ]; const {tree, allItems} = createTree(localTreeExample, treeInputs); const itemA = getItemByValue(allItems(), 'Item A'); @@ -401,12 +404,12 @@ describe('Tree Pattern', () => { expect(tree.activeItem()).toBe(itemC); }); - it('should not skip disabled items when skipDisabled is false', () => { - treeInputs.skipDisabled.set(false); + it('should not skip disabled items when softDisabled is true', () => { + treeInputs.softDisabled.set(true); const localTreeExample: TestTreeItem[] = [ - {value: 'Item A', disabled: false, selectable: true}, - {value: 'Item B', disabled: true, selectable: true}, - {value: 'Item C', disabled: false, selectable: true}, + {value: 'Item A', disabled: false, selectable: true, expanded: false}, + {value: 'Item B', disabled: true, selectable: true, expanded: false}, + {value: 'Item C', disabled: false, selectable: true, expanded: false}, ]; const {tree, allItems} = createTree(localTreeExample, treeInputs); const itemA = getItemByValue(allItems(), 'Item A'); @@ -443,10 +446,10 @@ describe('Tree Pattern', () => { multi: signal(false), orientation: signal('vertical'), selectionMode: signal('follow'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -459,11 +462,11 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); expect(item0.selected()).toBe(true); expect(item1.selected()).toBe(false); - treeInputs.value.set(['Item 1']); + treeInputs.values.set(['Item 1']); expect(item0.selected()).toBe(false); expect(item1.selected()).toBe(true); }); @@ -471,7 +474,7 @@ describe('Tree Pattern', () => { it('should have undefined selected state when non-selectable', () => { const {allItems, itemPatternInputsMap} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); itemPatternInputsMap.get(item0.id())!.selectable.set(false); expect(item0.selected()).toBeUndefined(); }); @@ -483,11 +486,11 @@ describe('Tree Pattern', () => { tree.onKeydown(down()); expect(tree.activeItem()).toBe(item1); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); tree.onKeydown(up()); expect(tree.activeItem()).toBe(item0); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should not change selection when the tree is disabled', () => { @@ -495,7 +498,7 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(down()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); }); @@ -511,10 +514,10 @@ describe('Tree Pattern', () => { multi: signal(false), orientation: signal('vertical'), selectionMode: signal('explicit'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -526,45 +529,45 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should not deselect an item on Space', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should select an item on Enter', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should not deselect an item on Enter', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should only allow one selected item', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); tree.onKeydown(down()); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should not change selection when the tree is disabled', () => { @@ -572,10 +575,10 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); }); @@ -591,10 +594,10 @@ describe('Tree Pattern', () => { multi: signal(true), orientation: signal('vertical'), selectionMode: signal('explicit'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -606,14 +609,14 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should select an item on Enter', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should allow multiple selected items', () => { @@ -622,23 +625,23 @@ describe('Tree Pattern', () => { tree.onKeydown(enter()); tree.onKeydown(down()); tree.onKeydown(enter()); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 1']); }); it('should select a range of visible items on Shift + ArrowDown/ArrowUp', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - item0.expansion.open(); + item0.expanded.set(true); tree.onKeydown(shift()); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0']); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); tree.onKeydown(up({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0']); }); it('should not allow wrapping while Shift is held down', () => { @@ -648,47 +651,47 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(up({shift: true})); expect(tree.activeItem()).toBe(item0); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should select a range of visible items on Shift + Space (or Enter)', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - item0.expansion.open(); + item0.expanded.set(true); tree.onKeydown(down()); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual(['Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0-0']); tree.onKeydown(down()); tree.onKeydown(down()); tree.onKeydown(shift()); tree.onKeydown(space({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1']); + expect(tree.inputs.values()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1']); }); it('should select the focused item and all visible items up to the first on Ctrl + Shift + Home', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); - item0.expansion.open(); + item0.expanded.set(true); tree.listBehavior.goto(item1); tree.onKeydown(shift()); tree.onKeydown(home({control: true, shift: true})); - expect(tree.inputs.value()).toEqual(['Item 1', 'Item 0-1', 'Item 0-0', 'Item 0']); + expect(tree.inputs.values()).toEqual(['Item 1', 'Item 0-1', 'Item 0-0', 'Item 0']); }); it('should select the focused item and all visible items down to the last on Ctrl + Shift + End', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); - item0.expansion.open(); + item0.expanded.set(true); tree.listBehavior.goto(item0_0); tree.onKeydown(shift()); tree.onKeydown(end({control: true, shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); + expect(tree.inputs.values()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); }); it('should not change selection when the tree is disabled', () => { @@ -696,19 +699,19 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(space()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); tree.onKeydown(a({control: true})); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should not select disabled items on Shift + ArrowUp / ArrowDown', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: false, selectable: true}, - {value: 'B', disabled: true, selectable: true}, - {value: 'C', disabled: false, selectable: true}, + {value: 'A', disabled: false, selectable: true, expanded: false}, + {value: 'B', disabled: true, selectable: true, expanded: false}, + {value: 'C', disabled: false, selectable: true, expanded: false}, ]; - treeInputs.skipDisabled.set(false); + treeInputs.softDisabled.set(true); const {tree, allItems} = createTree(localTreeData, treeInputs); const itemA = getItemByValue(allItems(), 'A'); @@ -716,14 +719,14 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(down({shift: true})); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['A', 'C']); + expect(tree.inputs.values()).toEqual(['A', 'C']); }); it('should not select non-selectable items on Shift + ArrowUp / ArrowDown', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: false, selectable: true}, - {value: 'B', disabled: false, selectable: false}, - {value: 'C', disabled: false, selectable: true}, + {value: 'A', disabled: false, selectable: true, expanded: false}, + {value: 'B', disabled: false, selectable: false, expanded: false}, + {value: 'C', disabled: false, selectable: true, expanded: false}, ]; const {tree, allItems} = createTree(localTreeData, treeInputs); const itemA = getItemByValue(allItems(), 'A'); @@ -732,26 +735,32 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(down({shift: true})); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['A', 'C']); + expect(tree.inputs.values()).toEqual(['A', 'C']); }); it('should select all visible items on Ctrl + A', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - item0.expansion.open(); + item0.expanded.set(true); tree.onKeydown(a({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); + expect(tree.inputs.values()).toEqual([ + 'Item 0', + 'Item 0-0', + 'Item 0-1', + 'Item 1', + 'Item 2', + ]); }); it('should deselect all visible items on Ctrl + A if all are selected', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - item0.expansion.open(); + item0.expanded.set(true); tree.onKeydown(a({control: true})); tree.onKeydown(a({control: true})); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); }); @@ -767,10 +776,10 @@ describe('Tree Pattern', () => { multi: signal(true), orientation: signal('vertical'), selectionMode: signal('follow'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -782,42 +791,42 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(down()); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should navigate without selecting if the Ctrl key is pressed', () => { - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); const {tree, allItems} = createTree(treeExample, treeInputs); const item1 = getItemByValue(allItems(), 'Item 1'); tree.onKeydown(down({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); expect(tree.activeItem()).toBe(item1); }); it('should toggle an item selection state on Ctrl + Space', () => { - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(down({control: true})); tree.onKeydown(space({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 1']); tree.onKeydown(space({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); it('should select a range of visible items on Shift + ArrowDown/ArrowUp', () => { - treeInputs.value.set(['Item 0']); + treeInputs.values.set(['Item 0']); const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - item0.expansion.open(); + item0.expanded.set(true); tree.onKeydown(shift()); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0']); tree.onKeydown(down({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); }); it('should not allow wrapping while Shift is held down', () => { @@ -828,44 +837,44 @@ describe('Tree Pattern', () => { tree.onKeydown(shift()); tree.onKeydown(up({shift: true})); expect(tree.activeItem()).toBe(item0); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should select a range of visible items on Shift + Space (or Enter)', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - item0.expansion.open(); + item0.expanded.set(true); tree.listBehavior.goto(item0); tree.onKeydown(down({control: true})); tree.onKeydown(down({control: true})); tree.onKeydown(shift()); tree.onKeydown(space({shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1']); }); it('should select the focused item and all visible items up to the first on Ctrl + Shift + Home', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); - item0.expansion.open(); + item0.expanded.set(true); tree.listBehavior.goto(item1); tree.onKeydown(shift()); tree.onKeydown(home({control: true, shift: true})); - expect(tree.inputs.value()).toEqual(['Item 1', 'Item 0-1', 'Item 0-0', 'Item 0']); + expect(tree.inputs.values()).toEqual(['Item 1', 'Item 0-1', 'Item 0-0', 'Item 0']); }); it('should select the focused item and all visible items down to the last on Ctrl + Shift + End', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); - item0.expansion.open(); + item0.expanded.set(true); tree.listBehavior.goto(item0_0); tree.onKeydown(shift()); tree.onKeydown(end({control: true, shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); + expect(tree.inputs.values()).toEqual(['Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); }); it('should not change selection when the tree is disabled', () => { @@ -873,50 +882,56 @@ describe('Tree Pattern', () => { const {tree} = createTree(treeExample, treeInputs); tree.onKeydown(down()); - expect(tree.inputs.value()).toEqual([]); + expect(tree.inputs.values()).toEqual([]); }); it('should not select disabled items on navigation', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: false, selectable: true}, - {value: 'B', disabled: true, selectable: true}, - {value: 'C', disabled: false, selectable: true}, + {value: 'A', disabled: false, selectable: true, expanded: false}, + {value: 'B', disabled: true, selectable: true, expanded: false}, + {value: 'C', disabled: false, selectable: true, expanded: false}, ]; - treeInputs.skipDisabled.set(true); + treeInputs.softDisabled.set(false); const {tree, allItems} = createTree(localTreeData, treeInputs); - treeInputs.value.set(['A']); + treeInputs.values.set(['A']); tree.listBehavior.goto(getItemByValue(allItems(), 'A')); tree.onKeydown(down()); - expect(tree.inputs.value()).toEqual(['C']); + expect(tree.inputs.values()).toEqual(['C']); }); it('should not select non-selectable items on navigation', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: false, selectable: true}, - {value: 'B', disabled: false, selectable: false}, - {value: 'C', disabled: false, selectable: true}, + {value: 'A', disabled: false, selectable: true, expanded: false}, + {value: 'B', disabled: false, selectable: false, expanded: false}, + {value: 'C', disabled: false, selectable: true, expanded: false}, ]; const {tree, allItems} = createTree(localTreeData, treeInputs); - treeInputs.value.set(['A']); + treeInputs.values.set(['A']); tree.listBehavior.goto(getItemByValue(allItems(), 'A')); tree.onKeydown(down()); tree.onKeydown(down()); - expect(tree.inputs.value()).toEqual(['C']); + expect(tree.inputs.values()).toEqual(['C']); }); it('should deselect all except the focused item on Ctrl + A if all are selected', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); - item0.expansion.open(); + item0.expanded.set(true); tree.listBehavior.goto(item0_0); tree.onKeydown(a({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); + expect(tree.inputs.values()).toEqual([ + 'Item 0', + 'Item 0-0', + 'Item 0-1', + 'Item 1', + 'Item 2', + ]); tree.onKeydown(a({control: true})); - expect(tree.inputs.value()).toEqual(['Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0-0']); }); }); }); @@ -934,10 +949,10 @@ describe('Tree Pattern', () => { multi: signal(false), orientation: signal('vertical'), selectionMode: signal('follow'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -949,9 +964,9 @@ describe('Tree Pattern', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item1 = getItemByValue(allItems(), 'Item 1'); - tree.onPointerdown(createClickEvent(item1.element())); + tree.onPointerdown(createClickEvent(item1.element()!)); expect(tree.activeItem()).toBe(item1); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should not change selection when the tree is disabled', () => { @@ -959,8 +974,8 @@ describe('Tree Pattern', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item1 = getItemByValue(allItems(), 'Item 1'); - tree.onPointerdown(createClickEvent(item1.element())); - expect(tree.inputs.value()).toEqual([]); + tree.onPointerdown(createClickEvent(item1.element()!)); + expect(tree.inputs.values()).toEqual([]); }); }); @@ -976,10 +991,10 @@ describe('Tree Pattern', () => { multi: signal(false), orientation: signal('vertical'), selectionMode: signal('explicit'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -991,22 +1006,22 @@ describe('Tree Pattern', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item1 = getItemByValue(allItems(), 'Item 1'); - tree.onPointerdown(createClickEvent(item1.element())); + tree.onPointerdown(createClickEvent(item1.element()!)); expect(tree.activeItem()).toBe(item1); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should not deselect item on click', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item1 = getItemByValue(allItems(), 'Item 1'); - tree.onPointerdown(createClickEvent(item1.element())); + tree.onPointerdown(createClickEvent(item1.element()!)); expect(tree.activeItem()).toBe(item1); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); - tree.onPointerdown(createClickEvent(item1.element())); + tree.onPointerdown(createClickEvent(item1.element()!)); expect(tree.activeItem()).toBe(item1); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should not change selection when the tree is disabled', () => { @@ -1014,8 +1029,8 @@ describe('Tree Pattern', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item1 = getItemByValue(allItems(), 'Item 1'); - tree.onPointerdown(createClickEvent(item1.element())); - expect(tree.inputs.value()).toEqual([]); + tree.onPointerdown(createClickEvent(item1.element()!)); + expect(tree.inputs.values()).toEqual([]); }); }); @@ -1031,10 +1046,10 @@ describe('Tree Pattern', () => { multi: signal(true), orientation: signal('vertical'), selectionMode: signal('explicit'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -1047,25 +1062,25 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); - tree.onPointerdown(createClickEvent(item0.element())); - expect(tree.inputs.value()).toEqual(['Item 0']); + tree.onPointerdown(createClickEvent(item0.element()!)); + expect(tree.inputs.values()).toEqual(['Item 0']); - tree.onPointerdown(createClickEvent(item1.element())); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 1']); + tree.onPointerdown(createClickEvent(item1.element()!)); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 1']); - tree.onPointerdown(createClickEvent(item0.element())); - expect(tree.inputs.value()).toEqual(['Item 1']); + tree.onPointerdown(createClickEvent(item0.element()!)); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should navigate and select range from anchor on shift + click', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); - item0.expansion.open(); + item0.expanded.set(true); tree.onKeydown(shift()); - tree.onPointerdown(createClickEvent(item1.element(), {shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1']); + tree.onPointerdown(createClickEvent(item1.element()!, {shift: true})); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1']); }); }); @@ -1081,10 +1096,10 @@ describe('Tree Pattern', () => { multi: signal(true), orientation: signal('vertical'), selectionMode: signal('follow'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -1097,10 +1112,10 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); - tree.onPointerdown(createClickEvent(item0.element())); - expect(tree.inputs.value()).toEqual(['Item 0']); - tree.onPointerdown(createClickEvent(item1.element())); - expect(tree.inputs.value()).toEqual(['Item 1']); + tree.onPointerdown(createClickEvent(item0.element()!)); + expect(tree.inputs.values()).toEqual(['Item 0']); + tree.onPointerdown(createClickEvent(item1.element()!)); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should navigate and toggle selection on ctrl + click', () => { @@ -1108,11 +1123,11 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); - tree.onPointerdown(createClickEvent(item0.element())); // Select and expand Item 0 - tree.onPointerdown(createClickEvent(item1.element(), {control: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 1']); - tree.onPointerdown(createClickEvent(item0.element(), {control: true})); - expect(tree.inputs.value()).toEqual(['Item 1']); + tree.onPointerdown(createClickEvent(item0.element()!)); // Select and expand Item 0 + tree.onPointerdown(createClickEvent(item1.element()!, {control: true})); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 1']); + tree.onPointerdown(createClickEvent(item0.element()!, {control: true})); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should navigate and select range from anchor on shift + click', () => { @@ -1120,10 +1135,16 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item2 = getItemByValue(allItems(), 'Item 2'); - tree.onPointerdown(createClickEvent(item0.element())); // Select and expand Item 0 + tree.onPointerdown(createClickEvent(item0.element()!)); // Select and expand Item 0 tree.onKeydown(shift()); - tree.onPointerdown(createClickEvent(item2.element(), {shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1', 'Item 2']); + tree.onPointerdown(createClickEvent(item2.element()!, {shift: true})); + expect(tree.inputs.values()).toEqual([ + 'Item 0', + 'Item 0-0', + 'Item 0-1', + 'Item 1', + 'Item 2', + ]); }); it('should select a new range on subsequent shift + clicks, deselecting previous range', () => { @@ -1131,36 +1152,36 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item1 = getItemByValue(allItems(), 'Item 1'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); - item0.expansion.open(); + item0.expanded.set(true); tree.onKeydown(shift()); - tree.onPointerdown(createClickEvent(item1.element(), {shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1']); + tree.onPointerdown(createClickEvent(item1.element()!, {shift: true})); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0', 'Item 0-1', 'Item 1']); - tree.onPointerdown(createClickEvent(item0_0.element(), {shift: true})); - expect(tree.inputs.value()).toEqual(['Item 0', 'Item 0-0']); + tree.onPointerdown(createClickEvent(item0_0.element()!, {shift: true})); + expect(tree.inputs.values()).toEqual(['Item 0', 'Item 0-0']); }); it('should not select disabled items on click', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: true, selectable: true}, + {value: 'A', disabled: true, selectable: true, expanded: false}, ]; const {tree, allItems} = createTree(localTreeData, treeInputs); const itemA = getItemByValue(allItems(), 'A'); - tree.onPointerdown(createClickEvent(itemA.element())); - expect(tree.inputs.value()).toEqual([]); + tree.onPointerdown(createClickEvent(itemA.element()!)); + expect(tree.inputs.values()).toEqual([]); expect(tree.activeItem()).toBe(itemA); }); it('should not select non-selectable items on click', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: false, selectable: false}, + {value: 'A', disabled: false, selectable: false, expanded: false}, ]; const {tree, allItems} = createTree(localTreeData, treeInputs); const itemA = getItemByValue(allItems(), 'A'); - tree.onPointerdown(createClickEvent(itemA.element())); - expect(tree.inputs.value()).toEqual([]); + tree.onPointerdown(createClickEvent(itemA.element()!)); + expect(tree.inputs.values()).toEqual([]); }); }); }); @@ -1177,10 +1198,10 @@ describe('Tree Pattern', () => { multi: signal(false), orientation: signal('vertical'), selectionMode: signal('explicit'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -1189,15 +1210,49 @@ describe('Tree Pattern', () => { }); it('should correctly compute visible state', () => { - const {allItems} = createTree(treeExample, treeInputs); + const {allItems} = createTree( + [ + { + value: 'Item 0', + children: [ + { + value: 'Item 0-0', + children: [ + {value: 'Item 0-0-0', disabled: false, selectable: true, expanded: false}, + ], + disabled: false, + selectable: true, + expanded: false, + }, + { + value: 'Item 0-1', + disabled: false, + selectable: true, + expanded: false, + }, + ], + disabled: false, + selectable: true, + expanded: false, + }, + ], + treeInputs, + ); const item0 = getItemByValue(allItems(), 'Item 0'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); + const item0_0_0 = getItemByValue(allItems(), 'Item 0-0-0'); expect(item0_0.visible()).toBe(false); - item0.expansion.open(); + expect(item0_0_0.visible()).toBe(false); + item0.expanded.set(true); + expect(item0_0.visible()).toBe(true); + expect(item0_0_0.visible()).toBe(false); + item0_0.expanded.set(true); expect(item0_0.visible()).toBe(true); - item0.expansion.close(); + expect(item0_0_0.visible()).toBe(true); + item0.expanded.set(false); expect(item0_0.visible()).toBe(false); + expect(item0_0_0.visible()).toBe(false); }); it('should correctly compute expanded state', () => { @@ -1205,7 +1260,7 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); expect(item0.expanded()).toBe(false); - item0.expansion.open(); + item0.expanded.set(true); expect(item0.expanded()).toBe(true); }); @@ -1226,7 +1281,7 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); tree.listBehavior.goto(item0); - item0.expansion.open(); + item0.expanded.set(true); tree.onKeydown(right()); expect(tree.activeItem()).toBe(item0_0); @@ -1247,7 +1302,7 @@ describe('Tree Pattern', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); tree.listBehavior.goto(item0); - item0.expansion.open(); + item0.expanded.set(true); expect(item0.expanded()).toBe(true); tree.onKeydown(left()); @@ -1259,7 +1314,7 @@ describe('Tree Pattern', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); - item0.expansion.open(); + item0.expanded.set(true); tree.listBehavior.goto(item0_0); tree.onKeydown(left()); @@ -1295,9 +1350,9 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); expect(item0.expanded()).toBe(false); - tree.onPointerdown(createClickEvent(item0.element())); + tree.onPointerdown(createClickEvent(item0.element()!)); expect(item0.expanded()).toBe(true); - tree.onPointerdown(createClickEvent(item0.element())); + tree.onPointerdown(createClickEvent(item0.element()!)); expect(item0.expanded()).toBe(false); }); @@ -1306,7 +1361,7 @@ describe('Tree Pattern', () => { const item1 = getItemByValue(allItems(), 'Item 1'); expect(item1.expanded()).toBe(false); - tree.onPointerdown(createClickEvent(item1.element())); + tree.onPointerdown(createClickEvent(item1.element()!)); expect(item1.expanded()).toBe(false); }); @@ -1315,7 +1370,7 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); itemPatternInputsMap.get(item0.id())!.disabled.set(true); - tree.onPointerdown(createClickEvent(item0.element())); + tree.onPointerdown(createClickEvent(item0.element()!)); expect(item0.expanded()).toBe(false); }); @@ -1324,7 +1379,7 @@ describe('Tree Pattern', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - tree.onPointerdown(createClickEvent(item0.element())); + tree.onPointerdown(createClickEvent(item0.element()!)); expect(item0.expanded()).toBe(false); }); @@ -1340,11 +1395,11 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); tree.listBehavior.goto(item0); - item0.expansion.open(); + item0.expanded.set(true); tree.onKeydown(right()); expect(tree.activeItem()).toBe(item0_0); - expect(tree.inputs.value()).toEqual(['Item 0-0']); + expect(tree.inputs.values()).toEqual(['Item 0-0']); }); it('should navigate and select the parent on collapseKey if collapsed (vertical)', () => { @@ -1352,12 +1407,12 @@ describe('Tree Pattern', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); - item0.expansion.open(); + item0.expanded.set(true); tree.listBehavior.goto(item0_0); tree.onKeydown(left()); expect(tree.activeItem()).toBe(item0); - expect(tree.inputs.value()).toEqual(['Item 0']); + expect(tree.inputs.values()).toEqual(['Item 0']); }); }); @@ -1373,12 +1428,12 @@ describe('Tree Pattern', () => { const item0 = getItemByValue(allItems(), 'Item 0'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); tree.listBehavior.goto(item0); - item0.expansion.open(); - tree.inputs.value.set(['Item 1']); // pre-select something else + item0.expanded.set(true); + tree.inputs.values.set(['Item 1']); // pre-select something else tree.onKeydown(right({control: true})); expect(tree.activeItem()).toBe(item0_0); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); it('should navigate without select the parent on Ctrl + collapseKey if collapsed (vertical)', () => { @@ -1386,13 +1441,13 @@ describe('Tree Pattern', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); const item0_0 = getItemByValue(allItems(), 'Item 0-0'); - item0.expansion.open(); + item0.expanded.set(true); tree.listBehavior.goto(item0_0); - tree.inputs.value.set(['Item 1']); // pre-select something else + tree.inputs.values.set(['Item 1']); // pre-select something else tree.onKeydown(left({control: true})); expect(tree.activeItem()).toBe(item0); - expect(tree.inputs.value()).toEqual(['Item 1']); + expect(tree.inputs.values()).toEqual(['Item 1']); }); }); }); @@ -1409,10 +1464,10 @@ describe('Tree Pattern', () => { multi: signal(false), orientation: signal('vertical'), selectionMode: signal('explicit'), - skipDisabled: signal(true), + softDisabled: signal(true), textDirection: signal('ltr'), typeaheadDelay: signal(0), - value: signal([]), + values: signal([]), wrap: signal(false), nav: signal(false), currentType: signal('page'), @@ -1422,8 +1477,8 @@ describe('Tree Pattern', () => { it('should set activeIndex to the first visible focusable item if no selection', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: false, selectable: true}, - {value: 'B', disabled: false, selectable: true}, + {value: 'A', disabled: false, selectable: true, expanded: false}, + {value: 'B', disabled: false, selectable: true, expanded: false}, ]; const {tree, allItems} = createTree(localTreeData, treeInputs); @@ -1431,12 +1486,12 @@ describe('Tree Pattern', () => { expect(treeInputs.activeItem()).toBe(allItems()[0]); }); - it('should set activeIndex to the first visible focusable disabled item if skipDisabled is false and no selection', () => { + it('should set activeIndex to the first visible focusable disabled item if softDisabled is true and no selection', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: true, selectable: true}, - {value: 'B', disabled: false, selectable: true}, + {value: 'A', disabled: true, selectable: true, expanded: false}, + {value: 'B', disabled: false, selectable: true, expanded: false}, ]; - treeInputs.skipDisabled.set(false); + treeInputs.softDisabled.set(true); const {tree, allItems} = createTree(localTreeData, treeInputs); tree.setDefaultState(); @@ -1445,11 +1500,11 @@ describe('Tree Pattern', () => { it('should set activeIndex to the first selected visible focusable item', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: false, selectable: true}, - {value: 'B', disabled: false, selectable: true}, - {value: 'C', disabled: false, selectable: true}, + {value: 'A', disabled: false, selectable: true, expanded: false}, + {value: 'B', disabled: false, selectable: true, expanded: false}, + {value: 'C', disabled: false, selectable: true, expanded: false}, ]; - treeInputs.value.set(['B']); + treeInputs.values.set(['B']); const {tree, allItems} = createTree(localTreeData, treeInputs); tree.setDefaultState(); @@ -1458,39 +1513,39 @@ describe('Tree Pattern', () => { it('should prioritize the first selected item in visible order', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: false, selectable: true}, - {value: 'B', disabled: false, selectable: true}, - {value: 'C', disabled: false, selectable: true}, + {value: 'A', disabled: false, selectable: true, expanded: false}, + {value: 'B', disabled: false, selectable: true, expanded: false}, + {value: 'C', disabled: false, selectable: true, expanded: false}, ]; - treeInputs.value.set(['C', 'A']); + treeInputs.values.set(['C', 'A']); const {tree, allItems} = createTree(localTreeData, treeInputs); tree.setDefaultState(); expect(treeInputs.activeItem()).toBe(allItems()[0]); }); - it('should skip a selected disabled item if skipDisabled is true', () => { + it('should skip a selected disabled item if softDisabled is false', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: false, selectable: true}, - {value: 'B', disabled: true, selectable: true}, - {value: 'C', disabled: false, selectable: true}, + {value: 'A', disabled: false, selectable: true, expanded: false}, + {value: 'B', disabled: true, selectable: true, expanded: false}, + {value: 'C', disabled: false, selectable: true, expanded: false}, ]; - treeInputs.value.set(['B']); - treeInputs.skipDisabled.set(true); + treeInputs.values.set(['B']); + treeInputs.softDisabled.set(false); const {tree, allItems} = createTree(localTreeData, treeInputs); tree.setDefaultState(); expect(treeInputs.activeItem()).toBe(allItems()[0]); }); - it('should select a selected disabled item if skipDisabled is false', () => { + it('should select a selected disabled item if softDisabled is true', () => { const localTreeData: TestTreeItem[] = [ - {value: 'A', disabled: false, selectable: true}, - {value: 'B', disabled: true, selectable: true}, - {value: 'C', disabled: false, selectable: true}, + {value: 'A', disabled: false, selectable: true, expanded: false}, + {value: 'B', disabled: true, selectable: true, expanded: false}, + {value: 'C', disabled: false, selectable: true, expanded: false}, ]; - treeInputs.value.set(['B']); - treeInputs.skipDisabled.set(false); + treeInputs.values.set(['B']); + treeInputs.softDisabled.set(true); const {tree, allItems} = createTree(localTreeData, treeInputs); tree.setDefaultState(); @@ -1500,7 +1555,7 @@ describe('Tree Pattern', () => { it('should set activeIndex to first visible focusable item if selected item is not visible', () => { const {tree, allItems} = createTree(treeExample, treeInputs); const item0 = getItemByValue(allItems(), 'Item 0'); - treeInputs.value.set(['Item 0-0']); + treeInputs.values.set(['Item 0-0']); expect(item0.expanded()).toBe(false); expect(getItemByValue(allItems(), 'Item 0-0').visible()).toBe(false); diff --git a/src/aria/ui-patterns/tree/tree.ts b/src/aria/private/tree/tree.ts similarity index 74% rename from src/aria/ui-patterns/tree/tree.ts rename to src/aria/private/tree/tree.ts index 0f17ff45b7df..8829fdfa7230 100644 --- a/src/aria/ui-patterns/tree/tree.ts +++ b/src/aria/private/tree/tree.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.dev/license */ -import {computed, signal} from '@angular/core'; -import {SignalLike, WritableSignalLike} from '../behaviors/signal-like/signal-like'; +import {SignalLike, computed, WritableSignalLike} from '../behaviors/signal-like/signal-like'; import {List, ListInputs, ListItem} from '../behaviors/list/list'; -import {ExpansionItem, ExpansionControl, ListExpansion} from '../behaviors/expansion/expansion'; +import {ExpansionItem, ListExpansion} from '../behaviors/expansion/expansion'; import {KeyboardEventManager, PointerEventManager, Modifier} from '../behaviors/event-manager'; /** Represents the required inputs for a tree item. */ -export interface TreeItemInputs extends Omit, 'index'> { +export interface TreeItemInputs + extends Omit, 'index'>, Omit { /** The parent item. */ parent: SignalLike | TreePattern>; @@ -32,55 +32,51 @@ export interface TreeItemInputs extends Omit, 'index'> { */ export class TreeItemPattern implements ListItem, ExpansionItem { /** A unique identifier for this item. */ - readonly id: SignalLike; + readonly id: SignalLike = () => this.inputs.id(); /** The value of this item. */ - readonly value: SignalLike; + readonly value: SignalLike = () => this.inputs.value(); /** A reference to the item element. */ - readonly element: SignalLike; + readonly element: SignalLike = () => this.inputs.element()!; /** Whether the item is disabled. */ - readonly disabled: SignalLike; + readonly disabled: SignalLike = () => this.inputs.disabled(); /** The text used by the typeahead search. */ - readonly searchTerm: SignalLike; + readonly searchTerm: SignalLike = () => this.inputs.searchTerm(); /** The tree pattern this item belongs to. */ - readonly tree: SignalLike>; + readonly tree: SignalLike> = () => this.inputs.tree(); /** The parent item. */ - readonly parent: SignalLike | TreePattern>; + readonly parent: SignalLike | TreePattern> = () => this.inputs.parent(); /** The children items. */ - readonly children: SignalLike[]>; + readonly children: SignalLike[]> = () => this.inputs.children(); /** The position of this item among its siblings. */ readonly index = computed(() => this.tree().visibleItems().indexOf(this)); - /** The unique identifier used by the expansion behavior. */ - readonly expansionId: SignalLike; - /** Controls expansion for child items. */ - readonly expansionManager: ListExpansion; - - /** Controls expansion for this item. */ - readonly expansion: ExpansionControl; + readonly expansionBehavior: ListExpansion; /** Whether the item is expandable. It's expandable if children item exist. */ - readonly expandable: SignalLike; + readonly expandable: SignalLike = () => this.inputs.hasChildren(); /** Whether the item is selectable. */ - readonly selectable: SignalLike; + readonly selectable: SignalLike = () => this.inputs.selectable(); + + /** Whether the item is expanded. */ + readonly expanded: WritableSignalLike; /** The level of the current item in a tree. */ readonly level: SignalLike = computed(() => this.parent().level() + 1); - /** Whether this item is currently expanded. */ - readonly expanded = computed(() => this.expansion.isExpanded()); - /** Whether this item is visible. */ - readonly visible = computed(() => this.parent().expanded()); + readonly visible: SignalLike = computed( + () => this.parent().expanded() && this.parent().visible(), + ); /** The number of items under the same parent at the same level. */ readonly setsize = computed(() => this.parent().children().length); @@ -91,8 +87,8 @@ export class TreeItemPattern implements ListItem, ExpansionItem { /** Whether the item is active. */ readonly active = computed(() => this.tree().activeItem() === this); - /** The tabindex of the item. */ - readonly tabindex = computed(() => this.tree().listBehavior.getItemTabindex(this)); + /** The tab index of the item. */ + readonly tabIndex = computed(() => this.tree().listBehavior.getItemTabindex(this)); /** Whether the item is selected. */ readonly selected: SignalLike = computed(() => { @@ -102,7 +98,7 @@ export class TreeItemPattern implements ListItem, ExpansionItem { if (!this.selectable()) { return undefined; } - return this.tree().value().includes(this.value()); + return this.tree().values().includes(this.value()); }); /** The current type of this item. */ @@ -113,32 +109,14 @@ export class TreeItemPattern implements ListItem, ExpansionItem { if (!this.selectable()) { return undefined; } - return this.tree().value().includes(this.value()) ? this.tree().currentType() : undefined; + return this.tree().values().includes(this.value()) ? this.tree().currentType() : undefined; }); constructor(readonly inputs: TreeItemInputs) { - this.id = inputs.id; - this.value = inputs.value; - this.element = inputs.element; - this.disabled = inputs.disabled; - this.searchTerm = inputs.searchTerm; - this.expansionId = inputs.id; - this.tree = inputs.tree; - this.parent = inputs.parent; - this.children = inputs.children; - this.expandable = inputs.hasChildren; - this.selectable = inputs.selectable; - this.expansion = new ExpansionControl({ - ...inputs, - expandable: this.expandable, - expansionId: this.expansionId, - expansionManager: this.parent().expansionManager, - }); - this.expansionManager = new ListExpansion({ + this.expanded = inputs.expanded; + this.expansionBehavior = new ListExpansion({ ...inputs, multiExpandable: () => true, - // TODO(ok7sai): allow pre-expanded tree items. - expandedIds: signal([]), items: this.children, disabled: computed(() => this.tree()?.disabled() ?? false), }); @@ -168,14 +146,13 @@ export interface TreeInputs extends Omit, V>, ' currentType: SignalLike<'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'>; } -export interface TreePattern extends TreeInputs {} /** Controls the state and interactions of a tree view. */ -export class TreePattern { +export class TreePattern implements TreeInputs { /** The list behavior for the tree. */ readonly listBehavior: List, V>; /** Controls expansion for direct children of the tree root (top-level items). */ - readonly expansionManager: ListExpansion; + readonly expansionBehavior: ListExpansion; /** The root level is 0. */ readonly level = () => 0; @@ -183,11 +160,14 @@ export class TreePattern { /** The root is always expanded. */ readonly expanded = () => true; - /** The tabindex of the tree. */ - readonly tabindex: SignalLike<-1 | 0> = computed(() => this.listBehavior.tabindex()); + /** The root is always visible. */ + readonly visible = () => true; + + /** The tab index of the tree. */ + readonly tabIndex: SignalLike<-1 | 0> = computed(() => this.listBehavior.tabIndex()); /** The id of the current active item. */ - readonly activedescendant = computed(() => this.listBehavior.activedescendant()); + readonly activeDescendant = computed(() => this.listBehavior.activeDescendant()); /** The direct children of the root (top-level tree items). */ readonly children = computed(() => @@ -200,12 +180,15 @@ export class TreePattern { /** Whether the tree selection follows focus. */ readonly followFocus = computed(() => this.inputs.selectionMode() === 'follow'); + /** Whether the tree direction is RTL. */ + readonly isRtl = computed(() => this.inputs.textDirection() === 'rtl'); + /** The key for navigating to the previous item. */ readonly prevKey = computed(() => { if (this.inputs.orientation() === 'vertical') { return 'ArrowUp'; } - return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; + return this.isRtl() ? 'ArrowRight' : 'ArrowLeft'; }); /** The key for navigating to the next item. */ @@ -213,7 +196,7 @@ export class TreePattern { if (this.inputs.orientation() === 'vertical') { return 'ArrowDown'; } - return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; + return this.isRtl() ? 'ArrowLeft' : 'ArrowRight'; }); /** The key for collapsing an item or moving to its parent. */ @@ -221,7 +204,7 @@ export class TreePattern { if (this.inputs.orientation() === 'horizontal') { return 'ArrowUp'; } - return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; + return this.isRtl() ? 'ArrowRight' : 'ArrowLeft'; }); /** The key for expanding an item or moving to its first child. */ @@ -229,7 +212,7 @@ export class TreePattern { if (this.inputs.orientation() === 'horizontal') { return 'ArrowDown'; } - return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; + return this.isRtl() ? 'ArrowLeft' : 'ArrowRight'; }); /** Represents the space key. Does nothing when the user is actively using typeahead. */ @@ -275,13 +258,13 @@ export class TreePattern { if (!this.followFocus() && this.inputs.multi()) { manager .on(this.dynamicSpaceKey, () => list.toggle()) - .on('Enter', () => list.toggle()) + .on('Enter', () => list.toggle(), {preventDefault: !this.nav()}) .on([Modifier.Ctrl, Modifier.Meta], 'A', () => list.toggleAll()); } if (!this.followFocus() && !this.inputs.multi()) { manager.on(this.dynamicSpaceKey, () => list.selectOne()); - manager.on('Enter', () => list.selectOne()); + manager.on('Enter', () => list.selectOne(), {preventDefault: !this.nav()}); } if (this.inputs.multi() && this.followFocus()) { @@ -329,63 +312,58 @@ export class TreePattern { }); /** A unique identifier for the tree. */ - id: SignalLike; + readonly id: SignalLike = () => this.inputs.id(); + + /** The host native element. */ + readonly element: SignalLike = () => this.inputs.element()!; /** Whether the tree is in navigation mode. */ - nav: SignalLike; + readonly nav: SignalLike = () => this.inputs.nav(); /** The aria-current type. */ - currentType: SignalLike<'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'>; + readonly currentType: SignalLike< + 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false' + > = () => this.inputs.currentType(); /** All items in the tree, in document order (DFS-like, a flattened list). */ - allItems: SignalLike[]>; + readonly allItems: SignalLike[]> = () => this.inputs.allItems(); + + /** The focus strategy used by the tree. */ + readonly focusMode: SignalLike<'roving' | 'activedescendant'> = () => this.inputs.focusMode(); /** Whether the tree is disabled. */ - disabled: SignalLike; + readonly disabled: SignalLike = () => this.inputs.disabled(); /** The currently active item in the tree. */ - activeItem: WritableSignalLike | undefined> = signal(undefined); + readonly activeItem: WritableSignalLike | undefined>; - /** Whether disabled items should be skipped when navigating. */ - skipDisabled: SignalLike; + /** Whether disabled items should be focusable. */ + readonly softDisabled: SignalLike = () => this.inputs.softDisabled(); /** Whether the focus should wrap when navigating past the first or last item. */ - wrap: SignalLike; + readonly wrap: SignalLike = () => this.inputs.wrap(); /** The orientation of the tree. */ - orientation: SignalLike<'vertical' | 'horizontal'>; + readonly orientation: SignalLike<'vertical' | 'horizontal'> = () => this.inputs.orientation(); /** The text direction of the tree. */ - textDirection: SignalLike<'ltr' | 'rtl'>; + readonly textDirection: SignalLike<'ltr' | 'rtl'> = () => this.textDirection(); /** Whether multiple items can be selected at the same time. */ - multi: SignalLike; + readonly multi: SignalLike = computed(() => (this.nav() ? false : this.inputs.multi())); /** The selection mode of the tree. */ - selectionMode: SignalLike<'follow' | 'explicit'>; + readonly selectionMode: SignalLike<'follow' | 'explicit'> = () => this.inputs.selectionMode(); /** The delay in milliseconds to wait before clearing the typeahead buffer. */ - typeaheadDelay: SignalLike; + readonly typeaheadDelay: SignalLike = () => this.inputs.typeaheadDelay(); - /** The current value of the tree (the selected items). */ - value: WritableSignalLike; + /** The current selected items of the tree. */ + readonly values: WritableSignalLike; constructor(readonly inputs: TreeInputs) { - this.id = inputs.id; - this.nav = inputs.nav; - this.currentType = inputs.currentType; - this.allItems = inputs.allItems; - this.focusMode = inputs.focusMode; - this.disabled = inputs.disabled; this.activeItem = inputs.activeItem; - this.skipDisabled = inputs.skipDisabled; - this.wrap = inputs.wrap; - this.orientation = inputs.orientation; - this.textDirection = inputs.textDirection; - this.multi = computed(() => (this.nav() ? false : this.inputs.multi())); - this.selectionMode = inputs.selectionMode; - this.typeaheadDelay = inputs.typeaheadDelay; - this.value = inputs.value; + this.values = inputs.values; this.listBehavior = new List({ ...inputs, @@ -393,10 +371,8 @@ export class TreePattern { multi: this.multi, }); - this.expansionManager = new ListExpansion({ + this.expansionBehavior = new ListExpansion({ multiExpandable: () => true, - // TODO(ok7sai): allow pre-expanded tree items. - expandedIds: signal([]), items: this.children, disabled: this.disabled, }); @@ -462,7 +438,7 @@ export class TreePattern { if (item.expanded()) { this.collapse(); } else { - item.expansion.open(); + this.expansionBehavior.open(item); } } @@ -472,7 +448,7 @@ export class TreePattern { if (!item || !this.listBehavior.isFocusable(item)) return; if (item.expandable() && !item.expanded()) { - item.expansion.open(); + this.expansionBehavior.open(item); } else if ( item.expanded() && item.children().some(item => this.listBehavior.isFocusable(item)) @@ -485,7 +461,7 @@ export class TreePattern { expandSiblings(item?: TreeItemPattern) { item ??= this.activeItem(); const siblings = item?.parent()?.children(); - siblings?.forEach(item => item.expansion.open()); + siblings?.forEach(item => this.expansionBehavior.open(item)); } /** Collapses a tree item. */ @@ -494,7 +470,7 @@ export class TreePattern { if (!item || !this.listBehavior.isFocusable(item)) return; if (item.expandable() && item.expanded()) { - item.expansion.close(); + this.expansionBehavior.close(item); } else if (item.parent() && item.parent() !== this) { const parentItem = item.parent(); if (parentItem instanceof TreeItemPattern && this.listBehavior.isFocusable(parentItem)) { diff --git a/src/aria/ui-patterns/ui-pattern-rules.md b/src/aria/private/ui-pattern-rules.md similarity index 98% rename from src/aria/ui-patterns/ui-pattern-rules.md rename to src/aria/private/ui-pattern-rules.md index 04672869efd9..115765c398e1 100644 --- a/src/aria/ui-patterns/ui-pattern-rules.md +++ b/src/aria/private/ui-pattern-rules.md @@ -31,8 +31,8 @@ All .ts files should begin with an @license comment. ### Imports - Imports should be at the top of the file and kept in alphabetical order. -- The only allowed external APIs are `signal`, and `computed` from `@angular/core`. - All other dependencies must come from inside of the ui-patterns folder. +- Signal primitives, like `signal` and `computed`, must be imported from `signal-like.ts` ### Type Definition diff --git a/src/aria/radio-group/BUILD.bazel b/src/aria/radio-group/BUILD.bazel deleted file mode 100644 index 74a189efbb42..000000000000 --- a/src/aria/radio-group/BUILD.bazel +++ /dev/null @@ -1,38 +0,0 @@ -load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite") - -package(default_visibility = ["//visibility:public"]) - -ng_project( - name = "radio-group", - srcs = glob( - ["**/*.ts"], - exclude = ["**/*.spec.ts"], - ), - deps = [ - "//:node_modules/@angular/core", - "//src/aria/toolbar", - "//src/aria/ui-patterns", - "//src/cdk/a11y", - "//src/cdk/bidi", - ], -) - -ng_project( - name = "unit_test_sources", - testonly = True, - srcs = glob( - ["**/*.spec.ts"], - exclude = ["**/*.e2e.spec.ts"], - ), - deps = [ - ":radio-group", - "//:node_modules/@angular/core", - "//:node_modules/@angular/platform-browser", - "//src/cdk/testing/private", - ], -) - -ng_web_test_suite( - name = "unit_tests", - deps = [":unit_test_sources"], -) diff --git a/src/aria/radio-group/radio-group.spec.ts b/src/aria/radio-group/radio-group.spec.ts deleted file mode 100644 index b0643cd5a1cf..000000000000 --- a/src/aria/radio-group/radio-group.spec.ts +++ /dev/null @@ -1,570 +0,0 @@ -import {Component, DebugElement, signal} from '@angular/core'; -import {RadioButton, RadioGroup} from './radio-group'; -import {ComponentFixture, TestBed} from '@angular/core/testing'; -import {By} from '@angular/platform-browser'; -import {Direction} from '@angular/cdk/bidi'; -import {provideFakeDirectionality, runAccessibilityChecks} from '@angular/cdk/testing/private'; - -describe('RadioGroup', () => { - let fixture: ComponentFixture; - let radioGroup: DebugElement; - let radioButtons: DebugElement[]; - let radioGroupInstance: RadioGroup; - let radioGroupElement: HTMLElement; - let radioButtonElements: HTMLElement[]; - - const keydown = (key: string) => { - radioGroupElement.dispatchEvent(new KeyboardEvent('keydown', {bubbles: true, key})); - fixture.detectChanges(); - }; - - const click = (index: number) => { - radioButtonElements[index].dispatchEvent(new PointerEvent('pointerdown', {bubbles: true})); - fixture.detectChanges(); - }; - - const space = () => keydown(' '); - const enter = () => keydown('Enter'); - const up = () => keydown('ArrowUp'); - const down = () => keydown('ArrowDown'); - const left = () => keydown('ArrowLeft'); - const right = () => keydown('ArrowRight'); - const home = () => keydown('Home'); - const end = () => keydown('End'); - - function setupRadioGroup(opts?: { - orientation?: 'horizontal' | 'vertical'; - disabled?: boolean; - readonly?: boolean; - value?: number | null; - skipDisabled?: boolean; - focusMode?: 'roving' | 'activedescendant'; - disabledOptions?: number[]; - options?: TestOption[]; - textDirection?: Direction; - }) { - TestBed.configureTestingModule({ - providers: [provideFakeDirectionality(opts?.textDirection ?? 'ltr')], - }); - - fixture = TestBed.createComponent(RadioGroupExample); - const testComponent = fixture.componentInstance; - - if (opts?.orientation !== undefined) { - testComponent.orientation = opts.orientation; - } - if (opts?.disabled !== undefined) { - testComponent.disabled = opts.disabled; - } - if (opts?.readonly !== undefined) { - testComponent.readonly = opts.readonly; - } - if (opts?.value !== undefined) { - testComponent.value = opts.value; - } - if (opts?.skipDisabled !== undefined) { - testComponent.skipDisabled = opts.skipDisabled; - } - if (opts?.focusMode !== undefined) { - testComponent.focusMode = opts.focusMode; - } - if (opts?.options !== undefined) { - testComponent.options.set(opts.options); - } - if (opts?.disabledOptions !== undefined) { - opts.disabledOptions.forEach(index => { - testComponent.options()[index].disabled = true; - }); - } - - fixture.detectChanges(); - defineTestVariables(fixture); - } - - function setupDefaultRadioGroup() { - TestBed.configureTestingModule({ - providers: [provideFakeDirectionality('ltr')], - }); - - const fixture = TestBed.createComponent(DefaultRadioGroupExample); - fixture.detectChanges(); - defineTestVariables(fixture); - } - - function defineTestVariables(fixture: ComponentFixture) { - radioGroup = fixture.debugElement.query(By.directive(RadioGroup)); - radioButtons = fixture.debugElement.queryAll(By.directive(RadioButton)); - radioGroupInstance = radioGroup.injector.get>(RadioGroup); - radioGroupElement = radioGroup.nativeElement; - radioButtonElements = radioButtons.map(radioButton => radioButton.nativeElement); - } - - afterEach(async () => { - await runAccessibilityChecks(radioGroupElement); - }); - - describe('ARIA attributes and roles', () => { - describe('default configuration', () => { - it('should correctly set the role attribute to "radiogroup"', () => { - setupDefaultRadioGroup(); - expect(radioGroupElement.getAttribute('role')).toBe('radiogroup'); - }); - - it('should correctly set the role attribute to "radio" for the radio buttons', () => { - setupDefaultRadioGroup(); - radioButtonElements.forEach(radioButtonElement => { - expect(radioButtonElement.getAttribute('role')).toBe('radio'); - }); - }); - - it('should set aria-orientation to "vertical"', () => { - setupDefaultRadioGroup(); - expect(radioGroupElement.getAttribute('aria-orientation')).toBe('vertical'); - }); - - it('should set aria-disabled to false', () => { - setupDefaultRadioGroup(); - expect(radioGroupElement.getAttribute('aria-disabled')).toBe('false'); - }); - - it('should set aria-readonly to false', () => { - setupDefaultRadioGroup(); - expect(radioGroupElement.getAttribute('aria-readonly')).toBe('false'); - }); - }); - - describe('custom configuration', () => { - it('should be able to set aria-orientation to "vertical"', () => { - setupRadioGroup({orientation: 'vertical'}); - expect(radioGroupElement.getAttribute('aria-orientation')).toBe('vertical'); - }); - - it('should be able to set aria-disabled to true', () => { - setupRadioGroup({disabled: true}); - expect(radioGroupElement.getAttribute('aria-disabled')).toBe('true'); - }); - - it('should be able to set aria-readonly to true', () => { - setupRadioGroup({readonly: true}); - expect(radioGroupElement.getAttribute('aria-readonly')).toBe('true'); - }); - }); - - describe('roving focus mode', () => { - it('should have tabindex="-1" when focusMode is "roving"', () => { - setupRadioGroup({focusMode: 'roving'}); - expect(radioGroupElement.getAttribute('tabindex')).toBe('-1'); - }); - - it('should set tabindex="0" when disabled', () => { - setupRadioGroup({disabled: true, focusMode: 'roving'}); - expect(radioGroupElement.getAttribute('tabindex')).toBe('0'); - }); - - it('should set initial focus on the selected option', () => { - setupRadioGroup({focusMode: 'roving', value: 3}); - expect(radioButtonElements[3].getAttribute('tabindex')).toBe('0'); - }); - - it('should set initial focus on the first option if none are selected', () => { - setupRadioGroup({focusMode: 'roving'}); - expect(radioButtonElements[0].getAttribute('tabindex')).toBe('0'); - }); - - it('should not have aria-activedescendant when focusMode is "roving"', () => { - setupRadioGroup({focusMode: 'roving'}); - expect(radioGroupElement.getAttribute('aria-activedescendant')).toBeNull(); - }); - }); - - describe('activedescendant focus mode', () => { - it('should have tabindex="0"', () => { - setupRadioGroup({focusMode: 'activedescendant'}); - expect(radioGroupElement.getAttribute('tabindex')).toBe('0'); - }); - - it('should set initial focus on the selected option', () => { - setupRadioGroup({focusMode: 'activedescendant', value: 3}); - expect(radioGroupElement.getAttribute('aria-activedescendant')).toBe( - radioButtonElements[3].id, - ); - }); - - it('should set initial focus on the first option if none are selected', () => { - setupRadioGroup({focusMode: 'activedescendant'}); - expect(radioGroupElement.getAttribute('aria-activedescendant')).toBe( - radioButtonElements[0].id, - ); - }); - }); - }); - - describe('value and selection', () => { - it('should select the radio button corresponding to the value input', () => { - setupRadioGroup(); - radioGroupInstance.value.set(1); - fixture.detectChanges(); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('true'); - }); - - it('should update the value model when the value of a radio group is changed through the ui', () => { - setupRadioGroup(); - click(1); - expect(radioGroupInstance.value()).toBe(1); - }); - - describe('pointer interaction', () => { - it('should update the group value when a radio button is selected via pointer click', () => { - setupRadioGroup(); - click(1); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('true'); - }); - - it('should only allow one radio button to be selected at a time', () => { - setupRadioGroup(); - click(1); - click(2); - expect(radioButtonElements[0].getAttribute('aria-checked')).toBe('false'); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('false'); - expect(radioButtonElements[2].getAttribute('aria-checked')).toBe('true'); - expect(radioButtonElements[3].getAttribute('aria-checked')).toBe('false'); - expect(radioButtonElements[4].getAttribute('aria-checked')).toBe('false'); - }); - - it('should not change the value if the radio group is readonly', () => { - setupRadioGroup({readonly: true}); - click(3); - expect(radioButtonElements[3].getAttribute('aria-checked')).toBe('false'); - }); - - it('should not change the value if the radio group is disabled', () => { - setupRadioGroup({disabled: true}); - click(3); - expect(radioButtonElements[3].getAttribute('aria-checked')).toBe('false'); - }); - - it('should not change the value if a disabled radio button is clicked', () => { - setupRadioGroup({disabledOptions: [2]}); - click(2); - expect(radioButtonElements[2].getAttribute('aria-checked')).toBe('false'); - }); - - it('should not change the value if a radio button is clicked in a readonly group', () => { - setupRadioGroup({readonly: true}); - click(1); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('false'); - }); - }); - - describe('keyboard interaction', () => { - it('should update the group value on Space', () => { - setupRadioGroup(); - space(); - expect(radioButtonElements[0].getAttribute('aria-checked')).toBe('true'); - }); - - it('should update the group value on Enter', () => { - setupRadioGroup(); - enter(); - expect(radioButtonElements[0].getAttribute('aria-checked')).toBe('true'); - }); - - it('should not change the value if the radio group is readonly', () => { - setupRadioGroup({orientation: 'horizontal', readonly: true}); - right(); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('false'); - }); - - it('should not change the value if the radio group is disabled', () => { - setupRadioGroup({orientation: 'horizontal', disabled: true}); - right(); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('false'); - }); - - describe('horizontal orientation', () => { - it('should update the group value on ArrowRight', () => { - setupRadioGroup({orientation: 'horizontal'}); - right(); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('true'); - }); - - it('should update the group value on ArrowLeft', () => { - setupRadioGroup({orientation: 'horizontal'}); - right(); - right(); - left(); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('true'); - }); - - describe('text direction rtl', () => { - it('should update the group value on ArrowLeft', () => { - setupRadioGroup({orientation: 'horizontal', textDirection: 'rtl'}); - left(); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('true'); - }); - - it('should update the group value on ArrowRight', () => { - setupRadioGroup({orientation: 'horizontal', textDirection: 'rtl'}); - left(); - left(); - right(); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('true'); - }); - }); - }); - - describe('vertical orientation', () => { - it('should update the group value on ArrowDown', () => { - setupRadioGroup({orientation: 'vertical'}); - down(); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('true'); - }); - - it('should update the group value on ArrowUp', () => { - setupRadioGroup({orientation: 'vertical'}); - down(); - down(); - up(); - expect(radioButtonElements[1].getAttribute('aria-checked')).toBe('true'); - }); - }); - }); - }); - - function runNavigationTests( - focusMode: 'activedescendant' | 'roving', - isFocused: (index: number) => boolean, - ) { - describe(`keyboard navigation (focusMode="${focusMode}")`, () => { - it('should move focus to and select the last enabled radio button on End', () => { - setupRadioGroup({focusMode}); - end(); - expect(isFocused(4)).toBe(true); - }); - - it('should move focus to and select the first enabled radio button on Home', () => { - setupRadioGroup({focusMode}); - end(); - home(); - expect(isFocused(0)).toBe(true); - }); - - it('should not allow keyboard navigation or selection if the group is disabled', () => { - setupRadioGroup({focusMode, orientation: 'horizontal', disabled: true}); - right(); - expect(isFocused(0)).toBe(false); - }); - - it('should allow keyboard navigation if the group is readonly', () => { - setupRadioGroup({focusMode, orientation: 'horizontal', readonly: true}); - right(); - expect(isFocused(1)).toBe(true); - }); - - describe('vertical orientation', () => { - it('should move focus to the next radio button on ArrowDown', () => { - setupRadioGroup({focusMode, orientation: 'vertical'}); - down(); - expect(isFocused(1)).toBe(true); - }); - - it('should move focus to the previous radio button on ArrowUp', () => { - setupRadioGroup({focusMode, orientation: 'vertical'}); - down(); - down(); - up(); - expect(isFocused(1)).toBe(true); - }); - - it('should skip disabled radio buttons (skipDisabled="true")', () => { - setupRadioGroup({ - focusMode, - orientation: 'vertical', - skipDisabled: true, - disabledOptions: [1, 2], - }); - down(); - expect(isFocused(3)).toBe(true); - }); - - it('should not skip disabled radio buttons (skipDisabled="false")', () => { - setupRadioGroup({ - focusMode, - orientation: 'vertical', - skipDisabled: false, - disabledOptions: [1, 2], - }); - down(); - expect(isFocused(1)).toBe(true); - }); - }); - - describe('horizontal orientation', () => { - it('should move focus to the next radio button on ArrowRight', () => { - setupRadioGroup({focusMode, orientation: 'horizontal'}); - right(); - expect(isFocused(1)).toBe(true); - }); - - it('should move focus to the previous radio button on ArrowLeft', () => { - setupRadioGroup({focusMode, orientation: 'horizontal'}); - right(); - right(); - left(); - expect(isFocused(1)).toBe(true); - }); - - it('should skip disabled radio buttons (skipDisabled="true")', () => { - setupRadioGroup({ - focusMode, - orientation: 'horizontal', - skipDisabled: true, - disabledOptions: [1, 2], - }); - right(); - expect(isFocused(3)).toBe(true); - }); - - it('should not skip disabled radio buttons (skipDisabled="false")', () => { - setupRadioGroup({ - focusMode, - orientation: 'horizontal', - skipDisabled: false, - disabledOptions: [1, 2], - }); - right(); - expect(isFocused(1)).toBe(true); - }); - - describe('text direction rtl', () => { - it('should move focus to the next radio button on ArrowLeft', () => { - setupRadioGroup({focusMode, textDirection: 'rtl', orientation: 'horizontal'}); - left(); - expect(isFocused(1)).toBe(true); - }); - - it('should move focus to the previous radio button on ArrowRight', () => { - setupRadioGroup({focusMode, textDirection: 'rtl', orientation: 'horizontal'}); - left(); - left(); - right(); - expect(isFocused(1)).toBe(true); - }); - - it('should skip disabled radio buttons when navigating', () => { - setupRadioGroup({ - focusMode, - skipDisabled: true, - textDirection: 'rtl', - disabledOptions: [1, 2], - orientation: 'horizontal', - }); - left(); - expect(isFocused(3)).toBe(true); - }); - }); - }); - }); - - describe(`pointer navigation (focusMode="${focusMode}")`, () => { - it('should move focus to the clicked radio button', () => { - setupRadioGroup({focusMode}); - click(3); - expect(isFocused(3)).toBe(true); - }); - - it('should move focus to the clicked radio button if the group is disabled (skipDisabled="true")', () => { - setupRadioGroup({focusMode, skipDisabled: true, disabled: true}); - click(3); - expect(isFocused(3)).toBe(false); - }); - - it('should not move focus to the clicked radio button if the group is disabled (skipDisabled="false")', () => { - setupRadioGroup({focusMode, skipDisabled: true, disabled: true}); - click(3); - expect(isFocused(0)).toBe(false); - }); - - it('should move focus to the clicked radio button if the group is readonly', () => { - setupRadioGroup({focusMode, readonly: true}); - click(3); - expect(isFocused(3)).toBe(true); - }); - }); - } - - runNavigationTests('roving', i => { - return radioButtonElements[i].getAttribute('tabindex') === '0'; - }); - - runNavigationTests('activedescendant', i => { - return radioGroupElement.getAttribute('aria-activedescendant') === radioButtonElements[i].id; - }); - - describe('failure cases', () => { - it('should handle an empty set of radio buttons gracefully', () => { - setupRadioGroup({options: []}); - expect(radioButtons.length).toBe(0); - }); - - describe('bad accessibility violations', () => { - it('should report when the selected radio button is disabled and skipDisabled is true', () => { - spyOn(console, 'error'); - setupRadioGroup({value: 1, skipDisabled: true, disabledOptions: [1]}); - expect(console.error).toHaveBeenCalled(); - }); - }); - }); -}); - -interface TestOption { - value: number; - label: string; - disabled: boolean; -} - -@Component({ - template: ` -
        - @for (option of options(); track option.value) { -
        {{ option.label }}
        - } -
        - `, - imports: [RadioGroup, RadioButton], -}) -class RadioGroupExample { - options = signal([ - {value: 0, label: '0', disabled: false}, - {value: 1, label: '1', disabled: false}, - {value: 2, label: '2', disabled: false}, - {value: 3, label: '3', disabled: false}, - {value: 4, label: '4', disabled: false}, - ]); - - value: number | null = null; - disabled = false; - readonly = false; - skipDisabled = true; - focusMode: 'roving' | 'activedescendant' = 'roving'; - orientation: 'horizontal' | 'vertical' = 'horizontal'; -} - -@Component({ - template: ` -
        -
        0
        -
        1
        -
        2
        -
        - `, - imports: [RadioGroup, RadioButton], -}) -class DefaultRadioGroupExample {} diff --git a/src/aria/radio-group/radio-group.ts b/src/aria/radio-group/radio-group.ts deleted file mode 100644 index a832139e92ec..000000000000 --- a/src/aria/radio-group/radio-group.ts +++ /dev/null @@ -1,249 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import { - afterRenderEffect, - booleanAttribute, - computed, - contentChildren, - Directive, - ElementRef, - inject, - input, - linkedSignal, - model, - signal, - WritableSignal, -} from '@angular/core'; -import { - RadioButtonPattern, - RadioGroupInputs, - RadioGroupPattern, - ToolbarRadioGroupInputs, - ToolbarRadioGroupPattern, -} from '@angular/aria/ui-patterns'; -import {Directionality} from '@angular/cdk/bidi'; -import {_IdGenerator} from '@angular/cdk/a11y'; -import {ToolbarWidgetGroup} from '@angular/aria/toolbar'; - -// TODO: Move mapSignal to it's own file so it can be reused across components. - -/** - * Creates a new writable signal (signal V) whose value is connected to the given original - * writable signal (signal T) such that updating signal V updates signal T and vice-versa. - * - * This function establishes a two-way synchronization between the source signal and the new mapped - * signal. When the source signal changes, the mapped signal updates by applying the `transform` - * function. When the mapped signal is explicitly set or updated, the change is propagated back to - * the source signal by applying the `reverse` function. - */ -export function mapSignal( - originalSignal: WritableSignal, - operations: { - transform: (value: T) => V; - reverse: (value: V) => T; - }, -) { - const mappedSignal = linkedSignal(() => operations.transform(originalSignal())); - const updateMappedSignal = mappedSignal.update; - const setMappedSignal = mappedSignal.set; - - mappedSignal.set = (newValue: V) => { - setMappedSignal(newValue); - originalSignal.set(operations.reverse(newValue)); - }; - - mappedSignal.update = (updateFn: (value: V) => V) => { - updateMappedSignal(oldValue => updateFn(oldValue)); - originalSignal.update(oldValue => operations.reverse(updateFn(operations.transform(oldValue)))); - }; - - return mappedSignal; -} - -/** - * A radio button group container. - * - * Radio groups are used to group multiple radio buttons or radio group labels so they function as - * a single form control. The RadioGroup is meant to be used in conjunction with RadioButton - * as follows: - * - * ```html - *
        - *
        Option 1
        - *
        Option 2
        - *
        Option 3
        - *
        - * ``` - */ -@Directive({ - selector: '[ngRadioGroup]', - exportAs: 'ngRadioGroup', - host: { - 'role': 'radiogroup', - 'class': 'ng-radio-group', - '[attr.tabindex]': 'pattern.tabindex()', - '[attr.aria-readonly]': 'pattern.readonly()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[attr.aria-orientation]': 'pattern.orientation()', - '[attr.aria-activedescendant]': 'pattern.activedescendant()', - '(keydown)': 'pattern.onKeydown($event)', - '(pointerdown)': 'pattern.onPointerdown($event)', - '(focusin)': 'onFocus()', - }, - hostDirectives: [ - { - directive: ToolbarWidgetGroup, - inputs: ['disabled'], - }, - ], -}) -export class RadioGroup { - /** A reference to the radio group element. */ - private readonly _elementRef = inject(ElementRef); - - /** A reference to the ToolbarWidgetGroup, if the radio group is in a toolbar. */ - private readonly _toolbarWidgetGroup = inject(ToolbarWidgetGroup); - - /** Whether the radio group is inside of a Toolbar. */ - private readonly _hasToolbar = computed(() => !!this._toolbarWidgetGroup.toolbar()); - - /** The RadioButtons nested inside of the RadioGroup. */ - private readonly _radioButtons = contentChildren(RadioButton, {descendants: true}); - - /** A signal wrapper for directionality. */ - protected textDirection = inject(Directionality).valueSignal; - - /** The RadioButton UIPatterns of the child RadioButtons. */ - protected items = computed(() => this._radioButtons().map(radio => radio.pattern)); - - /** Whether the radio group is vertically or horizontally oriented. */ - readonly orientation = input<'vertical' | 'horizontal'>('vertical'); - - /** Whether disabled items in the group should be skipped when navigating. */ - readonly skipDisabled = input(true, {transform: booleanAttribute}); - - /** The focus strategy used by the radio group. */ - readonly focusMode = input<'roving' | 'activedescendant'>('roving'); - - /** Whether the radio group is disabled. */ - readonly disabled = input(false, {transform: booleanAttribute}); - - /** Whether the radio group is readonly. */ - readonly readonly = input(false, {transform: booleanAttribute}); - - /** The value of the currently selected radio button. */ - readonly value = model(null); - - /** The internal selection state for the radio group. */ - private readonly _value = mapSignal(this.value, { - transform: value => (value !== null ? [value] : []), - reverse: values => (values.length === 0 ? null : values[0]), - }); - - /** The RadioGroup UIPattern. */ - readonly pattern: RadioGroupPattern; - - /** Whether the radio group has received focus yet. */ - private _hasFocused = signal(false); - - constructor() { - const inputs: RadioGroupInputs | ToolbarRadioGroupInputs = { - ...this, - items: this.items, - value: this._value, - activeItem: signal(undefined), - textDirection: this.textDirection, - element: () => this._elementRef.nativeElement, - getItem: e => { - if (!(e.target instanceof HTMLElement)) { - return undefined; - } - const element = e.target.closest('[role="radio"]'); - return this.items().find(i => i.element() === element); - }, - toolbar: this._toolbarWidgetGroup.toolbar, - }; - - this.pattern = this._hasToolbar() - ? new ToolbarRadioGroupPattern(inputs as ToolbarRadioGroupInputs) - : new RadioGroupPattern(inputs as RadioGroupInputs); - - if (this._hasToolbar()) { - this._toolbarWidgetGroup.controls.set(this.pattern as ToolbarRadioGroupPattern); - } - - afterRenderEffect(() => { - if (typeof ngDevMode === 'undefined' || ngDevMode) { - const violations = this.pattern.validate(); - for (const violation of violations) { - console.error(violation); - } - } - }); - - afterRenderEffect(() => { - if (!this._hasFocused() && !this._hasToolbar()) { - this.pattern.setDefaultState(); - } - }); - } - - onFocus() { - this._hasFocused.set(true); - } -} - -/** A selectable radio button in a RadioGroup. */ -@Directive({ - selector: '[ngRadioButton]', - exportAs: 'ngRadioButton', - host: { - 'role': 'radio', - 'class': 'ng-radio-button', - '[attr.data-active]': 'pattern.active()', - '[attr.tabindex]': 'pattern.tabindex()', - '[attr.aria-checked]': 'pattern.selected()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[id]': 'pattern.id()', - }, -}) -export class RadioButton { - /** A reference to the radio button element. */ - private readonly _elementRef = inject(ElementRef); - - /** The parent RadioGroup. */ - private readonly _radioGroup = inject(RadioGroup); - - /** A unique identifier for the radio button. */ - private readonly _generatedId = inject(_IdGenerator).getId('ng-radio-button-'); - - /** A unique identifier for the radio button. */ - readonly id = computed(() => this._generatedId); - - /** The value associated with the radio button. */ - readonly value = input.required(); - - /** The parent RadioGroup UIPattern. */ - readonly group = computed(() => this._radioGroup.pattern); - - /** A reference to the radio button element to be focused on navigation. */ - element = computed(() => this._elementRef.nativeElement); - - /** Whether the radio button is disabled. */ - disabled = input(false, {transform: booleanAttribute}); - - /** The RadioButton UIPattern. */ - pattern = new RadioButtonPattern({ - ...this, - id: this.id, - value: this.value, - group: this.group, - element: this.element, - }); -} diff --git a/src/aria/tabs/BUILD.bazel b/src/aria/tabs/BUILD.bazel index 8fbfc69b87c0..13aa715fbabc 100644 --- a/src/aria/tabs/BUILD.bazel +++ b/src/aria/tabs/BUILD.bazel @@ -1,17 +1,16 @@ -load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite") +load("//tools:defaults.bzl", "extract_api_to_json", "ng_project", "ng_web_test_suite") package(default_visibility = ["//visibility:public"]) ng_project( name = "tabs", - srcs = [ - "index.ts", - "tabs.ts", - ], + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), deps = [ "//:node_modules/@angular/core", - "//src/aria/deferred-content", - "//src/aria/ui-patterns", + "//src/aria/private", "//src/cdk/a11y", "//src/cdk/bidi", ], @@ -35,3 +34,23 @@ ng_web_test_suite( name = "unit_tests", deps = [":unit_test_sources"], ) + +filegroup( + name = "source-files", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), +) + +extract_api_to_json( + name = "json_api", + srcs = [ + ":source-files", + ], + entry_point = ":index.ts", + module_name = "@angular/aria/tabs", + output_name = "aria-tabs.json", + private_modules = [""], + repo = "angular/components", +) diff --git a/src/aria/tabs/index.ts b/src/aria/tabs/index.ts index 7e81afdec8d6..52b3c7a5156f 100644 --- a/src/aria/tabs/index.ts +++ b/src/aria/tabs/index.ts @@ -6,4 +6,4 @@ * found in the LICENSE file at https://angular.dev/license */ -export {Tabs, TabList, Tab, TabPanel, TabContent} from './tabs'; +export * from './public-api'; diff --git a/src/aria/tabs/public-api.ts b/src/aria/tabs/public-api.ts new file mode 100644 index 000000000000..301245ea153e --- /dev/null +++ b/src/aria/tabs/public-api.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +export {Tabs} from './tabs'; +export {TabList} from './tab-list'; +export {Tab} from './tab'; +export {TabPanel} from './tab-panel'; +export {TabContent} from './tab-content'; + +// This needs to be re-exported, because it's used by the tab components. +// See: https://github.com/angular/components/issues/30663. +export { + DeferredContent as ɵɵDeferredContent, + DeferredContentAware as ɵɵDeferredContentAware, +} from '../private'; diff --git a/src/aria/tabs/tab-content.ts b/src/aria/tabs/tab-content.ts new file mode 100644 index 000000000000..872847e61ba9 --- /dev/null +++ b/src/aria/tabs/tab-content.ts @@ -0,0 +1,36 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Directive} from '@angular/core'; +import {DeferredContent} from '../private'; + +/** + * A TabContent container for the lazy-loaded content. + * + * This structural directive should be applied to an `ng-template` within an `ngTabPanel`. + * It enables lazy loading of the tab's content, meaning the content is only rendered + * when the tab is activated for the first time. + * + * ```html + *
        + * + *

        This content will be loaded when 'myTabId' is selected.

        + *
        + *
        + * ``` + * + * @developerPreview 21.0 + * + * @see [Tabs](guide/aria/tabs) + */ +@Directive({ + selector: 'ng-template[ngTabContent]', + exportAs: 'ngTabContent', + hostDirectives: [DeferredContent], +}) +export class TabContent {} diff --git a/src/aria/tabs/tab-list.ts b/src/aria/tabs/tab-list.ts new file mode 100644 index 000000000000..992685520f0b --- /dev/null +++ b/src/aria/tabs/tab-list.ts @@ -0,0 +1,174 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Directionality} from '@angular/cdk/bidi'; +import { + booleanAttribute, + computed, + Directive, + ElementRef, + inject, + input, + model, + signal, + afterRenderEffect, + OnInit, + OnDestroy, +} from '@angular/core'; +import {TabListPattern} from '../private'; +import {sortDirectives, TABS} from './utils'; +import type {Tab} from './tab'; + +/** + * A TabList container. + * + * The `ngTabList` directive controls a list of `ngTab` elements. It manages keyboard + * navigation, selection, and the overall orientation of the tabs. It should be placed + * within an `ngTabs` container. + * + * ```html + *
          + *
        • First Tab
        • + *
        • Second Tab
        • + *
        + * ``` + * + * @developerPreview 21.0 + * + * @see [Tabs](guide/aria/tabs) + */ +@Directive({ + selector: '[ngTabList]', + exportAs: 'ngTabList', + host: { + 'role': 'tablist', + '[attr.tabindex]': '_pattern.tabIndex()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.aria-orientation]': '_pattern.orientation()', + '[attr.aria-activedescendant]': '_pattern.activeDescendant()', + '(keydown)': '_pattern.onKeydown($event)', + '(pointerdown)': '_pattern.onPointerdown($event)', + '(focusin)': '_onFocus()', + }, +}) +export class TabList implements OnInit, OnDestroy { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The parent Tabs. */ + private readonly _tabs = inject(TABS); + + /** The Tabs nested inside of the TabList. */ + private readonly _unorderedTabs = signal(new Set()); + + /** Text direction. */ + readonly textDirection = inject(Directionality).valueSignal; + + /** The Tab UIPatterns of the child Tabs. */ + readonly _tabPatterns = computed(() => + [...this._unorderedTabs()].sort(sortDirectives).map(tab => tab._pattern), + ); + + /** Whether the tablist is vertically or horizontally oriented. */ + readonly orientation = input<'vertical' | 'horizontal'>('horizontal'); + + /** Whether focus should wrap when navigating. */ + readonly wrap = input(true, {transform: booleanAttribute}); + + /** + * Whether to allow disabled items to receive focus. When `true`, disabled items are + * focusable but not interactive. When `false`, disabled items are skipped during navigation. + */ + readonly softDisabled = input(true, {transform: booleanAttribute}); + + /** + * The focus strategy used by the tablist. + * - `roving`: Focus is moved to the active tab using `tabindex`. + * - `activedescendant`: Focus remains on the tablist container, and `aria-activedescendant` is used to indicate the active tab. + */ + readonly focusMode = input<'roving' | 'activedescendant'>('roving'); + + /** + * The selection strategy used by the tablist. + * - `follow`: The focused tab is automatically selected. + * - `explicit`: Tabs are selected explicitly by the user (e.g., via click or spacebar). + */ + readonly selectionMode = input<'follow' | 'explicit'>('follow'); + + /** The current selected tab. */ + readonly selectedTab = model(); + + /** Whether the tablist is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** The TabList UIPattern. */ + readonly _pattern: TabListPattern = new TabListPattern({ + ...this, + items: this._tabPatterns, + activeItem: signal(undefined), + element: () => this._elementRef.nativeElement, + }); + + /** Whether the tree has received focus yet. */ + private _hasFocused = signal(false); + + constructor() { + afterRenderEffect(() => { + if (!this._hasFocused()) { + this._pattern.setDefaultState(); + } + }); + + afterRenderEffect(() => { + const tab = this._pattern.selectedTab(); + if (tab) { + this.selectedTab.set(tab.value()); + } + }); + + afterRenderEffect(() => { + const value = this.selectedTab(); + if (value) { + this._tabPatterns().forEach(tab => tab.expanded.set(false)); + const tab = this._tabPatterns().find(t => t.value() === value); + this._pattern.selectedTab.set(tab); + tab?.expanded.set(true); + } + }); + } + + _onFocus() { + this._hasFocused.set(true); + } + + ngOnInit() { + this._tabs._register(this); + } + + ngOnDestroy() { + this._tabs._unregister(this); + } + + _register(child: Tab) { + this._unorderedTabs().add(child); + this._unorderedTabs.set(new Set(this._unorderedTabs())); + } + + _unregister(child: Tab) { + this._unorderedTabs().delete(child); + this._unorderedTabs.set(new Set(this._unorderedTabs())); + } + + /** Opens the tab panel with the specified value. */ + open(value: string): boolean { + return this._pattern.open(value); + } +} diff --git a/src/aria/tabs/tab-panel.ts b/src/aria/tabs/tab-panel.ts new file mode 100644 index 000000000000..31f594e7443c --- /dev/null +++ b/src/aria/tabs/tab-panel.ts @@ -0,0 +1,103 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {_IdGenerator} from '@angular/cdk/a11y'; +import { + computed, + Directive, + ElementRef, + inject, + input, + afterRenderEffect, + OnInit, + OnDestroy, +} from '@angular/core'; +import {TabPanelPattern, DeferredContentAware} from '../private'; +import {TABS} from './utils'; + +/** + * A TabPanel container for the resources of layered content associated with a tab. + * + * The `ngTabPanel` directive holds the content for a specific tab. It is linked to an + * `ngTab` by a matching `value`. If a tab panel is hidden, the `inert` attribute will be + * applied to remove it from the accessibility tree. Proper styling is required for visual hiding. + * + * ```html + *
        + * + * + * + *
        + * ``` + * + * @developerPreview 21.0 + * + * @see [Tabs](guide/aria/tabs) + */ +@Directive({ + selector: '[ngTabPanel]', + exportAs: 'ngTabPanel', + host: { + 'role': 'tabpanel', + '[attr.id]': '_pattern.id()', + '[attr.tabindex]': '_pattern.tabIndex()', + '[attr.inert]': '!visible() ? true : null', + '[attr.aria-labelledby]': '_pattern.labelledBy()', + }, + hostDirectives: [ + { + directive: DeferredContentAware, + inputs: ['preserveContent'], + }, + ], +}) +export class TabPanel implements OnInit, OnDestroy { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The DeferredContentAware host directive. */ + private readonly _deferredContentAware = inject(DeferredContentAware); + + /** The parent Tabs. */ + private readonly _tabs = inject(TABS); + + /** A global unique identifier for the tab. */ + readonly id = input(inject(_IdGenerator).getId('ng-tabpanel-', true)); + + /** The Tab UIPattern associated with the tabpanel */ + private readonly _tabPattern = computed(() => + this._tabs._tabPatterns()?.find(tab => tab.value() === this.value()), + ); + + /** A local unique identifier for the tabpanel. */ + readonly value = input.required(); + + /** Whether the tab panel is visible. */ + readonly visible = computed(() => !this._pattern.hidden()); + + /** The TabPanel UIPattern. */ + readonly _pattern: TabPanelPattern = new TabPanelPattern({ + ...this, + tab: this._tabPattern, + }); + + constructor() { + afterRenderEffect(() => this._deferredContentAware.contentVisible.set(this.visible())); + } + + ngOnInit() { + this._tabs._register(this); + } + + ngOnDestroy() { + this._tabs._unregister(this); + } +} diff --git a/src/aria/tabs/tab.ts b/src/aria/tabs/tab.ts new file mode 100644 index 000000000000..fcc6c07a5763 --- /dev/null +++ b/src/aria/tabs/tab.ts @@ -0,0 +1,111 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {_IdGenerator} from '@angular/cdk/a11y'; +import { + booleanAttribute, + computed, + Directive, + ElementRef, + inject, + input, + signal, + OnInit, + OnDestroy, +} from '@angular/core'; +import {TabPattern} from '../private'; +import {TabList} from './tab-list'; +import {HasElement, TABS} from './utils'; + +/** + * A selectable tab in a TabList. + * + * The `ngTab` directive represents an individual tab control within an `ngTabList`. It + * requires a `value` that uniquely identifies it and links it to a corresponding `ngTabPanel`. + * + * ```html + *
      • + * My Tab Label + *
      • + * ``` + * + * @developerPreview 21.0 + * + * @see [Tabs](guide/aria/tabs) + */ +@Directive({ + selector: '[ngTab]', + exportAs: 'ngTab', + host: { + 'role': 'tab', + '[attr.data-active]': 'active()', + '[attr.id]': '_pattern.id()', + '[attr.tabindex]': '_pattern.tabIndex()', + '[attr.aria-selected]': 'selected()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.aria-controls]': '_pattern.controls()', + }, +}) +export class Tab implements HasElement, OnInit, OnDestroy { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The parent Tabs. */ + private readonly _tabs = inject(TABS); + + /** The parent TabList. */ + private readonly _tabList = inject(TabList); + + /** A unique identifier for the widget. */ + readonly id = input(inject(_IdGenerator).getId('ng-tab-', true)); + + /** The parent TabList UIPattern. */ + private readonly _tablistPattern = computed(() => this._tabList._pattern); + + /** The TabPanel UIPattern associated with the tab */ + private readonly _tabpanelPattern = computed(() => + this._tabs._unorderedTabpanelPatterns().find(tabpanel => tabpanel.value() === this.value()), + ); + + /** Whether a tab is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** The remote tabpanel unique identifier. */ + readonly value = input.required(); + + /** Whether the tab is active. */ + readonly active = computed(() => this._pattern.active()); + + /** Whether the tab is selected. */ + readonly selected = computed(() => this._pattern.selected()); + + /** The Tab UIPattern. */ + readonly _pattern: TabPattern = new TabPattern({ + ...this, + tablist: this._tablistPattern, + tabpanel: this._tabpanelPattern, + expanded: signal(false), + element: () => this.element, + }); + + /** Opens this tab panel. */ + open() { + this._pattern.open(); + } + + ngOnInit() { + this._tabList._register(this); + } + + ngOnDestroy() { + this._tabList._unregister(this); + } +} diff --git a/src/aria/tabs/tabs.spec.ts b/src/aria/tabs/tabs.spec.ts index d7a7d7367a34..8ac9ed40301d 100644 --- a/src/aria/tabs/tabs.spec.ts +++ b/src/aria/tabs/tabs.spec.ts @@ -3,7 +3,11 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Direction} from '@angular/cdk/bidi'; import {provideFakeDirectionality, runAccessibilityChecks} from '@angular/cdk/testing/private'; -import {Tabs, TabList, Tab, TabPanel, TabContent} from './tabs'; +import {Tabs} from './tabs'; +import {TabList} from './tab-list'; +import {Tab} from './tab'; +import {TabPanel} from './tab-panel'; +import {TabContent} from './tab-content'; interface ModifierKeys { ctrlKey?: boolean; @@ -79,7 +83,7 @@ describe('Tabs', () => { orientation?: 'horizontal' | 'vertical'; disabled?: boolean; wrap?: boolean; - skipDisabled?: boolean; + softDisabled?: boolean; focusMode?: 'roving' | 'activedescendant'; selectionMode?: 'follow' | 'explicit'; } = {}, @@ -89,7 +93,7 @@ describe('Tabs', () => { if (options.orientation !== undefined) testComponent.orientation.set(options.orientation); if (options.disabled !== undefined) testComponent.disabled.set(options.disabled); if (options.wrap !== undefined) testComponent.wrap.set(options.wrap); - if (options.skipDisabled !== undefined) testComponent.skipDisabled.set(options.skipDisabled); + if (options.softDisabled !== undefined) testComponent.softDisabled.set(options.softDisabled); if (options.focusMode !== undefined) testComponent.focusMode.set(options.focusMode); if (options.selectionMode !== undefined) testComponent.selectionMode.set(options.selectionMode); @@ -273,12 +277,12 @@ describe('Tabs', () => { it('should move focus with ArrowRight', () => { expect(isTabFocused(0)).toBe(true); right(); - expect(isTabFocused(2)).toBe(true); + expect(isTabFocused(1)).toBe(true); }); it('should move focus with ArrowLeft', () => { right(); - expect(isTabFocused(2)).toBe(true); + expect(isTabFocused(1)).toBe(true); left(); expect(isTabFocused(0)).toBe(true); }); @@ -286,6 +290,8 @@ describe('Tabs', () => { it('should wrap focus with ArrowRight if wrap is true', () => { updateTabs({wrap: true}); right(); + expect(isTabFocused(1)).toBe(true); + right(); expect(isTabFocused(2)).toBe(true); right(); expect(isTabFocused(0)).toBe(true); @@ -294,6 +300,8 @@ describe('Tabs', () => { it('should not wrap focus with ArrowRight if wrap is false', () => { updateTabs({wrap: false}); right(); + expect(isTabFocused(1)).toBe(true); + right(); expect(isTabFocused(2)).toBe(true); right(); expect(isTabFocused(2)).toBe(true); @@ -326,15 +334,15 @@ describe('Tabs', () => { expect(isTabFocused(2)).toBe(true); }); - it('should skip disabled tabs if skipDisabled is true', () => { - updateTabs({skipDisabled: true}); + it('should skip disabled tabs if softDisabled is false', () => { + updateTabs({softDisabled: false}); expect(isTabFocused(0)).toBe(true); right(); expect(isTabFocused(2)).toBe(true); }); - it('should not skip disabled tabs if skipDisabled is false', () => { - updateTabs({skipDisabled: false}); + it('should not skip disabled tabs if softDisabled is true', () => { + updateTabs({softDisabled: true}); tabListElement.focus(); fixture.detectChanges(); expect(isTabFocused(0)).toBe(true); @@ -359,12 +367,12 @@ describe('Tabs', () => { it('should move focus with ArrowLeft (effectively next)', () => { expect(isTabFocused(0)).toBe(true); left(); - expect(isTabFocused(2)).toBe(true); + expect(isTabFocused(1)).toBe(true); }); it('should move focus with ArrowRight (effectively previous)', () => { left(); - expect(isTabFocused(2)).toBe(true); + expect(isTabFocused(1)).toBe(true); right(); expect(isTabFocused(0)).toBe(true); }); @@ -372,6 +380,9 @@ describe('Tabs', () => { it('should wrap focus with ArrowLeft if wrap is true', () => { updateTabs({wrap: true}); left(); + expect(isTabFocused(1)).toBe(true); + left(); + expect(isTabFocused(2)).toBe(true); left(); expect(isTabFocused(0)).toBe(true); }); @@ -402,12 +413,12 @@ describe('Tabs', () => { it('should move focus with ArrowDown', () => { expect(isTabFocused(0)).toBe(true); down(); - expect(isTabFocused(2)).toBe(true); + expect(isTabFocused(1)).toBe(true); }); it('should move focus with ArrowUp', () => { down(); - expect(isTabFocused(2)).toBe(true); + expect(isTabFocused(1)).toBe(true); up(); expect(isTabFocused(0)).toBe(true); }); @@ -415,6 +426,8 @@ describe('Tabs', () => { it('should wrap focus with ArrowDown if wrap is true', () => { updateTabs({wrap: true}); down(); + expect(isTabFocused(1)).toBe(true); + down(); expect(isTabFocused(2)).toBe(true); down(); expect(isTabFocused(0)).toBe(true); @@ -423,6 +436,8 @@ describe('Tabs', () => { it('should not wrap focus with ArrowDown if wrap is false', () => { updateTabs({wrap: false}); down(); + expect(isTabFocused(1)).toBe(true); + down(); expect(isTabFocused(2)).toBe(true); down(); expect(isTabFocused(2)).toBe(true); @@ -443,7 +458,7 @@ describe('Tabs', () => { }); it('should move focus to first tab with Home', () => { - down(); + end(); expect(isTabFocused(2)).toBe(true); home(); expect(isTabFocused(0)).toBe(true); @@ -644,7 +659,7 @@ describe('Tabs', () => { ], selectedTab: 'tab1', selectionMode: 'explicit', - skipDisabled: false, + softDisabled: true, }); expect(testComponent.selectedTab()).toBe('tab1'); right(); @@ -669,6 +684,28 @@ describe('Tabs', () => { expect(tabElements[1].getAttribute('aria-selected')).toBe('true'); expect(tabElements[0].getAttribute('aria-selected')).toBe('false'); }); + + it('should allow programmatic selection even if disabled', () => { + updateTabs({disabled: true}); + + expect(tabElements[0].getAttribute('aria-selected')).toBe('true'); + expect(tabElements[1].getAttribute('aria-selected')).toBe('false'); + expect(tabElements[2].getAttribute('aria-selected')).toBe('false'); + + expect(tabPanelElements[0].hasAttribute('inert')).toBe(false); + expect(tabPanelElements[1].hasAttribute('inert')).toBe(true); + expect(tabPanelElements[2].hasAttribute('inert')).toBe(true); + + updateTabs({selectedTab: 'tab2'}); + + expect(tabElements[0].getAttribute('aria-selected')).toBe('false'); + expect(tabElements[1].getAttribute('aria-selected')).toBe('true'); + expect(tabElements[2].getAttribute('aria-selected')).toBe('false'); + + expect(tabPanelElements[0].hasAttribute('inert')).toBe(true); + expect(tabPanelElements[1].hasAttribute('inert')).toBe(false); + expect(tabPanelElements[2].hasAttribute('inert')).toBe(true); + }); }); }); @@ -680,7 +717,7 @@ describe('Tabs', () => { [orientation]="orientation()" [disabled]="disabled()" [wrap]="wrap()" - [skipDisabled]="skipDisabled()" + [softDisabled]="softDisabled()" [focusMode]="focusMode()" [selectionMode]="selectionMode()"> @for (tabDef of tabsData(); track tabDef.value) { @@ -723,7 +760,7 @@ class TestTabsComponent { orientation = signal<'horizontal' | 'vertical'>('horizontal'); disabled = signal(false); wrap = signal(true); - skipDisabled = signal(true); + softDisabled = signal(true); focusMode = signal<'roving' | 'activedescendant'>('roving'); selectionMode = signal<'follow' | 'explicit'>('follow'); } diff --git a/src/aria/tabs/tabs.ts b/src/aria/tabs/tabs.ts index 537e685406ed..481906a1d8af 100644 --- a/src/aria/tabs/tabs.ts +++ b/src/aria/tabs/tabs.ts @@ -6,72 +6,54 @@ * found in the LICENSE file at https://angular.dev/license */ -import {DeferredContent, DeferredContentAware} from '@angular/aria/deferred-content'; -import {_IdGenerator} from '@angular/cdk/a11y'; -import {Directionality} from '@angular/cdk/bidi'; -import { - booleanAttribute, - computed, - Directive, - ElementRef, - inject, - input, - model, - linkedSignal, - signal, - Signal, - afterRenderEffect, - OnInit, - OnDestroy, -} from '@angular/core'; -import {TabListPattern, TabPanelPattern, TabPattern} from '@angular/aria/ui-patterns'; - -interface HasElement { - element: Signal; -} - -/** - * Sort directives by their document order. - */ -function sortDirectives(a: HasElement, b: HasElement) { - return (a.element().compareDocumentPosition(b.element()) & Node.DOCUMENT_POSITION_PRECEDING) > 0 - ? 1 - : -1; -} +import {computed, Directive, ElementRef, inject, signal} from '@angular/core'; +import {TabList} from './tab-list'; +import {TabPanel} from './tab-panel'; +import {TABS} from './utils'; /** * A Tabs container. * - * Represents a set of layered sections of content. The Tabs is a container meant to be used with - * TabList, Tab, and TabPanel as follows: + * The `ngTabs` directive represents a set of layered sections of content. It acts as the + * overarching container for a tabbed interface, coordinating the behavior of `ngTabList`, + * `ngTab`, and `ngTabPanel` directives. * * ```html *
        - *
          + *
            *
          • Tab 1
          • *
          • Tab 2
          • *
          • Tab 3
          • *
          * *
          - * Tab content 1 + * Content for Tab 1 *
          *
          - * Tab content 2 + * Content for Tab 2 *
          *
          - * Tab content 3 + * Content for Tab 3 *
          + *
        * ``` + * + * @developerPreview 21.0 + * + * @see [Tabs](guide/aria/tabs) */ @Directive({ selector: '[ngTabs]', exportAs: 'ngTabs', - host: { - 'class': 'ng-tabs', - }, + providers: [{provide: TABS, useExisting: Tabs}], }) export class Tabs { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + /** The TabList nested inside of the container. */ private readonly _tablist = signal(undefined); @@ -79,14 +61,14 @@ export class Tabs { private readonly _unorderedPanels = signal(new Set()); /** The Tab UIPattern of the child Tabs. */ - tabs = computed(() => this._tablist()?.tabs()); + readonly _tabPatterns = computed(() => this._tablist()?._tabPatterns()); /** The TabPanel UIPattern of the child TabPanels. */ - unorderedTabpanels = computed(() => - [...this._unorderedPanels()].map(tabpanel => tabpanel.pattern), + readonly _unorderedTabpanelPatterns = computed(() => + [...this._unorderedPanels()].map(tabpanel => tabpanel._pattern), ); - register(child: TabList | TabPanel) { + _register(child: TabList | TabPanel) { if (child instanceof TabList) { this._tablist.set(child); } @@ -97,7 +79,7 @@ export class Tabs { } } - deregister(child: TabList | TabPanel) { + _unregister(child: TabList | TabPanel) { if (child instanceof TabList) { this._tablist.set(undefined); } @@ -108,247 +90,3 @@ export class Tabs { } } } - -/** - * A TabList container. - * - * Controls a list of Tab(s). - */ -@Directive({ - selector: '[ngTabList]', - exportAs: 'ngTabList', - host: { - 'role': 'tablist', - 'class': 'ng-tablist', - '[attr.tabindex]': 'pattern.tabindex()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[attr.aria-orientation]': 'pattern.orientation()', - '[attr.aria-activedescendant]': 'pattern.activedescendant()', - '(keydown)': 'pattern.onKeydown($event)', - '(pointerdown)': 'pattern.onPointerdown($event)', - '(focusin)': 'onFocus()', - }, -}) -export class TabList implements OnInit, OnDestroy { - /** A reference to the tab list element. */ - private readonly _elementRef = inject(ElementRef); - - /** The parent Tabs. */ - private readonly _tabs = inject(Tabs); - - /** The Tabs nested inside of the TabList. */ - private readonly _unorderedTabs = signal(new Set()); - - /** The internal tab selection state. */ - private readonly _selection = linkedSignal(() => - this.selectedTab() ? [this.selectedTab()!] : [], - ); - - /** Text direction. */ - readonly textDirection = inject(Directionality).valueSignal; - - /** The Tab UIPatterns of the child Tabs. */ - readonly tabs = computed(() => - [...this._unorderedTabs()].sort(sortDirectives).map(tab => tab.pattern), - ); - - /** Whether the tablist is vertically or horizontally oriented. */ - readonly orientation = input<'vertical' | 'horizontal'>('horizontal'); - - /** Whether focus should wrap when navigating. */ - readonly wrap = input(true, {transform: booleanAttribute}); - - /** Whether disabled items in the list should be skipped when navigating. */ - readonly skipDisabled = input(true, {transform: booleanAttribute}); - - /** The focus strategy used by the tablist. */ - readonly focusMode = input<'roving' | 'activedescendant'>('roving'); - - /** The selection strategy used by the tablist. */ - readonly selectionMode = input<'follow' | 'explicit'>('follow'); - - /** Whether the tablist is disabled. */ - readonly disabled = input(false, {transform: booleanAttribute}); - - /** The current selected tab. */ - readonly selectedTab = model(); - - /** The TabList UIPattern. */ - readonly pattern: TabListPattern = new TabListPattern({ - ...this, - items: this.tabs, - value: this._selection, - activeItem: signal(undefined), - element: () => this._elementRef.nativeElement, - }); - - /** Whether the tree has received focus yet. */ - private _hasFocused = signal(false); - - constructor() { - afterRenderEffect(() => this.selectedTab.set(this._selection()[0])); - - afterRenderEffect(() => { - if (!this._hasFocused()) { - this.pattern.setDefaultState(); - } - }); - } - - onFocus() { - this._hasFocused.set(true); - } - - ngOnInit() { - this._tabs.register(this); - } - - ngOnDestroy() { - this._tabs.deregister(this); - } - - register(child: Tab) { - this._unorderedTabs().add(child); - this._unorderedTabs.set(new Set(this._unorderedTabs())); - } - - deregister(child: Tab) { - this._unorderedTabs().delete(child); - this._unorderedTabs.set(new Set(this._unorderedTabs())); - } -} - -/** A selectable tab in a TabList. */ -@Directive({ - selector: '[ngTab]', - exportAs: 'ngTab', - host: { - 'role': 'tab', - 'class': 'ng-tab', - '[attr.data-active]': 'pattern.active()', - '[attr.id]': 'pattern.id()', - '[attr.tabindex]': 'pattern.tabindex()', - '[attr.aria-selected]': 'pattern.selected()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[attr.aria-controls]': 'pattern.controls()', - }, -}) -export class Tab implements HasElement, OnInit, OnDestroy { - /** A reference to the tab element. */ - private readonly _elementRef = inject(ElementRef); - - /** The parent Tabs. */ - private readonly _tabs = inject(Tabs); - - /** The parent TabList. */ - private readonly _tabList = inject(TabList); - - /** A global unique identifier for the tab. */ - private readonly _id = inject(_IdGenerator).getId('ng-tab-'); - - /** The host native element. */ - readonly element = computed(() => this._elementRef.nativeElement); - - /** The parent TabList UIPattern. */ - readonly tablist = computed(() => this._tabList.pattern); - - /** The TabPanel UIPattern associated with the tab */ - readonly tabpanel = computed(() => - this._tabs.unorderedTabpanels().find(tabpanel => tabpanel.value() === this.value()), - ); - - /** Whether a tab is disabled. */ - readonly disabled = input(false, {transform: booleanAttribute}); - - /** A local unique identifier for the tab. */ - readonly value = input.required(); - - /** The Tab UIPattern. */ - readonly pattern: TabPattern = new TabPattern({ - ...this, - id: () => this._id, - tablist: this.tablist, - tabpanel: this.tabpanel, - value: this.value, - }); - - ngOnInit() { - this._tabList.register(this); - } - - ngOnDestroy() { - this._tabList.deregister(this); - } -} - -/** - * A TabPanel container for the resources of layered content associated with a tab. - * - * If a tabpanel is hidden due to its corresponding tab is not activated, the `inert` attribute - * will be applied to the tabpanel element to remove it from the accessibility tree and stop - * all the keyboard and pointer interactions. Note that this does not visually hide the tabpenl - * and a proper styling is required. - */ -@Directive({ - selector: '[ngTabPanel]', - exportAs: 'ngTabPanel', - host: { - 'role': 'tabpanel', - 'class': 'ng-tabpanel', - '[attr.id]': 'pattern.id()', - '[attr.tabindex]': 'pattern.tabindex()', - '[attr.inert]': 'pattern.hidden() ? true : null', - '[attr.aria-labelledby]': 'pattern.labelledBy()', - }, - hostDirectives: [ - { - directive: DeferredContentAware, - inputs: ['preserveContent'], - }, - ], -}) -export class TabPanel implements OnInit, OnDestroy { - /** The DeferredContentAware host directive. */ - private readonly _deferredContentAware = inject(DeferredContentAware); - - /** The parent Tabs. */ - private readonly _Tabs = inject(Tabs); - - /** A global unique identifier for the tab. */ - private readonly _id = inject(_IdGenerator).getId('ng-tabpanel-'); - - /** The Tab UIPattern associated with the tabpanel */ - readonly tab = computed(() => this._Tabs.tabs()?.find(tab => tab.value() === this.value())); - - /** A local unique identifier for the tabpanel. */ - readonly value = input.required(); - - /** The TabPanel UIPattern. */ - readonly pattern: TabPanelPattern = new TabPanelPattern({ - ...this, - id: () => this._id, - tab: this.tab, - }); - - constructor() { - afterRenderEffect(() => this._deferredContentAware.contentVisible.set(!this.pattern.hidden())); - } - - ngOnInit() { - this._Tabs.register(this); - } - - ngOnDestroy() { - this._Tabs.deregister(this); - } -} - -/** - * A TabContent container for the lazy-loaded content. - */ -@Directive({ - selector: 'ng-template[ngTabContent]', - exportAs: 'ngTabContent', - hostDirectives: [DeferredContent], -}) -export class TabContent {} diff --git a/src/aria/tabs/utils.ts b/src/aria/tabs/utils.ts new file mode 100644 index 000000000000..8a00da60c027 --- /dev/null +++ b/src/aria/tabs/utils.ts @@ -0,0 +1,26 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {InjectionToken} from '@angular/core'; +import type {Tabs} from './tabs'; + +/** Token used to expose the `Tabs` directive to child directives. */ +export const TABS = new InjectionToken('TABS'); + +export interface HasElement { + element: HTMLElement; +} + +/** + * Sort directives by their document order. + */ +export function sortDirectives(a: HasElement, b: HasElement) { + return (a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_PRECEDING) > 0 + ? 1 + : -1; +} diff --git a/src/aria/toolbar/BUILD.bazel b/src/aria/toolbar/BUILD.bazel index adca3e19b5ea..7516f3def5c0 100644 --- a/src/aria/toolbar/BUILD.bazel +++ b/src/aria/toolbar/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite", "ts_project") +load("//tools:defaults.bzl", "extract_api_to_json", "ng_project", "ng_web_test_suite", "ts_project") package(default_visibility = ["//visibility:public"]) @@ -10,7 +10,7 @@ ng_project( ), deps = [ "//:node_modules/@angular/core", - "//src/aria/ui-patterns", + "//src/aria/private", "//src/cdk/a11y", "//src/cdk/bidi", ], @@ -34,3 +34,23 @@ ng_web_test_suite( name = "unit_tests", deps = [":unit_test_sources"], ) + +filegroup( + name = "source-files", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), +) + +extract_api_to_json( + name = "json_api", + srcs = [ + ":source-files", + ], + entry_point = ":index.ts", + module_name = "@angular/aria/toolbar", + output_name = "aria-toolbar.json", + private_modules = [""], + repo = "angular/components", +) diff --git a/src/aria/toolbar/index.ts b/src/aria/toolbar/index.ts index 9cb6bc9fb4ee..52b3c7a5156f 100644 --- a/src/aria/toolbar/index.ts +++ b/src/aria/toolbar/index.ts @@ -6,4 +6,4 @@ * found in the LICENSE file at https://angular.dev/license */ -export {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from './toolbar'; +export * from './public-api'; diff --git a/src/aria/radio-group/index.ts b/src/aria/toolbar/public-api.ts similarity index 58% rename from src/aria/radio-group/index.ts rename to src/aria/toolbar/public-api.ts index 34aab88aafe3..50f6e9f89f84 100644 --- a/src/aria/radio-group/index.ts +++ b/src/aria/toolbar/public-api.ts @@ -6,4 +6,6 @@ * found in the LICENSE file at https://angular.dev/license */ -export {RadioGroup, RadioButton} from './radio-group'; +export {Toolbar} from './toolbar'; +export {ToolbarWidget} from './toolbar-widget'; +export {ToolbarWidgetGroup} from './toolbar-widget-group'; diff --git a/src/aria/toolbar/toolbar-widget-group.ts b/src/aria/toolbar/toolbar-widget-group.ts new file mode 100644 index 000000000000..01a76ec848cd --- /dev/null +++ b/src/aria/toolbar/toolbar-widget-group.ts @@ -0,0 +1,67 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Directive, + ElementRef, + inject, + computed, + input, + booleanAttribute, + contentChildren, +} from '@angular/core'; +import {ToolbarWidgetPattern, ToolbarWidgetGroupPattern} from '../private'; +import {Toolbar} from './toolbar'; +import {ToolbarWidget} from './toolbar-widget'; +import {TOOLBAR_WIDGET_GROUP} from './utils'; + +/** + * A directive that groups toolbar widgets, used for more complex widgets like radio groups + * that have their own internal navigation. + * + * @developerPreview 21.0 + * + * @see [Toolbar](guide/aria/toolbar) + */ +@Directive({ + selector: '[ngToolbarWidgetGroup]', + exportAs: 'ngToolbarWidgetGroup', + providers: [{provide: TOOLBAR_WIDGET_GROUP, useExisting: ToolbarWidgetGroup}], +}) +export class ToolbarWidgetGroup { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The parent Toolbar. */ + private readonly _toolbar = inject>(Toolbar, {optional: true}); + + /** The list of child widgets within the group. */ + private readonly _widgets = contentChildren(ToolbarWidget, {descendants: true}); + + /** The parent Toolbar UIPattern. */ + private readonly _toolbarPattern = computed(() => this._toolbar?._pattern); + + /** Whether the widget group is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** The list of toolbar items within the group. */ + private readonly _itemPatterns = () => this._widgets().map(w => w._pattern); + + /** Whether the group allows multiple widgets to be selected. */ + readonly multi = input(false, {transform: booleanAttribute}); + + /** The ToolbarWidgetGroup UIPattern. */ + readonly _pattern = new ToolbarWidgetGroupPattern, V>({ + ...this, + items: this._itemPatterns, + toolbar: this._toolbarPattern, + }); +} diff --git a/src/aria/toolbar/toolbar-widget.ts b/src/aria/toolbar/toolbar-widget.ts new file mode 100644 index 000000000000..c01976e8f51b --- /dev/null +++ b/src/aria/toolbar/toolbar-widget.ts @@ -0,0 +1,109 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Directive, + ElementRef, + inject, + computed, + input, + booleanAttribute, + OnInit, + OnDestroy, +} from '@angular/core'; +import {ToolbarWidgetPattern, ToolbarWidgetGroupPattern, SignalLike} from '../private'; +import {_IdGenerator} from '@angular/cdk/a11y'; +import {Toolbar} from './toolbar'; +import {TOOLBAR_WIDGET_GROUP} from './utils'; +import type {ToolbarWidgetGroup} from './toolbar-widget-group'; + +/** + * A widget within a toolbar. + * + * The `ngToolbarWidget` directive should be applied to any native HTML element that acts + * as an interactive widget within an `ngToolbar` or `ngToolbarWidgetGroup`. It enables + * keyboard navigation and selection within the toolbar. + * + * ```html + * + * ``` + * + * @developerPreview 21.0 + * + * @see [Toolbar](guide/aria/toolbar) + */ +@Directive({ + selector: '[ngToolbarWidget]', + exportAs: 'ngToolbarWidget', + host: { + '[attr.data-active]': 'active()', + '[attr.tabindex]': '_pattern.tabIndex()', + '[attr.inert]': 'hardDisabled() ? true : null', + '[attr.disabled]': 'hardDisabled() ? true : null', + '[attr.aria-disabled]': '_pattern.disabled()', + '[id]': '_pattern.id()', + }, +}) +export class ToolbarWidget implements OnInit, OnDestroy { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The parent Toolbar. */ + private readonly _toolbar = inject>(Toolbar); + + /** A unique identifier for the widget. */ + readonly id = input(inject(_IdGenerator).getId('ng-toolbar-widget-', true)); + + /** The parent Toolbar UIPattern. */ + readonly _toolbarPattern = computed(() => this._toolbar._pattern); + + /** Whether the widget is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** Whether the widget is 'hard' disabled, which is different from `aria-disabled`. A hard disabled widget cannot receive focus. */ + readonly hardDisabled = computed(() => this._pattern.disabled() && !this._toolbar.softDisabled()); + + /** The optional ToolbarWidgetGroup this widget belongs to. */ + readonly _group = inject>(TOOLBAR_WIDGET_GROUP, {optional: true}); + + /** The value associated with the widget. */ + readonly value = input.required(); + + /** Whether the widget is currently active (focused). */ + readonly active = computed(() => this._pattern.active()); + + /** Whether the widget is selected (only relevant in a selection group). */ + readonly selected = () => this._pattern.selected(); + + private readonly _groupPattern: SignalLike< + ToolbarWidgetGroupPattern, V> | undefined + > = () => this._group?._pattern; + + /** The ToolbarWidget UIPattern. */ + readonly _pattern = new ToolbarWidgetPattern({ + ...this, + group: this._groupPattern, + toolbar: this._toolbarPattern, + id: this.id, + value: this.value, + element: () => this.element, + }); + + ngOnInit() { + this._toolbar._register(this); + } + + ngOnDestroy() { + this._toolbar._unregister(this); + } +} diff --git a/src/aria/toolbar/toolbar.spec.ts b/src/aria/toolbar/toolbar.spec.ts index c6685baba582..26c246a9351a 100644 --- a/src/aria/toolbar/toolbar.spec.ts +++ b/src/aria/toolbar/toolbar.spec.ts @@ -1,55 +1,70 @@ -import {Component, inject, signal} from '@angular/core'; +import {Component, DebugElement, Directive, inject, signal} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {Direction} from '@angular/cdk/bidi'; -import {provideFakeDirectionality} from '@angular/cdk/testing/private'; -import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from './toolbar'; - -interface ModifierKeys { - ctrlKey?: boolean; - shiftKey?: boolean; - altKey?: boolean; - metaKey?: boolean; -} +import {provideFakeDirectionality, runAccessibilityChecks} from '@angular/cdk/testing/private'; +import {Toolbar} from './toolbar'; +import {ToolbarWidgetGroup} from './toolbar-widget-group'; +import {ToolbarWidget} from './toolbar-widget'; describe('Toolbar', () => { - let fixture: ComponentFixture; - let testComponent: TestToolbarComponent; + let fixture: ComponentFixture; let toolbarElement: HTMLElement; - let widgetElements: HTMLElement[]; - let testWidgetGroupInstance: TestToolbarWidgetGroup; - const keydown = (key: string, modifierKeys: ModifierKeys = {}) => { - const event = new KeyboardEvent('keydown', {key, bubbles: true, ...modifierKeys}); - toolbarElement.dispatchEvent(event); + const keydown = (key: string, target?: HTMLElement, modifierKeys: {} = {}) => { + const eventTarget = target || toolbarElement; + eventTarget.dispatchEvent( + new KeyboardEvent('keydown', { + key, + bubbles: true, + ...modifierKeys, + }), + ); fixture.detectChanges(); - defineTestVariables(); }; - const pointerDown = (target: HTMLElement, eventInit: PointerEventInit = {}) => { - target.dispatchEvent(new PointerEvent('pointerdown', {bubbles: true, ...eventInit})); + const click = (element: HTMLElement, eventInit?: PointerEventInit) => { + element.dispatchEvent(new PointerEvent('click', {bubbles: true, ...eventInit})); fixture.detectChanges(); - defineTestVariables(); }; - const up = (modifierKeys?: ModifierKeys) => keydown('ArrowUp', modifierKeys); - const down = (modifierKeys?: ModifierKeys) => keydown('ArrowDown', modifierKeys); - const left = (modifierKeys?: ModifierKeys) => keydown('ArrowLeft', modifierKeys); - const right = (modifierKeys?: ModifierKeys) => keydown('ArrowRight', modifierKeys); - const home = (modifierKeys?: ModifierKeys) => keydown('Home', modifierKeys); - const end = (modifierKeys?: ModifierKeys) => keydown('End', modifierKeys); - const enter = (modifierKeys?: ModifierKeys) => keydown('Enter', modifierKeys); - const space = (modifierKeys?: ModifierKeys) => keydown(' ', modifierKeys); - const click = (target: HTMLElement) => pointerDown(target); - - function setupTestToolbar(textDirection: Direction = 'ltr') { + const right = (target?: HTMLElement, modifierKeys?: {}) => + keydown('ArrowRight', target, modifierKeys); + const left = (target?: HTMLElement, modifierKeys?: {}) => + keydown('ArrowLeft', target, modifierKeys); + const up = (target?: HTMLElement, modifierKeys?: {}) => keydown('ArrowUp', target, modifierKeys); + const down = (target?: HTMLElement, modifierKeys?: {}) => + keydown('ArrowDown', target, modifierKeys); + const home = (target?: HTMLElement, modifierKeys?: {}) => keydown('Home', target, modifierKeys); + const end = (target?: HTMLElement, modifierKeys?: {}) => keydown('End', target, modifierKeys); + + function setupToolbar( + opts: { + orientation?: 'vertical' | 'horizontal'; + softDisabled?: boolean; + disabled?: boolean; + wrap?: boolean; + textDirection?: 'ltr' | 'rtl'; + } = {}, + ) { TestBed.configureTestingModule({ - imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup, TestToolbarComponent], - providers: [provideFakeDirectionality(textDirection)], + imports: [ToolbarExample], + providers: [provideFakeDirectionality(opts?.textDirection ?? 'ltr')], }); - - fixture = TestBed.createComponent(TestToolbarComponent); - testComponent = fixture.componentInstance; + fixture = TestBed.createComponent(ToolbarExample); + const testComponent = fixture.componentInstance as ToolbarExample; + + if (opts.orientation) { + testComponent.orientation.set(opts.orientation); + } + if (opts.softDisabled !== undefined) { + testComponent.softDisabled.set(opts.softDisabled); + } + if (opts.disabled !== undefined) { + testComponent.disabled.set(opts.disabled); + } + if (opts.wrap !== undefined) { + testComponent.wrap.set(opts.wrap); + } fixture.detectChanges(); defineTestVariables(); @@ -57,421 +72,643 @@ describe('Toolbar', () => { function defineTestVariables() { const toolbarDebugElement = fixture.debugElement.query(By.directive(Toolbar)); - const widgetDebugElements = fixture.debugElement.queryAll(By.css('[data-value="widget"]')); - const testWidgetGroupElement = fixture.debugElement.query(By.directive(TestToolbarWidgetGroup)); - toolbarElement = toolbarDebugElement.nativeElement as HTMLElement; - widgetElements = widgetDebugElements.map(debugEl => debugEl.nativeElement); - testWidgetGroupInstance = testWidgetGroupElement.componentInstance as TestToolbarWidgetGroup; } - function updateToolbar( - config: { - disabled?: boolean; - widgetGroupDisabled?: boolean; - orientation?: 'horizontal' | 'vertical'; - wrap?: boolean; - skipDisabled?: boolean; - } = {}, - ) { - if (config.disabled !== undefined) testComponent.disabled.set(config.disabled); - if (config.widgetGroupDisabled !== undefined) - testComponent.widgetGroupDisabled.set(config.widgetGroupDisabled); - if (config.orientation !== undefined) testComponent.orientation.set(config.orientation); - if (config.wrap !== undefined) testComponent.wrap.set(config.wrap); - if (config.skipDisabled !== undefined) testComponent.skipDisabled.set(config.skipDisabled); - - fixture.detectChanges(); - defineTestVariables(); + function getWidgetEl(text: string): HTMLElement | null { + const widgets = getWidgetEls(); + return widgets.find(widget => widget.textContent?.trim() === text) || null; } - describe('ARIA attributes and roles', () => { - describe('default configuration', () => { - beforeEach(() => { - setupTestToolbar(); - }); - - it('should correctly set the role attribute to "toolbar" for Toolbar', () => { - expect(toolbarElement.getAttribute('role')).toBe('toolbar'); - }); - - it('should set aria-orientation to "horizontal" by default', () => { - expect(toolbarElement.getAttribute('aria-orientation')).toBe('horizontal'); - }); - - it('should set aria-disabled to "false" by default for the toolbar', () => { - expect(toolbarElement.getAttribute('aria-disabled')).toBe('false'); - }); - - it('should set aria-disabled to "false" by default for widgets', () => { - expect(widgetElements[0].getAttribute('aria-disabled')).toBe('false'); - expect(widgetElements[1].getAttribute('aria-disabled')).toBe('true'); - expect(widgetElements[2].getAttribute('aria-disabled')).toBe('false'); - }); - - it('should set initial focus (tabindex="0") on the first non-disabled widget', () => { - expect(widgetElements[0].getAttribute('tabindex')).toBe('0'); - expect(widgetElements[1].getAttribute('tabindex')).toBe('-1'); - expect(widgetElements[2].getAttribute('tabindex')).toBe('-1'); - }); - - it('should not have aria-activedescendant by default', () => { - expect(toolbarElement.hasAttribute('aria-activedescendant')).toBe(false); - }); - }); - - describe('custom configuration', () => { - beforeEach(() => { - setupTestToolbar(); - }); - - it('should set aria-orientation to "vertical"', () => { - updateToolbar({orientation: 'vertical'}); - expect(toolbarElement.getAttribute('aria-orientation')).toBe('vertical'); - }); + function getWidgetEls(): HTMLElement[] { + return fixture.debugElement + .queryAll(By.directive(ToolbarWidget)) + .map((debugEl: DebugElement) => debugEl.nativeElement as HTMLElement); + } - it('should set aria-disabled to "true" for the toolbar', () => { - updateToolbar({disabled: true}); - expect(toolbarElement.getAttribute('aria-disabled')).toBe('true'); - }); + afterEach(async () => await runAccessibilityChecks(fixture.nativeElement)); - it('should set aria-disabled to "true" for all widgets when toolbar is disabled', () => { - updateToolbar({disabled: true}); - expect(widgetElements[0].getAttribute('aria-disabled')).toBe('true'); - expect(widgetElements[1].getAttribute('aria-disabled')).toBe('true'); - expect(widgetElements[2].getAttribute('aria-disabled')).toBe('true'); + describe('Navigation', () => { + describe('with horizontal orientation', () => { + it('should navigate on click', () => { + setupToolbar(); + const item3 = getWidgetEl('item 3')!; + click(item3); + expect(document.activeElement).toBe(item3); }); - }); - }); - describe('keyboard navigation', () => { - describe('LTR', () => { - beforeEach(() => { - setupTestToolbar('ltr'); - updateToolbar({widgetGroupDisabled: true}); - }); + describe('with ltr text direction', () => { + beforeEach(() => setupToolbar()); - describe('vertical orientation', () => { - beforeEach(() => { - updateToolbar({orientation: 'vertical'}); + it('should navigate next on ArrowRight', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); + right(); + expect(document.activeElement).toBe(getWidgetEl('item 1')); }); - it('should move focus to the next widget on ArrowDown', () => { - down(); - expect(document.activeElement).toBe(widgetElements[2]); + it('should navigate prev on ArrowLeft', () => { + const item1 = getWidgetEl('item 1')!; + click(item1); + left(); + expect(document.activeElement).toBe(getWidgetEl('item 0')); }); - it('should move focus to the previous widget on ArrowUp', () => { + it('should not navigate next on ArrowDown when not in a widget group', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); down(); - expect(document.activeElement).toBe(widgetElements[2]); + expect(document.activeElement).toBe(item0); + }); + it('should not navigate prev on ArrowUp when not in a widget group', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); up(); - expect(document.activeElement).toBe(widgetElements[0]); + expect(document.activeElement).toBe(item0); }); - }); - describe('horizontal orientation', () => { - beforeEach(() => { - updateToolbar({orientation: 'horizontal'}); + it('should navigate next in a widget group on ArrowDown', () => { + const item2 = getWidgetEl('item 2')!; + click(item2); + down(); + expect(document.activeElement).toBe(getWidgetEl('item 3')); }); - it('should move focus to the next widget on ArrowRight', () => { - right(); - expect(document.activeElement).toBe(widgetElements[2]); + it('should navigate prev in a widget group on ArrowUp', () => { + const item3 = getWidgetEl('item 3')!; + click(item3); + up(); + expect(document.activeElement).toBe(getWidgetEl('item 2')); }); - it('should move focus to the previous widget on ArrowLeft', () => { - right(); - expect(document.activeElement).toBe(widgetElements[2]); - - left(); - expect(document.activeElement).toBe(widgetElements[0]); + it('should navigate last to first in a widget group on ArrowDown', () => { + const item4 = getWidgetEl('item 4')!; + click(item4); + down(); + expect(document.activeElement).toBe(getWidgetEl('item 2')); }); - }); - - it('should move focus to the last enabled widget on End', () => { - end(); - expect(document.activeElement).toBe(widgetElements[2]); - }); - - it('should move focus to the first enabled widget on Home', () => { - end(); - expect(document.activeElement).toBe(widgetElements[2]); - home(); - expect(document.activeElement).toBe(widgetElements[0]); - }); - - it('should skip disabled widgets with arrow keys if skipDisabled=true', () => { - updateToolbar({skipDisabled: true}); - right(); - expect(document.activeElement).toBe(widgetElements[2]); - }); - - it('should not skip disabled widgets with arrow keys if skipDisabled=false', () => { - updateToolbar({skipDisabled: false}); - right(); - expect(document.activeElement).toBe(widgetElements[1]); - }); - - it('should wrap focus from last to first when wrap is true', () => { - updateToolbar({wrap: true}); - end(); - expect(document.activeElement).toBe(widgetElements[2]); + it('should navigate first to last in a widget group on ArrowUp', () => { + const item2 = getWidgetEl('item 2')!; + click(item2); + up(); + expect(document.activeElement).toBe(getWidgetEl('item 4')); + }); - right(); - expect(document.activeElement).toBe(widgetElements[0]); - }); + describe('with wrap false', () => { + beforeEach(() => { + fixture.componentInstance.wrap.set(false); + fixture.detectChanges(); + }); + + it('should not wrap from last to first', () => { + const item5 = getWidgetEl('item 5')!; + click(item5); + right(); + expect(document.activeElement).toBe(item5); + }); + + it('should not wrap from first to last', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); + left(); + expect(document.activeElement).toBe(item0); + }); + }); - it('should not wrap focus from last to first when wrap is false', () => { - updateToolbar({wrap: false}); - end(); - expect(document.activeElement).toBe(widgetElements[2]); + describe('with softDisabled true', () => { + beforeEach(() => { + fixture.componentInstance.softDisabled.set(true); + fixture.detectChanges(); + }); + + it('should not skip disabled items when navigating next', () => { + fixture.componentInstance.widgets[1].disabled.set(true); + fixture.detectChanges(); + click(getWidgetEl('item 0')!); + right(); + expect(document.activeElement).toBe(getWidgetEl('item 1')); + }); + + it('should not skip disabled items when navigating prev', () => { + fixture.componentInstance.widgets[1].disabled.set(true); + fixture.detectChanges(); + const item2 = getWidgetEl('item 2')!; + click(item2); + left(); + expect(document.activeElement).toBe(getWidgetEl('item 1')); + }); + + it('should not skip disabled groups when navigating next', () => { + fixture.componentInstance.groups[0].disabled.set(true); + fixture.detectChanges(); + const item1 = getWidgetEl('item 1')!; + click(item1); + right(); + expect(document.activeElement).toBe(getWidgetEl('item 2')); + }); + + it('should not skip disabled groups when navigating prev', () => { + fixture.componentInstance.groups[0].disabled.set(true); + fixture.detectChanges(); + const item5 = getWidgetEl('item 5')!; + click(item5); + left(); + expect(document.activeElement).toBe(getWidgetEl('item 4')); + }); + + it('should navigate to the last item on End', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); + end(); + expect(document.activeElement).toBe(getWidgetEl('item 5')); + }); + + it('should navigate to the first item on Home', () => { + const item5 = getWidgetEl('item 5')!; + click(item5); + home(); + expect(document.activeElement).toBe(getWidgetEl('item 0')); + }); + + describe('with wrap true', () => { + beforeEach(() => { + fixture.componentInstance.wrap.set(true); + fixture.detectChanges(); + }); + + it('should wrap from last to first', () => { + const item5 = getWidgetEl('item 5')!; + click(item5); + right(); + expect(document.activeElement).toBe(getWidgetEl('item 0')); + }); + + it('should wrap from first to last', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); + left(); + expect(document.activeElement).toBe(getWidgetEl('item 5')); + }); + }); + }); - right(); - expect(document.activeElement).toBe(widgetElements[2]); + describe('with softDisabled false', () => { + beforeEach(() => { + fixture.componentInstance.softDisabled.set(false); + fixture.detectChanges(); + }); + + it('should not navigate to disabled items on click', () => { + fixture.componentInstance.widgets[1].disabled.set(true); + fixture.detectChanges(); + const item1 = getWidgetEl('item 1')!; + click(item1); + expect(document.activeElement).not.toBe(item1); + }); + + it('should skip disabled items when navigating next', () => { + fixture.componentInstance.widgets[1].disabled.set(true); + fixture.detectChanges(); + const item0 = getWidgetEl('item 0')!; + click(item0); + right(); + expect(document.activeElement).toBe(getWidgetEl('item 2')); + }); + + it('should skip disabled items when navigating prev', () => { + fixture.componentInstance.widgets[1].disabled.set(true); + fixture.detectChanges(); + const item2 = getWidgetEl('item 2')!; + click(item2); + left(); + expect(document.activeElement).toBe(getWidgetEl('item 0')); + }); + + it('should not navigate to items in disabled groups on click', () => { + fixture.componentInstance.groups[0].disabled.set(true); + fixture.detectChanges(); + const item3 = getWidgetEl('item 3')!; + click(item3); + expect(document.activeElement).not.toBe(item3); + }); + + it('should skip disabled groups when navigating next', () => { + fixture.componentInstance.groups[0].disabled.set(true); + fixture.detectChanges(); + const item1 = getWidgetEl('item 1')!; + click(item1); + right(); + expect(document.activeElement).toBe(getWidgetEl('item 5')); + }); + + it('should skip disabled groups when navigating prev', () => { + fixture.componentInstance.groups[0].disabled.set(true); + fixture.detectChanges(); + const item5 = getWidgetEl('item 5')!; + click(item5); + left(); + expect(document.activeElement).toBe(getWidgetEl('item 1')); + }); + + it('should navigate to the last focusable item on End', () => { + fixture.componentInstance.widgets[5].disabled.set(true); + fixture.detectChanges(); + const item0 = getWidgetEl('item 0')!; + click(item0); + end(); + expect(document.activeElement).toBe(getWidgetEl('item 4')); + }); + + it('should navigate to the first focusable item on Home', () => { + fixture.componentInstance.widgets[0].disabled.set(true); + fixture.detectChanges(); + const item5 = getWidgetEl('item 5')!; + click(item5); + home(); + expect(document.activeElement).toBe(getWidgetEl('item 1')); + }); + + describe('with wrap true', () => { + beforeEach(() => { + fixture.componentInstance.wrap.set(true); + fixture.detectChanges(); + }); + + it('should wrap from last to first focusable item', () => { + fixture.componentInstance.widgets[0].disabled.set(true); + fixture.detectChanges(); + const item5 = getWidgetEl('item 5')!; + click(item5); + right(); + expect(document.activeElement).toBe(getWidgetEl('item 1')); + }); + + it('should wrap from first to last focusable item', () => { + fixture.componentInstance.widgets[5].disabled.set(true); + fixture.detectChanges(); + const item0 = getWidgetEl('item 0')!; + click(item0); + left(); + expect(document.activeElement).toBe(getWidgetEl('item 4')); + }); + }); + + describe('with wrap false', () => { + beforeEach(() => { + fixture.componentInstance.wrap.set(false); + fixture.detectChanges(); + }); + + it('should not wrap from last to first focusable item', () => { + fixture.componentInstance.widgets[0].disabled.set(true); + fixture.detectChanges(); + const item5 = getWidgetEl('item 5')!; + click(item5); + right(); + expect(document.activeElement).toBe(item5); + }); + + it('should not wrap from first to last focusable item', () => { + fixture.componentInstance.widgets[5].disabled.set(true); + fixture.detectChanges(); + const item0 = getWidgetEl('item 0')!; + click(item0); + left(); + expect(document.activeElement).toBe(item0); + }); + }); + }); }); - }); - describe('RTL', () => { - beforeEach(() => { - setupTestToolbar('rtl'); - updateToolbar({widgetGroupDisabled: true, orientation: 'horizontal'}); - }); + describe('with rtl text direction', () => { + beforeEach(() => setupToolbar({textDirection: 'rtl'})); - describe('horizontal orientation', () => { - it('should move focus to the next widget on ArrowLeft', () => { - left(); - expect(document.activeElement).toBe(widgetElements[2]); + it('should navigate on click', () => { + const item3 = getWidgetEl('item 3')!; + click(item3); + expect(document.activeElement).toBe(item3); }); - it('should move focus to the previous widget on ArrowRight', () => { + it('should navigate next on ArrowLeft', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); left(); - expect(document.activeElement).toBe(widgetElements[2]); - - right(); - expect(document.activeElement).toBe(widgetElements[0]); + expect(document.activeElement).toBe(getWidgetEl('item 1')); }); - }); - }); - }); - - describe('pointer navigation', () => { - beforeEach(() => setupTestToolbar()); - - it('should move focus to the clicked widget', () => { - click(widgetElements[2]); - expect(document.activeElement).toBe(widgetElements[2]); - }); - - it('should move focus to the clicked disabled widget if skipDisabled=false', () => { - updateToolbar({skipDisabled: false}); - click(widgetElements[1]); - expect(document.activeElement).toBe(widgetElements[1]); - }); - - it('should not move focus to the clicked disabled widget if skipDisabled=true', () => { - updateToolbar({skipDisabled: true}); - const initiallyFocused = document.activeElement; - - click(widgetElements[1]); - - expect(document.activeElement).toBe(initiallyFocused); - }); - }); - - describe('widget group', () => { - describe('LTR', () => { - beforeEach(() => { - setupTestToolbar('ltr'); - const widgetGroupElement = testWidgetGroupInstance.toolbarWidgetGroup.element(); - click(widgetGroupElement); - testWidgetGroupInstance.lastAction.set(undefined); - }); - describe('vertical orientation', () => { - beforeEach(() => { - updateToolbar({orientation: 'vertical'}); + it('should navigate prev on ArrowRight', () => { + click(getWidgetEl('item 1')!); + right(); + expect(document.activeElement).toBe(getWidgetEl('item 0')); }); - it('should call "next" on ArrowDown', () => { + it('should not navigate next on ArrowDown when not in a widget group', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); down(); - expect(testWidgetGroupInstance.lastAction()).toBe('next'); + expect(document.activeElement).toBe(item0); }); - it('should call "prev" on ArrowUp', () => { + it('should not navigate prev on ArrowUp when not in a widget group', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); up(); - expect(testWidgetGroupInstance.lastAction()).toBe('prev'); + expect(document.activeElement).toBe(item0); }); - it('should call "next" with wrap on ArrowRight', () => { - right(); - expect(testWidgetGroupInstance.lastAction()).toBe('nextWithWrap'); + it('should navigate next in a widget group on ArrowDown', () => { + const item2 = getWidgetEl('item 2')!; + click(item2); + down(); + expect(document.activeElement).toBe(getWidgetEl('item 3')); }); - it('should call "prev" with wrap on ArrowLeft', () => { - left(); - expect(testWidgetGroupInstance.lastAction()).toBe('prevWithWrap'); + it('should navigate prev in a widget group on ArrowUp', () => { + const item3 = getWidgetEl('item 3')!; + click(item3); + up(); + expect(document.activeElement).toBe(getWidgetEl('item 2')); }); - }); - describe('horizontal orientation', () => { - beforeEach(() => { - updateToolbar({orientation: 'horizontal'}); + it('should navigate first to last in a widget group on ArrowUp', () => { + const item2 = getWidgetEl('item 2')!; + click(item2); + up(); + expect(document.activeElement).toBe(getWidgetEl('item 4')); }); - it('should call "next" on ArrowRight', () => { - right(); - expect(testWidgetGroupInstance.lastAction()).toBe('next'); + it('should navigate last to first in a widget group on ArrowDown', () => { + const item4 = getWidgetEl('item 4')!; + click(item4); + down(); + expect(document.activeElement).toBe(getWidgetEl('item 2')); }); + }); + }); - it('should call "prev" on ArrowLeft', () => { - left(); - expect(testWidgetGroupInstance.lastAction()).toBe('prev'); - }); + describe('with vertical orientation', () => { + beforeEach(() => setupToolbar({orientation: 'vertical'})); - it('should call "next" with wrap on ArrowDown', () => { - down(); - expect(testWidgetGroupInstance.lastAction()).toBe('nextWithWrap'); - }); + it('should navigate next on ArrowDown', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); + down(); + expect(document.activeElement).toBe(getWidgetEl('item 1')); + }); - it('should call "prev" with wrap on ArrowUp', () => { - up(); - expect(testWidgetGroupInstance.lastAction()).toBe('prevWithWrap'); - }); + it('should navigate prev on ArrowUp', () => { + const item1 = getWidgetEl('item 1')!; + click(item1); + up(); + expect(document.activeElement).toBe(getWidgetEl('item 0')); }); - it('should call "unfocus" on Home key', () => { - home(); - expect(testWidgetGroupInstance.lastAction()).toBe('unfocus'); - expect(document.activeElement).toBe(widgetElements[0]); + it('should not navigate next on ArrowRight when not in a widget group', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); + right(); + expect(document.activeElement).toBe(item0); }); - it('should call "unfocus" on End key', () => { - end(); - expect(testWidgetGroupInstance.lastAction()).toBe('unfocus'); - expect(document.activeElement).toBe(widgetElements[2]); + it('should not navigate prev on ArrowLeft when not in a widget group', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); + left(); + expect(document.activeElement).toBe(item0); }); - it('should call "trigger" on Enter key', () => { - enter(); - expect(testWidgetGroupInstance.lastAction()).toBe('trigger'); + it('should navigate next in a widget group on ArrowRight', () => { + const item2 = getWidgetEl('item 2')!; + click(item2); + right(); + expect(document.activeElement).toBe(getWidgetEl('item 3')); }); - it('should call "trigger" on Space key', () => { - space(); - expect(testWidgetGroupInstance.lastAction()).toBe('trigger'); + it('should navigate prev in a widget group on ArrowLeft', () => { + const item3 = getWidgetEl('item 3')!; + click(item3); + left(); + expect(document.activeElement).toBe(getWidgetEl('item 2')); }); - it('should call "first" when navigating into a group from the previous widget', () => { - click(widgetElements[0]); + it('should navigate last to first in a widget group on ArrowRight', () => { + const item4 = getWidgetEl('item 4')!; + click(item4); right(); - expect(testWidgetGroupInstance.lastAction()).toBe('first'); + expect(document.activeElement).toBe(getWidgetEl('item 2')); }); - it('should call "last" when navigating into a group from the next widget', () => { - click(widgetElements[2]); + it('should navigate first to last in a widget group on ArrowLeft', () => { + const item2 = getWidgetEl('item 2')!; + click(item2); left(); - expect(testWidgetGroupInstance.lastAction()).toBe('last'); + expect(document.activeElement).toBe(getWidgetEl('item 4')); }); + }); + + describe('with disabled toolbar', () => { + it('should not navigate on any key press', () => { + setupToolbar({disabled: true}); + const item0 = getWidgetEl('item 0')!; + const initialActiveElement = document.activeElement; + click(item0); + expect(document.activeElement).toBe(initialActiveElement); + + right(); + expect(document.activeElement).toBe(initialActiveElement); - it('should call "goto" on click', () => { - click(testWidgetGroupInstance.toolbarWidgetGroup.element()); - expect(testWidgetGroupInstance.lastAction()).toBe('goto'); + left(); + expect(document.activeElement).toBe(initialActiveElement); + + down(); + expect(document.activeElement).toBe(initialActiveElement); + + up(); + expect(document.activeElement).toBe(initialActiveElement); + + home(); + expect(document.activeElement).toBe(initialActiveElement); + + end(); + expect(document.activeElement).toBe(initialActiveElement); }); }); - describe('RTL', () => { + describe('with wrapped toolbar widgets', () => { beforeEach(() => { - setupTestToolbar('rtl'); - const widgetGroupElement = testWidgetGroupInstance.toolbarWidgetGroup.element(); - click(widgetGroupElement); - testWidgetGroupInstance.lastAction.set(undefined); - updateToolbar({orientation: 'horizontal'}); + TestBed.configureTestingModule({imports: [WrappedToolbarExample]}); + fixture = TestBed.createComponent(WrappedToolbarExample) as any; + fixture.detectChanges(); }); - describe('horizontal orientation', () => { - it('should call "next" on ArrowLeft', () => { - left(); - expect(testWidgetGroupInstance.lastAction()).toBe('next'); - }); - - it('should call "prev" on ArrowRight', () => { - right(); - expect(testWidgetGroupInstance.lastAction()).toBe('prev'); - }); + it('should navigate on click', () => { + const widgets = fixture.debugElement + .queryAll(By.css('[toolbar-button]')) + .map((debugEl: DebugElement) => debugEl.nativeElement as HTMLElement); + click(widgets[0]); + expect(document.activeElement).toBe(widgets[0]); }); }); }); -}); -@Component({ - template: 'a black box', - selector: 'testWidgetGroup', - hostDirectives: [ - { - directive: ToolbarWidgetGroup, - inputs: ['disabled'], - }, - ], -}) -class TestToolbarWidgetGroup { - readonly toolbarWidgetGroup = inject(ToolbarWidgetGroup); - readonly lastAction = signal(undefined); - - constructor() { - this.toolbarWidgetGroup.controls.set({ - isOnFirstItem: () => false, - isOnLastItem: () => false, - next: wrap => { - this.lastAction.set(wrap ? 'nextWithWrap' : 'next'); - }, - prev: wrap => { - this.lastAction.set(wrap ? 'prevWithWrap' : 'prev'); - }, - first: () => { - this.lastAction.set('first'); - }, - last: () => { - this.lastAction.set('last'); - }, - unfocus: () => { - this.lastAction.set('unfocus'); - }, - trigger: () => { - this.lastAction.set('trigger'); - }, - goto: () => { - this.lastAction.set('goto'); - }, - setDefaultState: () => { - this.lastAction.set('setDefaultState'); - }, + describe('Selection', () => { + beforeEach(() => setupToolbar()); + + it('should toggle the active item on Enter', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); + keydown('Enter'); + expect(item0.getAttribute('aria-pressed')).toBe('false'); + keydown('Enter'); + expect(item0.getAttribute('aria-pressed')).toBe('true'); + }); + + it('should toggle the active item on Space', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); + keydown(' '); + expect(item0.getAttribute('aria-pressed')).toBe('false'); + keydown(' '); + expect(item0.getAttribute('aria-pressed')).toBe('true'); + }); + + it('should toggle the active item on click', () => { + const item0 = getWidgetEl('item 0')!; + click(item0); + expect(item0.getAttribute('aria-pressed')).toBe('true'); + click(item0); + expect(item0.getAttribute('aria-pressed')).toBe('false'); }); - } -} + + it('should be able to select multiple items in the toolbar', () => { + const item0 = getWidgetEl('item 0')!; + const item1 = getWidgetEl('item 1')!; + click(item0); + click(item1); + expect(item0.getAttribute('aria-pressed')).toBe('true'); + expect(item1.getAttribute('aria-pressed')).toBe('true'); + }); + + it('should not be able to select multiple items in a group', () => { + const item2 = getWidgetEl('item 2')!; + const item3 = getWidgetEl('item 3')!; + click(item2); + click(item3); + expect(item2.getAttribute('aria-pressed')).toBe('false'); + expect(item3.getAttribute('aria-pressed')).toBe('true'); + }); + + it('should not select disabled items', () => { + fixture.componentInstance.widgets[1].disabled.set(true); + fixture.detectChanges(); + const item1 = getWidgetEl('item 1')!; + click(item1); + expect(item1.getAttribute('aria-pressed')).toBe('false'); + }); + + it('should not select items in a disabled group', () => { + fixture.componentInstance.groups[0].disabled.set(true); + fixture.detectChanges(); + const item2 = getWidgetEl('item 2')!; + click(item2); + expect(item2.getAttribute('aria-pressed')).toBe('false'); + }); + }); +}); @Component({ template: `
        - - - - + + + + +
        + + + +
        +
        `, - imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup, TestToolbarWidgetGroup], + imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup], }) -class TestToolbarComponent { +class ToolbarExample { orientation = signal<'vertical' | 'horizontal'>('horizontal'); + softDisabled = signal(true); disabled = signal(false); - widgetGroupDisabled = signal(false); wrap = signal(true); - skipDisabled = signal(true); + + widgets = [ + {disabled: signal(false)}, + {disabled: signal(false)}, + {disabled: signal(false)}, + {disabled: signal(false)}, + {disabled: signal(false)}, + {disabled: signal(false)}, + ]; + + groups = [{disabled: signal(false)}]; } + +@Directive({ + selector: 'button[toolbar-button]', + hostDirectives: [{directive: ToolbarWidget, inputs: ['value', 'disabled']}], + host: { + type: 'button', + class: 'example-button material-symbols-outlined', + '[aria-label]': 'widget.value()', + }, +}) +export class SimpleToolbarButton { + widget = inject(ToolbarWidget); +} + +@Component({ + template: ` +
        + + +
        + `, + imports: [Toolbar, SimpleToolbarButton], +}) +class WrappedToolbarExample {} diff --git a/src/aria/toolbar/toolbar.ts b/src/aria/toolbar/toolbar.ts index 9d3b20f4c829..afbe8bc51c44 100644 --- a/src/aria/toolbar/toolbar.ts +++ b/src/aria/toolbar/toolbar.ts @@ -15,84 +15,75 @@ import { input, booleanAttribute, signal, - Signal, - OnInit, - OnDestroy, + model, } from '@angular/core'; -import { - ToolbarPattern, - ToolbarWidgetPattern, - ToolbarWidgetGroupPattern, - ToolbarWidgetGroupControls, -} from '@angular/aria/ui-patterns'; +import {ToolbarPattern} from '../private'; import {Directionality} from '@angular/cdk/bidi'; -import {_IdGenerator} from '@angular/cdk/a11y'; - -interface HasElement { - element: Signal; -} - -/** - * Sort directives by their document order. - */ -function sortDirectives(a: HasElement, b: HasElement) { - return (a.element().compareDocumentPosition(b.element()) & Node.DOCUMENT_POSITION_PRECEDING) > 0 - ? 1 - : -1; -} +import type {ToolbarWidget} from './toolbar-widget'; +import {sortDirectives} from './utils'; /** - * A toolbar widget container. - * - * Widgets such as radio groups or buttons are nested within a toolbar to allow for a single - * place of reference for focus and navigation. The Toolbar is meant to be used in conjunction - * with ToolbarWidget and RadioGroup as follows: + * A toolbar widget container for a group of interactive widgets, such as + * buttons or radio groups. It provides a single point of reference for keyboard navigation + * and focus management. It supports various orientations and disabled states. * * ```html - *
        - * - *
        - * - * - * - *
        + *
        + * + * + * + *
        + * + * + * + *
        *
        * ``` + * + * @developerPreview 21.0 + * + * @see [Toolbar](guide/aria/toolbar) */ @Directive({ selector: '[ngToolbar]', exportAs: 'ngToolbar', host: { 'role': 'toolbar', - 'class': 'ng-toolbar', - '[attr.tabindex]': 'pattern.tabindex()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[attr.aria-orientation]': 'pattern.orientation()', - '(keydown)': 'pattern.onKeydown($event)', - '(pointerdown)': 'pattern.onPointerdown($event)', - '(focusin)': 'onFocus()', + '[attr.tabindex]': '_pattern.tabIndex()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.aria-orientation]': '_pattern.orientation()', + '(keydown)': '_pattern.onKeydown($event)', + '(click)': '_pattern.onClick($event)', + '(pointerdown)': '_pattern.onPointerdown($event)', + '(focusin)': '_onFocus()', }, }) export class Toolbar { - /** A reference to the toolbar element. */ + /** A reference to the host element. */ private readonly _elementRef = inject(ElementRef); + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + /** The TabList nested inside of the container. */ - private readonly _widgets = signal(new Set | ToolbarWidgetGroup>()); + private readonly _widgets = signal(new Set>()); - /** A signal wrapper for directionality. */ + /** Text direction. */ readonly textDirection = inject(Directionality).valueSignal; /** Sorted UIPatterns of the child widgets */ - readonly items = computed(() => - [...this._widgets()].sort(sortDirectives).map(widget => widget.pattern), + readonly _itemPatterns = computed(() => + [...this._widgets()].sort(sortDirectives).map(widget => widget._pattern), ); /** Whether the toolbar is vertically or horizontally oriented. */ readonly orientation = input<'vertical' | 'horizontal'>('horizontal'); - /** Whether disabled items in the group should be skipped when navigating. */ - readonly skipDisabled = input(false, {transform: booleanAttribute}); + /** + * Whether to allow disabled items to receive focus. When `true`, disabled items are + * focusable but not interactive. When `false`, disabled items are skipped during navigation. + */ + softDisabled = input(true, {transform: booleanAttribute}); /** Whether the toolbar is disabled. */ readonly disabled = input(false, {transform: booleanAttribute}); @@ -100,22 +91,27 @@ export class Toolbar { /** Whether focus should wrap when navigating. */ readonly wrap = input(true, {transform: booleanAttribute}); + /** The values of the selected widgets within the toolbar. */ + readonly values = model([]); + /** The toolbar UIPattern. */ - readonly pattern: ToolbarPattern = new ToolbarPattern({ + readonly _pattern: ToolbarPattern = new ToolbarPattern({ ...this, + items: this._itemPatterns, activeItem: signal(undefined), textDirection: this.textDirection, element: () => this._elementRef.nativeElement, getItem: e => this._getItem(e), + values: this.values, }); /** Whether the toolbar has received focus yet. */ - private _hasFocused = signal(false); + private _hasBeenFocused = signal(false); constructor() { afterRenderEffect(() => { if (typeof ngDevMode === 'undefined' || ngDevMode) { - const violations = this.pattern.validate(); + const violations = this._pattern.validate(); for (const violation of violations) { console.error(violation); } @@ -123,17 +119,17 @@ export class Toolbar { }); afterRenderEffect(() => { - if (!this._hasFocused()) { - this.pattern.setDefaultState(); + if (!this._hasBeenFocused()) { + this._pattern.setDefaultState(); } }); } - onFocus() { - this._hasFocused.set(true); + _onFocus() { + this._hasBeenFocused.set(true); } - register(widget: ToolbarWidget | ToolbarWidgetGroup) { + _register(widget: ToolbarWidget) { const widgets = this._widgets(); if (!widgets.has(widget)) { widgets.add(widget); @@ -141,7 +137,7 @@ export class Toolbar { } } - unregister(widget: ToolbarWidget | ToolbarWidgetGroup) { + _unregister(widget: ToolbarWidget) { const widgets = this._widgets(); if (widgets.delete(widget)) { this._widgets.set(new Set(widgets)); @@ -150,121 +146,6 @@ export class Toolbar { /** Finds the toolbar item associated with a given element. */ private _getItem(element: Element) { - const widgetTarget = element.closest('.ng-toolbar-widget'); - const groupTarget = element.closest('.ng-toolbar-widget-group'); - return this.items().find( - widget => widget.element() === widgetTarget || widget.element() === groupTarget, - ); - } -} - -/** - * A widget within a toolbar. - * - * A widget is anything that is within a toolbar. It should be applied to any native HTML element - * that has the purpose of acting as a widget navigatable within a toolbar. - */ -@Directive({ - selector: '[ngToolbarWidget]', - exportAs: 'ngToolbarWidget', - host: { - 'class': 'ng-toolbar-widget', - '[attr.data-active]': 'pattern.active()', - '[attr.tabindex]': 'pattern.tabindex()', - '[attr.inert]': 'hardDisabled() ? true : null', - '[attr.disabled]': 'hardDisabled() ? true : null', - '[attr.aria-disabled]': 'pattern.disabled()', - '[id]': 'pattern.id()', - }, -}) -export class ToolbarWidget implements OnInit, OnDestroy { - /** A reference to the widget element. */ - private readonly _elementRef = inject(ElementRef); - - /** The parent Toolbar. */ - private readonly _toolbar = inject(Toolbar); - - /** A unique identifier for the widget. */ - private readonly _generatedId = inject(_IdGenerator).getId('ng-toolbar-widget-'); - - /** A unique identifier for the widget. */ - readonly id = computed(() => this._generatedId); - - /** The parent Toolbar UIPattern. */ - readonly toolbar = computed(() => this._toolbar.pattern); - - /** A reference to the widget element to be focused on navigation. */ - readonly element = computed(() => this._elementRef.nativeElement); - - /** Whether the widget is disabled. */ - readonly disabled = input(false, {transform: booleanAttribute}); - - /** Whether the widget is 'hard' disabled, which is different from `aria-disabled`. A hard disabled widget cannot receive focus. */ - readonly hardDisabled = computed(() => this.pattern.disabled() && this._toolbar.skipDisabled()); - - /** The ToolbarWidget UIPattern. */ - readonly pattern = new ToolbarWidgetPattern({ - ...this, - id: this.id, - element: this.element, - disabled: computed(() => this._toolbar.disabled() || this.disabled()), - }); - - ngOnInit() { - this._toolbar.register(this); - } - - ngOnDestroy() { - this._toolbar.unregister(this); - } -} - -/** - * A directive that groups toolbar widgets, used for more complex widgets like radio groups that - * have their own internal navigation. - */ -@Directive({ - host: { - '[class.ng-toolbar-widget-group]': '!!toolbar()', - }, -}) -export class ToolbarWidgetGroup implements OnInit, OnDestroy { - /** A reference to the widget element. */ - private readonly _elementRef = inject(ElementRef); - - /** The parent Toolbar. */ - private readonly _toolbar = inject(Toolbar, {optional: true}); - - /** A unique identifier for the widget. */ - private readonly _generatedId = inject(_IdGenerator).getId('ng-toolbar-widget-group-'); - - /** A unique identifier for the widget. */ - readonly id = computed(() => this._generatedId); - - /** The parent Toolbar UIPattern. */ - readonly toolbar = computed(() => this._toolbar?.pattern); - - /** A reference to the widget element to be focused on navigation. */ - readonly element = computed(() => this._elementRef.nativeElement); - - /** Whether the widget group is disabled. */ - readonly disabled = input(false, {transform: booleanAttribute}); - - /** The controls that can be performed on the widget group. */ - readonly controls = signal(undefined); - - /** The ToolbarWidgetGroup UIPattern. */ - readonly pattern = new ToolbarWidgetGroupPattern({ - ...this, - id: this.id, - element: this.element, - }); - - ngOnInit() { - this._toolbar?.register(this); - } - - ngOnDestroy() { - this._toolbar?.unregister(this); + return this._itemPatterns().find(item => item.element()?.contains(element)); } } diff --git a/src/aria/toolbar/utils.ts b/src/aria/toolbar/utils.ts new file mode 100644 index 000000000000..558f8508fde7 --- /dev/null +++ b/src/aria/toolbar/utils.ts @@ -0,0 +1,25 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {InjectionToken} from '@angular/core'; +import type {ToolbarWidgetGroup} from './toolbar-widget-group'; + +/** Token used to provide the `ToolbarWidgetGroup` directive. */ +export const TOOLBAR_WIDGET_GROUP = new InjectionToken>( + 'TOOLBAR_WIDGET_GROUP', +); + +interface HasElement { + element: HTMLElement; +} + +export function sortDirectives(a: HasElement, b: HasElement) { + return (a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_PRECEDING) > 0 + ? 1 + : -1; +} diff --git a/src/aria/tree/BUILD.bazel b/src/aria/tree/BUILD.bazel index 06577efb9b90..c18b29d276f3 100644 --- a/src/aria/tree/BUILD.bazel +++ b/src/aria/tree/BUILD.bazel @@ -1,18 +1,17 @@ -load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite") +load("//tools:defaults.bzl", "extract_api_to_json", "ng_project", "ng_web_test_suite") package(default_visibility = ["//visibility:public"]) ng_project( name = "tree", - srcs = [ - "index.ts", - "tree.ts", - ], + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), deps = [ "//:node_modules/@angular/core", "//src/aria/combobox", - "//src/aria/deferred-content", - "//src/aria/ui-patterns", + "//src/aria/private", "//src/cdk/a11y", "//src/cdk/bidi", ], @@ -37,3 +36,23 @@ ng_web_test_suite( name = "unit_tests", deps = [":unit_test_sources"], ) + +filegroup( + name = "source-files", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*.spec.ts"], + ), +) + +extract_api_to_json( + name = "json_api", + srcs = [ + ":source-files", + ], + entry_point = ":index.ts", + module_name = "@angular/aria/tree", + output_name = "aria-tree.json", + private_modules = [""], + repo = "angular/components", +) diff --git a/src/aria/tree/index.ts b/src/aria/tree/index.ts index f03ad4c2dbaa..52b3c7a5156f 100644 --- a/src/aria/tree/index.ts +++ b/src/aria/tree/index.ts @@ -6,4 +6,4 @@ * found in the LICENSE file at https://angular.dev/license */ -export {TreeItemGroup, Tree, TreeItem} from './tree'; +export * from './public-api'; diff --git a/src/aria/tree/public-api.ts b/src/aria/tree/public-api.ts new file mode 100644 index 000000000000..a072a42a53d9 --- /dev/null +++ b/src/aria/tree/public-api.ts @@ -0,0 +1,22 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +export {Tree} from './tree'; +export {TreeItem} from './tree-item'; +export {TreeItemGroup} from './tree-item-group'; + +// This needs to be re-exported, because it's used by the tree components. +// See: https://github.com/angular/components/issues/30663. +export {DeferredContent as ɵɵDeferredContent} from '../private'; +export { + Combobox as ɵɵCombobox, + ComboboxDialog as ɵɵComboboxDialog, + ComboboxInput as ɵɵComboboxInput, + ComboboxPopup as ɵɵComboboxPopup, + ComboboxPopupContainer as ɵɵComboboxPopupContainer, +} from '../combobox'; diff --git a/src/aria/tree/tree-item-group.ts b/src/aria/tree/tree-item-group.ts new file mode 100644 index 000000000000..01be388d4de1 --- /dev/null +++ b/src/aria/tree/tree-item-group.ts @@ -0,0 +1,89 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Directive, + ElementRef, + computed, + inject, + input, + signal, + OnInit, + OnDestroy, +} from '@angular/core'; +import {TreeItemPattern, DeferredContent} from '../private'; +import type {TreeItem} from './tree-item'; +import {sortDirectives} from './utils'; + +/** + * Group that contains children tree items. + * + * The `ngTreeItemGroup` structural directive should be applied to an `ng-template` that + * wraps the child `ngTreeItem` elements. It is used to define a group of children for an + * expandable `ngTreeItem`. The `ownedBy` input links the group to its parent `ngTreeItem`. + * + * ```html + *
      • + * Parent Item + *
          + * + *
        • Child Item
        • + *
          + *
        + *
      • + * ``` + * + * @developerPreview 21.0 + * + * @see [Tree](guide/aria/tree) + */ +@Directive({ + selector: 'ng-template[ngTreeItemGroup]', + exportAs: 'ngTreeItemGroup', + hostDirectives: [DeferredContent], +}) +export class TreeItemGroup implements OnInit, OnDestroy { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The DeferredContent host directive. */ + private readonly _deferredContent = inject(DeferredContent); + + /** All groupable items that are descendants of the group. */ + private readonly _unorderedItems = signal(new Set>()); + + /** Child items within this group. */ + readonly _childPatterns = computed[]>(() => + [...this._unorderedItems()].sort(sortDirectives).map(c => c._pattern), + ); + + /** Tree item that owns the group. */ + readonly ownedBy = input.required>(); + + ngOnInit() { + this._deferredContent.deferredContentAware.set(this.ownedBy()); + this.ownedBy()._register(this); + } + + ngOnDestroy() { + this.ownedBy()._unregister(); + } + + _register(child: TreeItem) { + this._unorderedItems().add(child); + this._unorderedItems.set(new Set(this._unorderedItems())); + } + + _unregister(child: TreeItem) { + this._unorderedItems().delete(child); + this._unorderedItems.set(new Set(this._unorderedItems())); + } +} diff --git a/src/aria/tree/tree-item.ts b/src/aria/tree/tree-item.ts new file mode 100644 index 000000000000..34b5fc44ad4a --- /dev/null +++ b/src/aria/tree/tree-item.ts @@ -0,0 +1,173 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Directive, + ElementRef, + afterRenderEffect, + booleanAttribute, + computed, + inject, + input, + model, + signal, + Signal, + OnInit, + OnDestroy, + afterNextRender, +} from '@angular/core'; +import {_IdGenerator} from '@angular/cdk/a11y'; +import {ComboboxTreePattern, TreeItemPattern, DeferredContentAware} from '../private'; +import {Tree} from './tree'; +import {TreeItemGroup} from './tree-item-group'; +import {HasElement} from './utils'; + +/** + * A selectable and expandable item in an `ngTree`. + * + * The `ngTreeItem` directive represents an individual node within an `ngTree`. It can be + * selected, expanded (if it has children), and disabled. The `parent` input establishes + * the hierarchical relationship within the tree. + * + * ```html + *
      • + * Item Label + *
      • + * ``` + * + * @developerPreview 21.0 + */ +@Directive({ + selector: '[ngTreeItem]', + exportAs: 'ngTreeItem', + host: { + '[attr.data-active]': 'active()', + 'role': 'treeitem', + '[id]': '_pattern.id()', + '[attr.aria-expanded]': '_expanded()', + '[attr.aria-selected]': 'selected()', + '[attr.aria-current]': '_pattern.current()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.aria-level]': 'level()', + '[attr.aria-setsize]': '_pattern.setsize()', + '[attr.aria-posinset]': '_pattern.posinset()', + '[attr.tabindex]': '_pattern.tabIndex()', + }, +}) +export class TreeItem extends DeferredContentAware implements OnInit, OnDestroy, HasElement { + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); + + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; + + /** The owned tree item group. */ + private readonly _group = signal | undefined>(undefined); + + /** A unique identifier for the tree item. */ + readonly id = input(inject(_IdGenerator).getId('ng-tree-item-', true)); + + /** The value of the tree item. */ + readonly value = input.required(); + + /** The parent tree root or tree item group. */ + readonly parent = input.required | TreeItemGroup>(); + + /** Whether the tree item is disabled. */ + readonly disabled = input(false, {transform: booleanAttribute}); + + /** Whether the tree item is selectable. */ + readonly selectable = input(true); + + /** Whether the tree item is expanded. */ + readonly expanded = model(false); + + /** Optional label for typeahead. Defaults to the element's textContent. */ + readonly label = input(); + + /** Search term for typeahead. */ + readonly searchTerm = computed(() => this.label() ?? this.element.textContent); + + /** The tree root. */ + readonly tree: Signal> = computed(() => { + if (this.parent() instanceof Tree) { + return this.parent() as Tree; + } + return (this.parent() as TreeItemGroup).ownedBy().tree(); + }); + + /** Whether the item is active. */ + readonly active = computed(() => this._pattern.active()); + + /** The level of the current item in a tree. */ + readonly level = computed(() => this._pattern.level()); + + /** Whether the item is selected. */ + readonly selected = computed(() => this._pattern.selected()); + + /** Whether this item is visible due to all of its parents being expanded. */ + readonly visible = computed(() => this._pattern.visible()); + + /** Whether the tree is expanded. Use this value for aria-expanded. */ + protected readonly _expanded: Signal = computed(() => + this._pattern.expandable() ? this._pattern.expanded() : undefined, + ); + + /** The UI pattern for this item. */ + _pattern: TreeItemPattern; + + constructor() { + super(); + afterNextRender(() => { + if (this.tree()._pattern instanceof ComboboxTreePattern) { + this.preserveContent.set(true); + } + }); + // Connect the group's hidden state to the DeferredContentAware's visibility. + afterRenderEffect(() => { + this.tree()._pattern instanceof ComboboxTreePattern + ? this.contentVisible.set(true) + : this.contentVisible.set(this._pattern.expanded()); + }); + } + + ngOnInit() { + this.parent()._register(this); + this.tree()._register(this); + + const treePattern = computed(() => this.tree()._pattern); + const parentPattern = computed(() => { + if (this.parent() instanceof Tree) { + return treePattern(); + } + return (this.parent() as TreeItemGroup).ownedBy()._pattern; + }); + this._pattern = new TreeItemPattern({ + ...this, + tree: treePattern, + parent: parentPattern, + children: computed(() => this._group()?._childPatterns() ?? []), + hasChildren: computed(() => !!this._group()), + element: () => this.element, + searchTerm: () => this.searchTerm() ?? '', + }); + } + + ngOnDestroy() { + this.parent()._unregister(this); + this.tree()._unregister(this); + } + + _register(group: TreeItemGroup) { + this._group.set(group); + } + + _unregister() { + this._group.set(undefined); + } +} diff --git a/src/aria/tree/tree.spec.ts b/src/aria/tree/tree.spec.ts index f19eb29f433b..8964b432fc90 100644 --- a/src/aria/tree/tree.spec.ts +++ b/src/aria/tree/tree.spec.ts @@ -4,7 +4,9 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Direction} from '@angular/cdk/bidi'; import {provideFakeDirectionality, runAccessibilityChecks} from '@angular/cdk/testing/private'; -import {Tree, TreeItem, TreeItemGroup} from './tree'; +import {Tree} from './tree'; +import {TreeItem} from './tree-item'; +import {TreeItemGroup} from './tree-item-group'; interface ModifierKeys { ctrlKey?: boolean; @@ -75,12 +77,12 @@ describe('Tree', () => { function updateTree( config: { nodes?: TestTreeNode[]; - value?: string[]; + values?: string[]; disabled?: boolean; orientation?: 'horizontal' | 'vertical'; multi?: boolean; wrap?: boolean; - skipDisabled?: boolean; + softDisabled?: boolean; focusMode?: 'roving' | 'activedescendant'; selectionMode?: 'follow' | 'explicit'; nav?: boolean; @@ -88,12 +90,12 @@ describe('Tree', () => { } = {}, ) { if (config.nodes !== undefined) testComponent.nodes.set(config.nodes); - if (config.value !== undefined) treeInstance.value.set(config.value); + if (config.values !== undefined) treeInstance.values.set(config.values); if (config.disabled !== undefined) testComponent.disabled.set(config.disabled); if (config.orientation !== undefined) testComponent.orientation.set(config.orientation); if (config.multi !== undefined) testComponent.multi.set(config.multi); if (config.wrap !== undefined) testComponent.wrap.set(config.wrap); - if (config.skipDisabled !== undefined) testComponent.skipDisabled.set(config.skipDisabled); + if (config.softDisabled !== undefined) testComponent.softDisabled.set(config.softDisabled); if (config.focusMode !== undefined) testComponent.focusMode.set(config.focusMode); if (config.selectionMode !== undefined) testComponent.selectionMode.set(config.selectionMode); if (config.nav !== undefined) testComponent.nav.set(config.nav); @@ -149,7 +151,7 @@ describe('Tree', () => { click(berriesEl); const vegetablesEl = getTreeItemElementByValue('vegetables')!; click(vegetablesEl); - updateTree({value: []}); + updateTree({values: []}); } afterEach(async () => { @@ -282,7 +284,7 @@ describe('Tree', () => { it('should set aria-selected to "true" for selected items', () => { expandAll(); - updateTree({value: ['apple']}); + updateTree({values: ['apple']}); const appleItem = getTreeItemElementByValue('apple')!; expect(appleItem.getAttribute('aria-selected')).toBe('true'); @@ -299,7 +301,7 @@ describe('Tree', () => { it('should set aria-current to specific current type when nav="true"', () => { expandAll(); - updateTree({nav: true, value: ['apple']}); + updateTree({nav: true, values: ['apple']}); const appleItem = getTreeItemElementByValue('apple')!; const bananaItem = getTreeItemElementByValue('banana')!; @@ -312,7 +314,7 @@ describe('Tree', () => { it('should not set aria-current when not selectable', () => { expandAll(); - updateTree({nav: true, value: ['apple']}); + updateTree({nav: true, values: ['apple']}); const appleItem = getTreeItemElementByValue('apple')!; expect(appleItem.getAttribute('aria-current')).toBe('page'); @@ -323,7 +325,7 @@ describe('Tree', () => { it('should not set aria-selected when nav="true"', () => { expandAll(); - updateTree({value: ['apple'], nav: true}); + updateTree({values: ['apple'], nav: true}); const appleItem = getTreeItemElementByValue('apple')!; expect(appleItem.hasAttribute('aria-selected')).toBe(false); @@ -333,7 +335,7 @@ describe('Tree', () => { it('should not set aria-selected when not selectable', () => { expandAll(); - updateTree({value: ['apple']}); + updateTree({values: ['apple']}); const appleItem = getTreeItemElementByValue('apple')!; expect(appleItem.getAttribute('aria-selected')).toBe('true'); @@ -352,7 +354,13 @@ describe('Tree', () => { expect(treeElement.getAttribute('tabindex')).toBe('-1'); }); - it('should set tabindex="0" for the tree when disabled', () => { + it('should set tabindex="0" for the tree when disabled when softDisabled is false', () => { + updateTree({disabled: true, focusMode: 'roving', softDisabled: false}); + + expect(treeElement.getAttribute('tabindex')).toBe('0'); + }); + + it('should set tabindex="0" for the tree when disabled when softDisabled is true', () => { updateTree({disabled: true, focusMode: 'roving'}); expect(treeElement.getAttribute('tabindex')).toBe('0'); @@ -371,7 +379,7 @@ describe('Tree', () => { }); it('should set initial focus (tabindex="0") on the first selected item', () => { - updateTree({value: ['vegetables', 'dairy'], focusMode: 'roving'}); + updateTree({values: ['vegetables', 'dairy'], focusMode: 'roving'}); const fruitsItem = getTreeItemElementByValue('fruits')!; const vegetablesItem = getTreeItemElementByValue('vegetables')!; @@ -405,7 +413,7 @@ describe('Tree', () => { }); it('should set aria-activedescendant to the ID of the first selected item', () => { - updateTree({value: ['vegetables', 'dairy'], focusMode: 'activedescendant'}); + updateTree({values: ['vegetables', 'dairy'], focusMode: 'activedescendant'}); const vegetablesItem = getTreeItemElementByValue('vegetables')!; expect(treeElement.getAttribute('aria-activedescendant')).toBe(vegetablesItem.id); @@ -433,7 +441,7 @@ describe('Tree', () => { it('should select items based on the initial value input', () => { setupTestTree(); expandAll(); - updateTree({value: ['apple', 'strawberry', 'carrot']}); + updateTree({values: ['apple', 'strawberry', 'carrot']}); expect(getTreeItemElementByValue('apple')!.getAttribute('aria-selected')).toBe('true'); expect(getTreeItemElementByValue('strawberry')!.getAttribute('aria-selected')).toBe('true'); @@ -454,12 +462,12 @@ describe('Tree', () => { const bananaEl = getTreeItemElementByValue('banana')!; click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); expect(appleEl.getAttribute('aria-selected')).toBe('true'); expect(bananaEl.getAttribute('aria-selected')).toBe('false'); click(bananaEl); - expect(treeInstance.value()).toEqual(['banana']); + expect(treeInstance.values()).toEqual(['banana']); expect(appleEl.getAttribute('aria-selected')).toBe('false'); expect(bananaEl.getAttribute('aria-selected')).toBe('true'); }); @@ -487,11 +495,11 @@ describe('Tree', () => { const carrotEl = getTreeItemElementByValue('carrot')!; click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); expect(appleEl.getAttribute('aria-selected')).toBe('true'); shiftClick(carrotEl); - expect(treeInstance.value()).toEqual([ + expect(treeInstance.values()).toEqual([ 'apple', 'banana', 'berries', @@ -505,24 +513,24 @@ describe('Tree', () => { const bananaEl = getTreeItemElementByValue('banana')!; click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); click(bananaEl); - expect(treeInstance.value()).toEqual(['apple', 'banana']); + expect(treeInstance.values()).toEqual(['apple', 'banana']); click(appleEl); - expect(treeInstance.value()).toEqual(['banana']); + expect(treeInstance.values()).toEqual(['banana']); }); describe('selectable=false', () => { it('should not select an item on click', () => { - updateTree({value: ['banana']}); + updateTree({values: ['banana']}); updateTreeItemByValue('apple', {selectable: false}); const appleEl = getTreeItemElementByValue('apple')!; click(appleEl); - expect(treeInstance.value()).not.toContain('apple'); - expect(treeInstance.value()).toContain('banana'); + expect(treeInstance.values()).not.toContain('apple'); + expect(treeInstance.values()).toContain('banana'); }); }); }); @@ -539,13 +547,13 @@ describe('Tree', () => { ctrlClick(appleEl); ctrlClick(bananaEl); - expect(treeInstance.value()).toEqual(['apple', 'banana']); + expect(treeInstance.values()).toEqual(['apple', 'banana']); click(carrotEl); - expect(treeInstance.value()).toEqual(['carrot']); + expect(treeInstance.values()).toEqual(['carrot']); click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); }); it('should add to selection with ctrl+click and toggle individual items', () => { @@ -553,13 +561,13 @@ describe('Tree', () => { const berriesEl = getTreeItemElementByValue('berries')!; click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); ctrlClick(berriesEl); - expect(treeInstance.value()).toEqual(['apple', 'berries']); + expect(treeInstance.values()).toEqual(['apple', 'berries']); ctrlClick(appleEl); - expect(treeInstance.value()).toEqual(['berries']); + expect(treeInstance.values()).toEqual(['berries']); }); it('should select a range with shift+click, anchoring from last selected/focused', () => { @@ -569,10 +577,10 @@ describe('Tree', () => { const broccoliEl = getTreeItemElementByValue('broccoli')!; click(appleEl); - expect(treeInstance.value()).toEqual(['apple']); + expect(treeInstance.values()).toEqual(['apple']); shiftClick(carrotEl); - expect(treeInstance.value()).toEqual([ + expect(treeInstance.values()).toEqual([ 'apple', 'banana', 'berries', @@ -581,10 +589,10 @@ describe('Tree', () => { ]); click(berriesEl); - expect(treeInstance.value()).toEqual(['berries']); + expect(treeInstance.values()).toEqual(['berries']); shiftClick(broccoliEl); - expect(treeInstance.value()).toEqual([ + expect(treeInstance.values()).toEqual([ 'berries', 'strawberry', 'blueberry', @@ -603,9 +611,9 @@ describe('Tree', () => { click(appleEl); shiftClick(berriesEl); - expect(treeInstance.value()).not.toContain('banana'); - expect(treeInstance.value()).toContain('apple'); - expect(treeInstance.value()).toContain('berries'); + expect(treeInstance.values()).not.toContain('banana'); + expect(treeInstance.values()).toContain('apple'); + expect(treeInstance.values()).toContain('berries'); }); it('should not toggle selection of an item on simple click', () => { @@ -613,17 +621,17 @@ describe('Tree', () => { const appleEl = getTreeItemElementByValue('apple')!; click(appleEl); - expect(treeInstance.value()).not.toContain('apple'); + expect(treeInstance.values()).not.toContain('apple'); }); it('should not add to selection with ctrl+click', () => { - updateTree({value: ['banana']}); + updateTree({values: ['banana']}); updateTreeItemByValue('apple', {selectable: false}); const appleEl = getTreeItemElementByValue('apple')!; ctrlClick(appleEl); - expect(treeInstance.value()).not.toContain('apple'); - expect(treeInstance.value()).toContain('banana'); + expect(treeInstance.values()).not.toContain('apple'); + expect(treeInstance.values()).toContain('banana'); }); }); }); @@ -644,47 +652,47 @@ describe('Tree', () => { it('should select the focused item with Enter and deselect others', () => { enter(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); enter(); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); }); it('should select the focused item with Space and deselect others', () => { space(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); space(); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); }); it('should move focus with arrows without changing selection until Enter/Space', () => { enter(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); enter(); - expect(treeInstance.value()).toEqual(['grains']); + expect(treeInstance.values()).toEqual(['grains']); }); describe('selectable=false', () => { it('should not select the focused item with Enter', () => { updateTreeItemByValue('fruits', {selectable: false}); enter(); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); it('should not select the focused item with Space', () => { updateTreeItemByValue('fruits', {selectable: false}); space(); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); }); }); @@ -695,45 +703,45 @@ describe('Tree', () => { }); it('should select an item when it becomes focused with ArrowDown and deselect others', () => { - updateTree({value: ['fruits']}); - expect(treeInstance.value()).toEqual(['fruits']); + updateTree({values: ['fruits']}); + expect(treeInstance.values()).toEqual(['fruits']); down(); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); down(); - expect(treeInstance.value()).toEqual(['grains']); + expect(treeInstance.values()).toEqual(['grains']); }); it('should select an item when it becomes focused with ArrowUp and deselect others', () => { - updateTree({value: ['grains']}); + updateTree({values: ['grains']}); up(); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); }); it('should select the first item with Home and deselect others', () => { - updateTree({value: ['grains']}); - expect(treeInstance.value()).toEqual(['grains']); + updateTree({values: ['grains']}); + expect(treeInstance.values()).toEqual(['grains']); home(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('should select the last visible item with End and deselect others', () => { - updateTree({value: ['fruits']}); - expect(treeInstance.value()).toEqual(['fruits']); + updateTree({values: ['fruits']}); + expect(treeInstance.values()).toEqual(['fruits']); end(); - expect(treeInstance.value()).toEqual(['dairy']); + expect(treeInstance.values()).toEqual(['dairy']); }); it('should select an item via typeahead and deselect others', () => { - updateTree({value: ['fruits']}); - expect(treeInstance.value()).toEqual(['fruits']); + updateTree({values: ['fruits']}); + expect(treeInstance.values()).toEqual(['fruits']); type('V'); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); }); }); }); @@ -751,35 +759,35 @@ describe('Tree', () => { it('should toggle selection of the focused item with Space, leaving other selections intact', () => { space(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); space(); - expect(treeInstance.value().sort()).toEqual(['fruits', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'vegetables']); }); it('should move focus with arrows without changing selection', () => { space(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('should extend selection downwards with Shift+ArrowDown', () => { shift(); down({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['fruits', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'vegetables']); down({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['fruits', 'grains', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'grains', 'vegetables']); }); it('should extend selection upwards with Shift+ArrowUp', () => { end(); shift(); up({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['dairy', 'grains']); + expect(treeInstance.values().sort()).toEqual(['dairy', 'grains']); }); it('Ctrl+A should select all enabled visible items, then deselect all', () => { @@ -793,7 +801,7 @@ describe('Tree', () => { updateTreeItemByValue('broccoli', {disabled: true}); keydown('A', {ctrlKey: true}); - expect(treeInstance.value().sort()).toEqual([ + expect(treeInstance.values().sort()).toEqual([ 'apple', 'banana', 'berries', @@ -804,25 +812,25 @@ describe('Tree', () => { ]); keydown('A', {ctrlKey: true}); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); it('Ctrl+ArrowKey should move focus without changing selection', () => { space(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); down({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); up({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); describe('selectable=false', () => { it('should not toggle selection of the focused item with Space', () => { updateTreeItemByValue('fruits', {selectable: false}); space(); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); it('should not extend selection with Shift+ArrowDown', () => { @@ -830,8 +838,8 @@ describe('Tree', () => { shift(); down({shiftKey: true}); down({shiftKey: true}); - expect(treeInstance.value()).not.toContain('vegetables'); - expect(treeInstance.value().sort()).toEqual(['fruits', 'grains']); + expect(treeInstance.values()).not.toContain('vegetables'); + expect(treeInstance.values().sort()).toEqual(['fruits', 'grains']); }); it('Ctrl+A should not select non-selectable items', () => { @@ -839,7 +847,7 @@ describe('Tree', () => { updateTreeItemByValue('apple', {selectable: false}); updateTreeItemByValue('carrot', {selectable: false}); keydown('A', {ctrlKey: true}); - const value = treeInstance.value(); + const value = treeInstance.values(); expect(value).not.toContain('apple'); expect(value).not.toContain('carrot'); expect(value).toContain('banana'); @@ -854,98 +862,98 @@ describe('Tree', () => { }); it('should select the focused item and deselect others on ArrowDown', () => { - updateTree({value: ['fruits']}); - expect(treeInstance.value()).toEqual(['fruits']); + updateTree({values: ['fruits']}); + expect(treeInstance.values()).toEqual(['fruits']); down(); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); }); it('should select the focused item and deselect others on ArrowUp', () => { - updateTree({value: ['vegetables']}); - expect(treeInstance.value()).toEqual(['vegetables']); + updateTree({values: ['vegetables']}); + expect(treeInstance.values()).toEqual(['vegetables']); up(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('should move focus without changing selection on Ctrl+ArrowDown', () => { - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); expect(getFocusedTreeItemValue()).toBe('fruits'); down({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); expect(getFocusedTreeItemValue()).toBe('vegetables'); }); it('should move focus without changing selection on Ctrl+ArrowUp', () => { - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); down({ctrlKey: true}); expect(getFocusedTreeItemValue()).toBe('vegetables'); up({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); expect(getFocusedTreeItemValue()).toBe('fruits'); }); it('should toggle selection of the focused item on Ctrl+Space, adding to existing selection', () => { - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); down({ctrlKey: true}); expect(getFocusedTreeItemValue()).toBe('vegetables'); space({ctrlKey: true}); - expect(treeInstance.value().sort()).toEqual(['fruits', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'vegetables']); space({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('should toggle selection of the focused item on Ctrl+Enter, adding to existing selection', () => { - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); down({ctrlKey: true}); expect(getFocusedTreeItemValue()).toBe('vegetables'); enter({ctrlKey: true}); - expect(treeInstance.value().sort()).toEqual(['fruits', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'vegetables']); enter({ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('should extend selection downwards with Shift+ArrowDown', () => { right(); // Expands fruits - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); shift(); down({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['apple', 'fruits']); + expect(treeInstance.values().sort()).toEqual(['apple', 'fruits']); down({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['apple', 'banana', 'fruits']); + expect(treeInstance.values().sort()).toEqual(['apple', 'banana', 'fruits']); }); it('should extend selection upwards with Shift+ArrowUp', () => { - updateTree({value: ['grains']}); + updateTree({values: ['grains']}); shift(); up({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['grains', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['grains', 'vegetables']); up({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['fruits', 'grains', 'vegetables']); + expect(treeInstance.values().sort()).toEqual(['fruits', 'grains', 'vegetables']); }); it('should select a range with Shift+Space, anchoring from last selected/focused item', () => { right(); // Expands fruits - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); down({ctrlKey: true}); down({ctrlKey: true}); expect(getFocusedTreeItemValue()).toBe('banana'); space({shiftKey: true}); - expect(treeInstance.value().sort()).toEqual(['apple', 'banana', 'fruits']); + expect(treeInstance.values().sort()).toEqual(['apple', 'banana', 'fruits']); }); it('Ctrl+A: select all enabled visible items; second Ctrl+A deselects all except focused', () => { @@ -953,7 +961,7 @@ describe('Tree', () => { updateTreeItemByValue('vegetables', {disabled: true}); keydown('A', {ctrlKey: true}); - expect(treeInstance.value().sort()).toEqual([ + expect(treeInstance.values().sort()).toEqual([ 'apple', 'banana', 'berries', @@ -963,13 +971,13 @@ describe('Tree', () => { ]); keydown('A', {ctrlKey: true}); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); it('typeahead should select the focused item and deselect others', () => { - updateTree({value: ['fruits']}); + updateTree({values: ['fruits']}); type('V'); - expect(treeInstance.value()).toEqual(['vegetables']); + expect(treeInstance.values()).toEqual(['vegetables']); expect(getFocusedTreeItemValue()).toBe('vegetables'); }); @@ -977,14 +985,14 @@ describe('Tree', () => { it('should not select an item on ArrowDown', () => { updateTreeItemByValue('vegetables', {selectable: false}); down(); - expect(treeInstance.value()).not.toContain('vegetables'); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).not.toContain('vegetables'); + expect(treeInstance.values()).toEqual([]); }); it('should not toggle selection of the focused item on Ctrl+Space', () => { updateTreeItemByValue('fruits', {selectable: false}); space({ctrlKey: true}); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); it('should not extend selection with Shift+ArrowDown', () => { @@ -992,38 +1000,38 @@ describe('Tree', () => { shift(); down({shiftKey: true}); down({shiftKey: true}); - expect(treeInstance.value()).not.toContain('vegetables'); - expect(treeInstance.value().sort()).toEqual(['fruits', 'grains']); + expect(treeInstance.values()).not.toContain('vegetables'); + expect(treeInstance.values().sort()).toEqual(['fruits', 'grains']); }); it('typeahead should not select the focused item', () => { updateTreeItemByValue('vegetables', {selectable: false}); type('v'); expect(getFocusedTreeItemValue()).toBe('vegetables'); - expect(treeInstance.value()).not.toContain('vegetables'); + expect(treeInstance.values()).not.toContain('vegetables'); }); }); - it('should not select disabled items during Shift+ArrowKey navigation even if skipDisabled is false', () => { + it('should not select disabled items during Shift+ArrowKey navigation even if softDisabled is true', () => { right(); // Expands fruits updateTreeItemByValue('banana', {disabled: true}); - updateTree({value: ['apple'], skipDisabled: false}); + updateTree({values: ['apple'], softDisabled: true}); expect(getFocusedTreeItemValue()).toBe('apple'); keydown('Shift'); down({shiftKey: true}); expect(getFocusedTreeItemValue()).toBe('banana'); - expect(treeInstance.value().sort()).toEqual(['apple']); + expect(treeInstance.values().sort()).toEqual(['apple']); down({shiftKey: true}); // Focus 'berries' expect(getFocusedTreeItemValue()).toBe('berries'); - expect(treeInstance.value().sort()).toEqual(['apple', 'berries']); + expect(treeInstance.values().sort()).toEqual(['apple', 'berries']); }); it('should not change selection if tree is disabled', () => { - updateTree({value: ['fruits'], disabled: true}); + updateTree({values: ['fruits'], disabled: true}); down(); - expect(treeInstance.value()).toEqual(['fruits']); + expect(treeInstance.values()).toEqual(['fruits']); }); }); }); @@ -1031,6 +1039,78 @@ describe('Tree', () => { }); describe('expansion and collapse', () => { + it('should expand items by setting expanded input', () => { + setupTestTree(); + updateTree({ + nodes: [ + { + value: 'fruits', + label: 'Fruits', + children: [ + {value: 'apple', label: 'Apple'}, + {value: 'banana', label: 'Banana'}, + { + value: 'berries', + label: 'Berries', + children: [ + {value: 'strawberry', label: 'Strawberry'}, + {value: 'blueberry', label: 'Blueberry'}, + ], + expanded: true, + }, + ], + expanded: true, + }, + ], + }); + const fruitsEl = getTreeItemElementByValue('fruits')!; + const berriesEl = getTreeItemElementByValue('berries')!; + expect(fruitsEl.getAttribute('aria-expanded')).toBe('true'); + expect(berriesEl.getAttribute('aria-expanded')).toBe('true'); + }); + + it('should not affect selected item when collapse', () => { + setupTestTree(); + updateTree({ + nodes: [ + { + value: 'fruits', + label: 'Fruits', + children: [ + {value: 'apple', label: 'Apple'}, + {value: 'banana', label: 'Banana'}, + { + value: 'berries', + label: 'Berries', + children: [ + {value: 'strawberry', label: 'Strawberry'}, + {value: 'blueberry', label: 'Blueberry'}, + ], + expanded: true, + }, + ], + expanded: true, + }, + ], + }); + const blueberryEl = getTreeItemElementByValue('blueberry')!; + const berriesEl = getTreeItemElementByValue('berries')!; + const fruits = getTreeItemElementByValue('fruits')!; + + click(blueberryEl); + expect(treeInstance.values()).toEqual(['blueberry']); + + left(); + left(); // collapse berries + expect(berriesEl.getAttribute('aria-expanded')).toBe('false'); + expect(treeInstance.values()).toEqual(['blueberry']); + + left(); + left(); // collapse fruits + expect(fruits.getAttribute('aria-expanded')).toBe('false'); + expect(treeInstance.values()).toEqual(['blueberry']); + }); + describe('LTR', () => { beforeEach(() => { setupTestTree(); @@ -1259,20 +1339,20 @@ describe('Tree', () => { expect(isFocused('fruits')).toBe(true); }); - it('should skip disabled items with ArrowDown if skipDisabled=true', () => { + it('should skip disabled items with ArrowDown if softDisabled=false', () => { right(); // Expands fruits updateTreeItemByValue('apple', {disabled: true}); - updateTree({skipDisabled: true}); + updateTree({softDisabled: false}); expect(isFocused('fruits')).toBe(true); down(); expect(isFocused('banana')).toBe(true); }); - it('should not skip disabled items with ArrowDown if skipDisabled=false', () => { + it('should not skip disabled items with ArrowDown if softDisabled=true', () => { right(); // Expands fruits updateTreeItemByValue('apple', {disabled: true}); - updateTree({skipDisabled: false}); + updateTree({softDisabled: true}); expect(isFocused('fruits')).toBe(true); down(); @@ -1315,7 +1395,8 @@ describe('Tree', () => { }); }); - it('should move focus to the last enabled visible item on End', () => { + it('should move focus to the last enabled visible item on End (softDisabled="false")', () => { + updateTree({softDisabled: false}); right(); // Expands fruits updateTreeItemByValue('dairy', {disabled: true}); updateTreeItemByValue('grains', {disabled: true}); @@ -1324,7 +1405,8 @@ describe('Tree', () => { expect(isFocused('berries')).toBe(true); }); - it('should move focus to the first enabled visible item on Home', () => { + it('should move focus to the first enabled visible item on Home (softDisabled="false")', () => { + updateTree({softDisabled: false}); end(); updateTreeItemByValue('fruits', {disabled: true}); home(); @@ -1386,9 +1468,9 @@ describe('Tree', () => { expect(isFocused('vegetables')).toBe(true); }); - it('should move focus to the clicked disabled item if skipDisabled=false', () => { + it('should move focus to the clicked disabled item if softDisabled=true', () => { updateTreeItemByValue('vegetables', {disabled: true}); - updateTree({skipDisabled: false}); + updateTree({softDisabled: true}); const vegetablesEl = getTreeItemElementByValue('vegetables')!; click(vegetablesEl); expect(isFocused('vegetables')).toBe(true); @@ -1408,27 +1490,27 @@ describe('Tree', () => { updateTree({selectionMode: 'follow'}); type('Gr'); expect(isFocused('grains')).toBe(true); - expect(treeInstance.value()).toEqual(['grains']); + expect(treeInstance.values()).toEqual(['grains']); }); it('should not select the focused item if selectionMode is "explicit"', () => { updateTree({selectionMode: 'explicit'}); type('Gr'); expect(isFocused('grains')).toBe(true); - expect(treeInstance.value()).toEqual([]); + expect(treeInstance.values()).toEqual([]); }); - it('should skip disabled items with typeahead if skipDisabled=true', () => { + it('should skip disabled items with typeahead if softDisabled=false', () => { right(); // Expands fruits updateTreeItemByValue('banana', {disabled: true}); - updateTree({skipDisabled: true}); + updateTree({softDisabled: false}); type('B'); expect(isFocused('berries')).toBe(true); }); - it('should focus disabled items with typeahead if skipDisabled=false', () => { + it('should focus disabled items with typeahead if softDisabled=true', () => { updateTreeItemByValue('vegetables', {disabled: true}); - updateTree({skipDisabled: false}); + updateTree({softDisabled: true}); type('V'); expect(isFocused('vegetables')).toBe(true); }); @@ -1443,6 +1525,7 @@ interface TestTreeNode { label: string; disabled?: boolean; selectable?: boolean; + expanded?: boolean; children?: TestTreeNode[]; } @@ -1454,10 +1537,10 @@ interface TestTreeNode { [selectionMode]="selectionMode()" [multi]="multi()" [wrap]="wrap()" - [skipDisabled]="skipDisabled()" + [softDisabled]="softDisabled()" [orientation]="orientation()" [disabled]="disabled()" - [(value)]="value" + [(values)]="values" [nav]="nav()" [currentType]="currentType()" #tree="ngTree" @@ -1474,6 +1557,7 @@ interface TestTreeNode { [label]="node.label" [disabled]="!!node.disabled" [selectable]="node.selectable ?? true" + [expanded]="node.expanded ?? false" [parent]="parent" [attr.data-value]="node.value" #treeItem="ngTreeItem" @@ -1525,12 +1609,12 @@ class TestTreeComponent { {value: 'grains', label: 'Grains'}, {value: 'dairy', label: 'Dairy'}, ]); - value = signal([]); + values = signal([]); disabled = signal(false); orientation = signal<'vertical' | 'horizontal'>('vertical'); multi = signal(false); wrap = signal(true); - skipDisabled = signal(true); + softDisabled = signal(true); focusMode = signal<'roving' | 'activedescendant'>('roving'); selectionMode = signal<'explicit' | 'follow'>('explicit'); nav = signal(false); diff --git a/src/aria/tree/tree.ts b/src/aria/tree/tree.ts index 045dc951493f..deafffde5b8c 100644 --- a/src/aria/tree/tree.ts +++ b/src/aria/tree/tree.ts @@ -16,88 +16,86 @@ import { input, model, signal, - Signal, - OnInit, - OnDestroy, untracked, } from '@angular/core'; import {_IdGenerator} from '@angular/cdk/a11y'; import {Directionality} from '@angular/cdk/bidi'; -import {DeferredContent, DeferredContentAware} from '@angular/aria/deferred-content'; -import {ComboboxTreePattern, TreeItemPattern, TreePattern} from '@angular/aria/ui-patterns'; +import {ComboboxTreePattern, TreeItemPattern, TreePattern} from '../private'; import {ComboboxPopup} from '../combobox'; - -interface HasElement { - element: Signal; -} - -/** - * Sort directives by their document order. - */ -function sortDirectives(a: HasElement, b: HasElement) { - return (a.element().compareDocumentPosition(b.element()) & Node.DOCUMENT_POSITION_PRECEDING) > 0 - ? 1 - : -1; -} +import type {TreeItem} from './tree-item'; +import {sortDirectives} from './utils'; /** - * A Tree container. - * - * Transforms nested lists into an accessible, ARIA-compliant tree structure. + * A container that transforms nested lists into an accessible, ARIA-compliant tree structure. + * It manages the overall state of the tree, including selection, expansion, and keyboard + * navigation. * * ```html *
          - *
        • Leaf Item 1
        • - *
        • - * Parent Item 1 - *
            - * - *
          • Child Item 1.1
          • - *
          • Child Item 1.2
          • - *
            - *
          - *
        • - *
        • Disabled Leaf Item 2
        • + * *
        + * + * + * @for (node of nodes; track node.name) { + *
      • + * {{ node.name }} + * @if (node.children) { + *
          + * + * + * + *
        + * } + *
      • + * } + *
        * ``` + * + * @developerPreview 21.0 + * + * @see [Tree](guide/aria/tree) */ @Directive({ selector: '[ngTree]', exportAs: 'ngTree', host: { - 'class': 'ng-tree', 'role': 'tree', '[attr.id]': 'id()', - '[attr.aria-orientation]': 'pattern.orientation()', - '[attr.aria-multiselectable]': 'pattern.multi()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[attr.aria-activedescendant]': 'pattern.activedescendant()', - '[tabindex]': 'pattern.tabindex()', - '(keydown)': 'pattern.onKeydown($event)', - '(pointerdown)': 'pattern.onPointerdown($event)', - '(focusin)': 'onFocus()', + '[attr.aria-orientation]': '_pattern.orientation()', + '[attr.aria-multiselectable]': '_pattern.multi()', + '[attr.aria-disabled]': '_pattern.disabled()', + '[attr.aria-activedescendant]': '_pattern.activeDescendant()', + '[tabindex]': '_pattern.tabIndex()', + '(keydown)': '_pattern.onKeydown($event)', + '(pointerdown)': '_pattern.onPointerdown($event)', + '(focusin)': '_onFocus()', }, - hostDirectives: [{directive: ComboboxPopup}], + hostDirectives: [ComboboxPopup], }) export class Tree { - /** A unique identifier for the tree. */ - private readonly _generatedId = inject(_IdGenerator).getId('ng-tree-'); + /** A reference to the host element. */ + private readonly _elementRef = inject(ElementRef); - // TODO(wagnermaciel): https://github.com/angular/components/pull/30495#discussion_r1972601144. - /** A unique identifier for the tree. */ - protected id = computed(() => this._generatedId); + /** A reference to the host element. */ + readonly element = this._elementRef.nativeElement as HTMLElement; /** A reference to the parent combobox popup, if one exists. */ private readonly _popup = inject>(ComboboxPopup, { optional: true, }); - /** A reference to the tree element. */ - private readonly _elementRef = inject(ElementRef); - /** All TreeItem instances within this tree. */ private readonly _unorderedItems = signal(new Set>()); + /** A unique identifier for the tree. */ + readonly id = input(inject(_IdGenerator).getId('ng-tree-', true)); + /** Orientation of the tree. */ readonly orientation = input<'vertical' | 'horizontal'>('vertical'); @@ -107,39 +105,53 @@ export class Tree { /** Whether the tree is disabled. */ readonly disabled = input(false, {transform: booleanAttribute}); - /** The selection strategy used by the tree. */ + /** + * The selection strategy used by the tree. + * - `explicit`: Items are selected explicitly by the user (e.g., via click or spacebar). + * - `follow`: The focused item is automatically selected. + */ readonly selectionMode = input<'explicit' | 'follow'>('explicit'); - /** The focus strategy used by the tree. */ + /** + * The focus strategy used by the tree. + * - `roving`: Focus is moved to the active item using `tabindex`. + * - `activedescendant`: Focus remains on the tree container, and `aria-activedescendant` is used to indicate the active item. + */ readonly focusMode = input<'roving' | 'activedescendant'>('roving'); /** Whether navigation wraps. */ readonly wrap = input(true, {transform: booleanAttribute}); - /** Whether to skip disabled items during navigation. */ - readonly skipDisabled = input(true, {transform: booleanAttribute}); + /** + * Whether to allow disabled items to receive focus. When `true`, disabled items are + * focusable but not interactive. When `false`, disabled items are skipped during navigation. + */ + readonly softDisabled = input(true, {transform: booleanAttribute}); - /** Typeahead delay. */ - readonly typeaheadDelay = input(0.5); + /** The delay in seconds before the typeahead search is reset. */ + readonly typeaheadDelay = input(500); - /** Selected item values. */ - readonly value = model([]); + /** The values of the currently selected items. */ + readonly values = model([]); /** Text direction. */ readonly textDirection = inject(Directionality).valueSignal; /** Whether the tree is in navigation mode. */ - readonly nav = input(false); + readonly nav = input(false, {transform: booleanAttribute}); - /** The aria-current type. */ + /** + * The `aria-current` type. It can be used in navigation trees to indicate the currently active item. + * See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-current for more details. + */ readonly currentType = input<'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'>( 'page', ); /** The UI pattern for the tree. */ - readonly pattern: TreePattern; + readonly _pattern: TreePattern; - /** Whether the tree has received focus yet. */ + /** Whether the tree has received focus since it was rendered. */ private _hasFocused = signal(false); constructor() { @@ -147,24 +159,24 @@ export class Tree { ...this, id: this.id, allItems: computed(() => - [...this._unorderedItems()].sort(sortDirectives).map(item => item.pattern), + [...this._unorderedItems()].sort(sortDirectives).map(item => item._pattern), ), activeItem: signal | undefined>(undefined), - element: () => this._elementRef.nativeElement, - combobox: () => this._popup?.combobox?.pattern, + combobox: () => this._popup?.combobox?._pattern, + element: () => this.element, }; - this.pattern = this._popup?.combobox + this._pattern = this._popup?.combobox ? new ComboboxTreePattern(inputs) : new TreePattern(inputs); if (this._popup?.combobox) { - this._popup?.controls?.set(this.pattern as ComboboxTreePattern); + this._popup?._controls?.set(this._pattern as ComboboxTreePattern); } afterRenderEffect(() => { if (!this._hasFocused()) { - this.pattern.setDefaultState(); + this._pattern.setDefaultState(); } }); @@ -173,183 +185,37 @@ export class Tree { const activeItem = untracked(() => inputs.activeItem()); if (!items.some(i => i === activeItem) && activeItem) { - this.pattern.listBehavior.unfocus(); + this._pattern.listBehavior.unfocus(); } }); afterRenderEffect(() => { + if (!(this._pattern instanceof ComboboxTreePattern)) return; + const items = inputs.allItems(); - const value = untracked(() => this.value()); + const values = untracked(() => this.values()); - if (items && value.some(v => !items.some(i => i.value() === v))) { - this.value.set(value.filter(v => items.some(i => i.value() === v))); + if (items && values.some(v => !items.some(i => i.value() === v))) { + this.values.set(values.filter(v => items.some(i => i.value() === v))); } }); } - onFocus() { + _onFocus() { this._hasFocused.set(true); } - register(child: TreeItem) { + _register(child: TreeItem) { this._unorderedItems().add(child); this._unorderedItems.set(new Set(this._unorderedItems())); } - unregister(child: TreeItem) { + _unregister(child: TreeItem) { this._unorderedItems().delete(child); this._unorderedItems.set(new Set(this._unorderedItems())); } -} - -/** - * A selectable and expandable Tree Item in a Tree. - */ -@Directive({ - selector: '[ngTreeItem]', - exportAs: 'ngTreeItem', - host: { - 'class': 'ng-treeitem', - '[attr.data-active]': 'pattern.active()', - 'role': 'treeitem', - '[id]': 'pattern.id()', - '[attr.aria-expanded]': 'pattern.expandable() ? pattern.expanded() : null', - '[attr.aria-selected]': 'pattern.selected()', - '[attr.aria-current]': 'pattern.current()', - '[attr.aria-disabled]': 'pattern.disabled()', - '[attr.aria-level]': 'pattern.level()', - '[attr.aria-setsize]': 'pattern.setsize()', - '[attr.aria-posinset]': 'pattern.posinset()', - '[attr.tabindex]': 'pattern.tabindex()', - }, -}) -export class TreeItem extends DeferredContentAware implements OnInit, OnDestroy, HasElement { - /** A reference to the tree item element. */ - private readonly _elementRef = inject(ElementRef); - - /** A unique identifier for the tree item. */ - private readonly _id = inject(_IdGenerator).getId('ng-tree-item-'); - - /** The owned tree item group. */ - private readonly _group = signal | undefined>(undefined); - - /** The host native element. */ - readonly element = computed(() => this._elementRef.nativeElement); - - /** The value of the tree item. */ - readonly value = input.required(); - - /** The parent tree root or tree item group. */ - readonly parent = input.required | TreeItemGroup>(); - - /** Whether the tree item is disabled. */ - readonly disabled = input(false, {transform: booleanAttribute}); - - /** Whether the tree item is selectable. */ - readonly selectable = input(true); - - /** Optional label for typeahead. Defaults to the element's textContent. */ - readonly label = input(); - - /** Search term for typeahead. */ - readonly searchTerm = computed(() => this.label() ?? this.element().textContent); - - /** The tree root. */ - readonly tree: Signal> = computed(() => { - if (this.parent() instanceof Tree) { - return this.parent() as Tree; - } - return (this.parent() as TreeItemGroup).ownedBy().tree(); - }); - - /** The UI pattern for this item. */ - pattern: TreeItemPattern; - - constructor() { - super(); - this.preserveContent.set(true); - // Connect the group's hidden state to the DeferredContentAware's visibility. - afterRenderEffect(() => { - this.tree().pattern instanceof ComboboxTreePattern - ? this.contentVisible.set(true) - : this.contentVisible.set(this.pattern.expanded()); - }); - } - - ngOnInit() { - this.parent().register(this); - this.tree().register(this); - - const treePattern = computed(() => this.tree().pattern); - const parentPattern = computed(() => { - if (this.parent() instanceof Tree) { - return treePattern(); - } - return (this.parent() as TreeItemGroup).ownedBy().pattern; - }); - this.pattern = new TreeItemPattern({ - ...this, - id: () => this._id, - tree: treePattern, - parent: parentPattern, - children: computed(() => this._group()?.children() ?? []), - hasChildren: computed(() => !!this._group()), - }); - } - - ngOnDestroy() { - this.parent().unregister(this); - this.tree().unregister(this); - } - - register(group: TreeItemGroup) { - this._group.set(group); - } - - unregister() { - this._group.set(undefined); - } -} - -/** - * Contains children tree itmes. - */ -@Directive({ - selector: 'ng-template[ngTreeItemGroup]', - exportAs: 'ngTreeItemGroup', - hostDirectives: [DeferredContent], -}) -export class TreeItemGroup implements OnInit, OnDestroy { - /** The DeferredContent host directive. */ - private readonly _deferredContent = inject(DeferredContent); - - /** All groupable items that are descendants of the group. */ - private readonly _unorderedItems = signal(new Set>()); - - /** Child items within this group. */ - readonly children = computed[]>(() => - [...this._unorderedItems()].sort(sortDirectives).map(c => c.pattern), - ); - - /** Tree item that owns the group. */ - readonly ownedBy = input.required>(); - - ngOnInit() { - this._deferredContent.deferredContentAware.set(this.ownedBy()); - this.ownedBy().register(this); - } - - ngOnDestroy() { - this.ownedBy().unregister(); - } - - register(child: TreeItem) { - this._unorderedItems().add(child); - this._unorderedItems.set(new Set(this._unorderedItems())); - } - unregister(child: TreeItem) { - this._unorderedItems().delete(child); - this._unorderedItems.set(new Set(this._unorderedItems())); + scrollActiveItemIntoView(options: ScrollIntoViewOptions = {block: 'nearest'}) { + this._pattern.inputs.activeItem()?.element()?.scrollIntoView(options); } } diff --git a/src/aria/tree/utils.ts b/src/aria/tree/utils.ts new file mode 100644 index 000000000000..656f7c79a5bb --- /dev/null +++ b/src/aria/tree/utils.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +export interface HasElement { + element: HTMLElement; +} + +/** + * Sort directives by their document order. + */ +export function sortDirectives(a: HasElement, b: HasElement) { + return (a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_PRECEDING) > 0 + ? 1 + : -1; +} diff --git a/src/aria/ui-patterns/BUILD.bazel b/src/aria/ui-patterns/BUILD.bazel deleted file mode 100644 index 2b19780986e7..000000000000 --- a/src/aria/ui-patterns/BUILD.bazel +++ /dev/null @@ -1,24 +0,0 @@ -load("//tools:defaults.bzl", "ts_project") - -package(default_visibility = ["//visibility:public"]) - -ts_project( - name = "ui-patterns", - srcs = glob( - ["**/*.ts"], - exclude = ["**/*.spec.ts"], - ), - deps = [ - "//:node_modules/@angular/core", - "//src/aria/ui-patterns/accordion", - "//src/aria/ui-patterns/behaviors/signal-like", - "//src/aria/ui-patterns/combobox", - "//src/aria/ui-patterns/grid", - "//src/aria/ui-patterns/listbox", - "//src/aria/ui-patterns/menu", - "//src/aria/ui-patterns/radio-group", - "//src/aria/ui-patterns/tabs", - "//src/aria/ui-patterns/toolbar", - "//src/aria/ui-patterns/tree", - ], -) diff --git a/src/aria/ui-patterns/accordion/accordion.ts b/src/aria/ui-patterns/accordion/accordion.ts deleted file mode 100644 index 3855da7f5b8b..000000000000 --- a/src/aria/ui-patterns/accordion/accordion.ts +++ /dev/null @@ -1,225 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {computed} from '@angular/core'; -import {KeyboardEventManager, PointerEventManager} from '../behaviors/event-manager'; -import { - ExpansionItem, - ExpansionControl, - ListExpansion, - ListExpansionInputs, -} from '../behaviors/expansion/expansion'; -import {ListFocus, ListFocusInputs, ListFocusItem} from '../behaviors/list-focus/list-focus'; -import { - ListNavigation, - ListNavigationInputs, - ListNavigationItem, -} from '../behaviors/list-navigation/list-navigation'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; - -/** Inputs of the AccordionGroupPattern. */ -export type AccordionGroupInputs = Omit< - ListNavigationInputs & - ListFocusInputs & - Omit, - 'focusMode' ->; - -const focusMode = () => 'roving' as const; - -export interface AccordionGroupPattern extends AccordionGroupInputs {} -/** A pattern controls the nested Accordions. */ -export class AccordionGroupPattern { - /** Controls navigation for the group. */ - navigation: ListNavigation; - - /** Controls focus for the group. */ - focusManager: ListFocus; - - /** Controls expansion for the group. */ - expansionManager: ListExpansion; - - constructor(readonly inputs: AccordionGroupInputs) { - this.wrap = inputs.wrap; - this.orientation = inputs.orientation; - this.textDirection = inputs.textDirection; - this.activeItem = inputs.activeItem; - this.disabled = inputs.disabled; - this.multiExpandable = inputs.multiExpandable; - this.items = inputs.items; - this.expandedIds = inputs.expandedIds; - this.skipDisabled = inputs.skipDisabled; - this.focusManager = new ListFocus({ - ...inputs, - focusMode, - }); - this.navigation = new ListNavigation({ - ...inputs, - focusMode, - focusManager: this.focusManager, - }); - this.expansionManager = new ListExpansion({ - ...inputs, - }); - } -} - -/** Inputs for the AccordionTriggerPattern. */ -export type AccordionTriggerInputs = Omit & - Omit & { - /** A local unique identifier for the trigger. */ - value: SignalLike; - - /** The parent accordion group that controls this trigger. */ - accordionGroup: SignalLike; - - /** The accordion panel controlled by this trigger. */ - accordionPanel: SignalLike; - }; - -export interface AccordionTriggerPattern extends AccordionTriggerInputs {} -/** A pattern controls the expansion state of an accordion. */ -export class AccordionTriggerPattern { - /** Whether this tab has expandable content. */ - expandable: SignalLike; - - /** The unique identifier used by the expansion behavior. */ - expansionId: SignalLike; - - /** Whether an accordion is expanded. */ - expanded: SignalLike; - - /** Controls the expansion state for the trigger. */ - expansionControl: ExpansionControl; - - /** Whether the trigger is active. */ - active = computed(() => this.inputs.accordionGroup().activeItem() === this); - - /** Id of the accordion panel controlled by the trigger. */ - controls = computed(() => this.inputs.accordionPanel()?.id()); - - /** The tabindex of the trigger. */ - tabindex = computed(() => (this.inputs.accordionGroup().focusManager.isFocusable(this) ? 0 : -1)); - - /** Whether the trigger is disabled. Disabling an accordion group disables all the triggers. */ - disabled = computed(() => this.inputs.disabled() || this.inputs.accordionGroup().disabled()); - - /** The index of the trigger within its accordion group. */ - index = computed(() => this.inputs.accordionGroup().items().indexOf(this)); - - constructor(readonly inputs: AccordionTriggerInputs) { - this.id = inputs.id; - this.element = inputs.element; - this.value = inputs.value; - this.expansionControl = new ExpansionControl({ - ...inputs, - expansionId: inputs.value, - expandable: () => true, - expansionManager: inputs.accordionGroup().expansionManager, - }); - this.expandable = this.expansionControl.isExpandable; - this.expansionId = this.expansionControl.expansionId; - this.expanded = this.expansionControl.isExpanded; - } - - /** The key used to navigate to the previous accordion trigger. */ - prevKey = computed(() => { - if (this.inputs.accordionGroup().orientation() === 'vertical') { - return 'ArrowUp'; - } - return this.inputs.accordionGroup().textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; - }); - - /** The key used to navigate to the next accordion trigger. */ - nextKey = computed(() => { - if (this.inputs.accordionGroup().orientation() === 'vertical') { - return 'ArrowDown'; - } - return this.inputs.accordionGroup().textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; - }); - - /** The keydown event manager for the accordion trigger. */ - keydown = computed(() => { - return new KeyboardEventManager() - .on(this.prevKey, () => this.inputs.accordionGroup().navigation.prev()) - .on(this.nextKey, () => this.inputs.accordionGroup().navigation.next()) - .on('Home', () => this.inputs.accordionGroup().navigation.first()) - .on('End', () => this.inputs.accordionGroup().navigation.last()) - .on(' ', () => this.expansionControl.toggle()) - .on('Enter', () => this.expansionControl.toggle()); - }); - - /** The pointerdown event manager for the accordion trigger. */ - pointerdown = computed(() => { - return new PointerEventManager().on(e => { - const item = this._getItem(e); - - if (item) { - this.inputs.accordionGroup().navigation.goto(item); - this.expansionControl.toggle(); - } - }); - }); - - /** Handles keydown events on the trigger, delegating to the group if not disabled. */ - onKeydown(event: KeyboardEvent): void { - this.keydown().handle(event); - } - - /** Handles pointerdown events on the trigger, delegating to the group if not disabled. */ - onPointerdown(event: PointerEvent): void { - this.pointerdown().handle(event); - } - - /** Handles focus events on the trigger. This ensures the tabbing changes the active index. */ - onFocus(event: FocusEvent): void { - const item = this._getItem(event); - - if (item && this.inputs.accordionGroup().focusManager.isFocusable(item)) { - this.inputs.accordionGroup().focusManager.focus(item); - } - } - - private _getItem(e: Event) { - if (!(e.target instanceof HTMLElement)) { - return; - } - - const element = e.target.closest('[role="button"]'); - return this.inputs - .accordionGroup() - .items() - .find(i => i.element() === element); - } -} - -/** Represents the required inputs for the AccordionPanelPattern. */ -export interface AccordionPanelInputs { - /** A global unique identifier for the panel. */ - id: SignalLike; - - /** A local unique identifier for the panel, matching its trigger's value. */ - value: SignalLike; - - /** The parent accordion trigger that controls this panel. */ - accordionTrigger: SignalLike; -} - -export interface AccordionPanelPattern extends AccordionPanelInputs {} -/** Represents an accordion panel. */ -export class AccordionPanelPattern { - /** Whether the accordion panel is hidden. True if the associated trigger is not expanded. */ - hidden: SignalLike; - - constructor(readonly inputs: AccordionPanelInputs) { - this.id = inputs.id; - this.value = inputs.value; - this.accordionTrigger = inputs.accordionTrigger; - this.hidden = computed(() => inputs.accordionTrigger()?.expanded() === false); - } -} diff --git a/src/aria/ui-patterns/behaviors/expansion/expansion.ts b/src/aria/ui-patterns/behaviors/expansion/expansion.ts deleted file mode 100644 index 7c0ed74b9fe7..000000000000 --- a/src/aria/ui-patterns/behaviors/expansion/expansion.ts +++ /dev/null @@ -1,128 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ -import {computed} from '@angular/core'; -import {SignalLike, WritableSignalLike} from '../signal-like/signal-like'; - -/** Represents an item that can be expanded or collapsed. */ -export interface ExpansionItem { - /** Whether the item is expandable. */ - expandable: SignalLike; - - /** Used to uniquely identify an expansion item. */ - expansionId: SignalLike; - - /** Whether the expansion is disabled. */ - disabled: SignalLike; -} - -export interface ExpansionControl extends ExpansionItem {} -/** - * Controls a single item's expansion state and interactions, - * delegating actual state changes to an Expansion manager. - */ -export class ExpansionControl { - /** Whether this specific item is currently expanded. Derived from the Expansion manager. */ - readonly isExpanded = computed(() => this.inputs.expansionManager.isExpanded(this)); - - /** Whether this item can be expanded. */ - readonly isExpandable = computed(() => this.inputs.expansionManager.isExpandable(this)); - - constructor(readonly inputs: ExpansionItem & {expansionManager: ListExpansion}) { - this.expansionId = inputs.expansionId; - this.expandable = inputs.expandable; - this.disabled = inputs.disabled; - } - - /** Requests the Expansion manager to open this item. */ - open() { - this.inputs.expansionManager.open(this); - } - - /** Requests the Expansion manager to close this item. */ - close() { - this.inputs.expansionManager.close(this); - } - - /** Requests the Expansion manager to toggle this item. */ - toggle() { - this.inputs.expansionManager.toggle(this); - } -} - -/** Represents the required inputs for an expansion behavior. */ -export interface ListExpansionInputs { - /** Whether multiple items can be expanded at once. */ - multiExpandable: SignalLike; - - /** An array of ids of the currently expanded items. */ - expandedIds: WritableSignalLike; - - /** An array of expansion items. */ - items: SignalLike; - - /** Whether all expansions are disabled. */ - disabled: SignalLike; -} - -/** Manages the expansion state of a list of items. */ -export class ListExpansion { - /** A signal holding an array of ids of the currently expanded items. */ - expandedIds: WritableSignalLike; - - constructor(readonly inputs: ListExpansionInputs) { - this.expandedIds = inputs.expandedIds; - } - - /** Opens the specified item. */ - open(item: ExpansionItem) { - if (!this.isExpandable(item)) return; - if (this.isExpanded(item)) return; - if (!this.inputs.multiExpandable()) { - this.closeAll(); - } - this.expandedIds.update(ids => ids.concat(item.expansionId())); - } - - /** Closes the specified item. */ - close(item: ExpansionItem) { - if (this.isExpandable(item)) { - this.expandedIds.update(ids => ids.filter(id => id !== item.expansionId())); - } - } - - /** Toggles the expansion state of the specified item. */ - toggle(item: ExpansionItem) { - this.expandedIds().includes(item.expansionId()) ? this.close(item) : this.open(item); - } - - /** Opens all focusable items in the list. */ - openAll() { - if (this.inputs.multiExpandable()) { - for (const item of this.inputs.items()) { - this.open(item); - } - } - } - - /** Closes all focusable items in the list. */ - closeAll() { - for (const item of this.inputs.items()) { - this.close(item); - } - } - - /** Checks whether the specified item is expandable / collapsible. */ - isExpandable(item: ExpansionItem) { - return !this.inputs.disabled() && !item.disabled() && item.expandable(); - } - - /** Checks whether the specified item is currently expanded. */ - isExpanded(item: ExpansionItem): boolean { - return this.expandedIds().includes(item.expansionId()); - } -} diff --git a/src/aria/ui-patterns/behaviors/grid/BUILD.bazel b/src/aria/ui-patterns/behaviors/grid/BUILD.bazel deleted file mode 100644 index 551c00f0bfb3..000000000000 --- a/src/aria/ui-patterns/behaviors/grid/BUILD.bazel +++ /dev/null @@ -1,15 +0,0 @@ -load("//tools:defaults.bzl", "ts_project") - -package(default_visibility = ["//visibility:public"]) - -ts_project( - name = "grid", - srcs = glob( - ["**/*.ts"], - exclude = ["**/*.spec.ts"], - ), - deps = [ - "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/signal-like", - ], -) diff --git a/src/aria/ui-patterns/behaviors/grid/grid.ts b/src/aria/ui-patterns/behaviors/grid/grid.ts deleted file mode 100644 index f6a2e46bab65..000000000000 --- a/src/aria/ui-patterns/behaviors/grid/grid.ts +++ /dev/null @@ -1,262 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {computed, linkedSignal} from '@angular/core'; -import {SignalLike} from '../signal-like/signal-like'; -import {GridData, BaseGridCell, GridDataInputs, RowCol} from './grid-data'; -import {GridFocus, GridFocusCell, GridFocusInputs} from './grid-focus'; -import { - direction, - GridNavigation, - GridNavigationCell, - GridNavigationInputs, -} from './grid-navigation'; -import {GridSelectionCell, GridSelectionInputs, GridSelection} from './grid-selection'; - -/** A type that represents a cell in a grid, combining all cell-related interfaces. */ -export type GridCell = BaseGridCell & GridFocusCell & GridNavigationCell & GridSelectionCell; - -/** Represents the required inputs for a grid. */ -export interface GridInputs - extends GridDataInputs, - GridFocusInputs, - GridNavigationInputs, - GridSelectionInputs { - /** Whether selection is enabled for the grid. */ - enableSelection: SignalLike; -} - -/** The main class that orchestrates the grid behaviors. */ -export class Grid { - /** The underlying data structure for the grid. */ - readonly data: GridData; - - /** Controls focus for the grid. */ - readonly focusBehavior: GridFocus; - - /** Controls navigation for the grid. */ - readonly navigationBehavior: GridNavigation; - - /** Controls selection for the grid. */ - readonly selectionBehavior: GridSelection; - - /** The anchor point for range selection, linked to the active coordinates. */ - readonly selectionAnchor = linkedSignal(() => this.focusBehavior.activeCoords()); - - /** The `tabindex` for the grid container. */ - readonly gridTabIndex = computed(() => this.focusBehavior.gridTabIndex()); - - /** Whether the grid is in a disabled state. */ - readonly gridDisabled = computed(() => this.focusBehavior.gridDisabled()); - - /** The ID of the active descendant for ARIA `activedescendant` focus management. */ - readonly activeDescendant = computed(() => this.focusBehavior.activeDescendant()); - - constructor(readonly inputs: GridInputs) { - this.data = new GridData(inputs); - this.focusBehavior = new GridFocus({...inputs, grid: this.data}); - this.navigationBehavior = new GridNavigation({ - ...inputs, - grid: this.data, - gridFocus: this.focusBehavior, - }); - this.selectionBehavior = new GridSelection({ - ...inputs, - grid: this.data, - gridFocus: this.focusBehavior, - }); - } - - /** Gets the 1-based row index of a cell. */ - rowIndex(cell: T): number | undefined { - const index = this.data.getCoords(cell)?.row; - return index !== undefined ? index + 1 : undefined; - } - - /** Gets the 1-based column index of a cell. */ - colIndex(cell: T): number | undefined { - const index = this.data.getCoords(cell)?.col; - return index !== undefined ? index + 1 : undefined; - } - - /** Gets the `tabindex` for a given cell. */ - cellTabIndex(cell: T): -1 | 0 { - return this.focusBehavior.getCellTabindex(cell); - } - - /** Navigates to the cell above the currently active cell. */ - up(): boolean { - return this.navigationBehavior.advance(direction.Up); - } - - /** Extends the selection to the cell above the selection anchor. */ - rangeSelectUp(): void { - const coords = this.navigationBehavior.peek(direction.Up, this.selectionAnchor()); - if (coords === undefined) return; - - this._rangeSelectCoords(coords); - } - - /** Navigates to the cell below the currently active cell. */ - down(): boolean { - return this.navigationBehavior.advance(direction.Down); - } - - /** Extends the selection to the cell below the selection anchor. */ - rangeSelectDown(): void { - const coords = this.navigationBehavior.peek(direction.Down, this.selectionAnchor()); - if (coords === undefined) return; - - this._rangeSelectCoords(coords); - } - - /** Navigates to the cell to the left of the currently active cell. */ - left(): boolean { - return this.navigationBehavior.advance(direction.Left); - } - - /** Extends the selection to the cell to the left of the selection anchor. */ - rangeSelectLeft(): void { - const coords = this.navigationBehavior.peek(direction.Left, this.selectionAnchor()); - if (coords === undefined) return; - - this._rangeSelectCoords(coords); - } - - /** Navigates to the cell to the right of the currently active cell. */ - right(): boolean { - return this.navigationBehavior.advance(direction.Right); - } - - /** Extends the selection to the cell to the right of the selection anchor. */ - rangeSelectRight(): void { - const coords = this.navigationBehavior.peek(direction.Right, this.selectionAnchor()); - if (coords === undefined) return; - - this._rangeSelectCoords(coords); - } - - /** Navigates to the first focusable cell in the grid. */ - first(): boolean { - return this.navigationBehavior.first(); - } - - /** Navigates to the first focusable cell in the current row. */ - firstInRow(): boolean { - return this.navigationBehavior.first(this.focusBehavior.activeCoords().row); - } - - /** Navigates to the last focusable cell in the grid. */ - last(): boolean { - return this.navigationBehavior.last(); - } - - /** Navigates to the last focusable cell in the current row. */ - lastInRow(): boolean { - return this.navigationBehavior.last(this.focusBehavior.activeCoords().row); - } - - /** Selects all cells in the current row. */ - selectRow(): void { - const row = this.focusBehavior.activeCoords().row; - this.selectionBehavior.deselectAll(); - this.selectionBehavior.select({row, col: 0}, {row, col: this.data.maxColCount()}); - } - - /** Selects all cells in the current column. */ - selectCol(): void { - const col = this.focusBehavior.activeCoords().col; - this.selectionBehavior.deselectAll(); - this.selectionBehavior.select({row: 0, col}, {row: this.data.maxRowCount(), col}); - } - - /** Selects all selectable cells in the grid. */ - selectAll(): void { - this.selectionBehavior.selectAll(); - } - - /** Navigates to and focuses the given cell. */ - gotoCell(cell: T): boolean { - return this.navigationBehavior.gotoCell(cell); - } - - /** Toggles the selection state of the given cell. */ - toggleSelect(cell: T): void { - const coords = this.data.getCoords(cell); - if (coords === undefined) return; - - this.selectionBehavior.toggle(coords); - } - - /** Extends the selection from the anchor to the given cell. */ - rangeSelect(cell: T): void { - const coords = this.data.getCoords(cell); - if (coords === undefined) return; - - this._rangeSelectCoords(coords); - } - - /** Extends the selection to the given coordinates. */ - private _rangeSelectCoords(coords: RowCol): void { - const activeCell = this.focusBehavior.activeCell(); - const anchorCell = this.data.getCell(coords); - if (activeCell === undefined || anchorCell === undefined) { - return; - } - - const allCoords = [ - ...this.data.getAllCoords(activeCell)!, - ...this.data.getAllCoords(anchorCell)!, - ]; - const allRows = allCoords.map(c => c.row); - const allCols = allCoords.map(c => c.col); - const fromCoords = { - row: Math.min(...allRows), - col: Math.min(...allCols), - }; - const toCoords = { - row: Math.max(...allRows), - col: Math.max(...allCols), - }; - - this.selectionBehavior.deselectAll(); - this.selectionBehavior.select(fromCoords, toCoords); - this.selectionAnchor.set(coords); - } - - /** Resets the active state of the grid if it is empty or stale. */ - resetState(): boolean { - if (this.focusBehavior.stateEmpty()) { - const firstFocusableCoords = this.navigationBehavior.peekFirst(); - if (firstFocusableCoords === undefined) { - return false; - } - - return this.focusBehavior.focusCoordinates(firstFocusableCoords); - } - - if (this.focusBehavior.stateStale()) { - // Try focus on the same active cell after if a reordering happened. - if (this.focusBehavior.focusCell(this.focusBehavior.activeCell()!)) { - return true; - } - - // If the active cell is no longer exist, focus on the coordinates instead. - if (this.focusBehavior.focusCoordinates(this.focusBehavior.activeCoords())) { - return true; - } - - // If the cooridnates no longer valid, go back to the first available cell. - if (this.focusBehavior.focusCoordinates(this.navigationBehavior.peekFirst()!)) { - return true; - } - } - - return false; - } -} diff --git a/src/aria/ui-patterns/behaviors/signal-like/signal-like.ts b/src/aria/ui-patterns/behaviors/signal-like/signal-like.ts deleted file mode 100644 index 5717dd3b8d6d..000000000000 --- a/src/aria/ui-patterns/behaviors/signal-like/signal-like.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -export type SignalLike = () => T; - -export interface WritableSignalLike extends SignalLike { - set(value: T): void; - update(updateFn: (value: T) => T): void; -} - -/** Converts a getter setter style signal to a WritableSignalLike. */ -export function convertGetterSetterToWritableSignalLike( - getter: () => T, - setter: (v: T) => void, -): WritableSignalLike { - // tslint:disable-next-line:ban Have to use `Object.assign` to preserve the getter function. - return Object.assign(getter, { - set: setter, - update: (updateCallback: (v: T) => T) => setter(updateCallback(getter())), - }); -} diff --git a/src/aria/ui-patterns/grid/cell.ts b/src/aria/ui-patterns/grid/cell.ts deleted file mode 100644 index 4ab9c2b8ff49..000000000000 --- a/src/aria/ui-patterns/grid/cell.ts +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {computed} from '@angular/core'; -import {SignalLike, WritableSignalLike} from '../behaviors/signal-like/signal-like'; -import {GridCell} from '../behaviors/grid'; -import type {GridPattern} from './grid'; -import type {GridRowPattern} from './row'; -import type {GridCellWidgetPattern} from './widget'; - -/** The inputs for the `GridCellPattern`. */ -export interface GridCellInputs extends GridCell { - /** The `GridPattern` that this cell belongs to. */ - grid: SignalLike; - - /** The `GridRowPattern` that this cell belongs to. */ - row: SignalLike; - - /** The widget pattern contained within this cell, if any. */ - widget: SignalLike; - - /** The index of this cell's row within the grid. */ - rowIndex: SignalLike; - - /** The index of this cell's column within the grid. */ - colIndex: SignalLike; -} - -/** The UI pattern for a grid cell. */ -export class GridCellPattern implements GridCell { - /** A unique identifier for the cell. */ - readonly id: SignalLike; - - /** Whether a cell is disabled. */ - readonly disabled: SignalLike; - - /** Whether the cell is selected. */ - readonly selected: WritableSignalLike; - - /** Whether the cell is selectable. */ - readonly selectable: SignalLike; - - /** The number of rows the cell should span. */ - readonly rowSpan: SignalLike; - - /** The number of columns the cell should span. */ - readonly colSpan: SignalLike; - - /** The `aria-selected` attribute for the cell. */ - readonly ariaSelected = computed(() => - this.inputs.grid().inputs.enableSelection() && this.selectable() ? this.selected() : undefined, - ); - - /** The `aria-rowindex` attribute for the cell. */ - readonly ariaRowIndex = computed( - () => - this.inputs.row().rowIndex() ?? - this.inputs.rowIndex() ?? - this.inputs.grid().gridBehavior.rowIndex(this), - ); - - /** The `aria-colindex` attribute for the cell. */ - readonly ariaColIndex = computed( - () => this.inputs.colIndex() ?? this.inputs.grid().gridBehavior.colIndex(this), - ); - - /** The html element that should receive focus. */ - readonly element: SignalLike = computed( - () => this.inputs.widget()?.element() ?? this.inputs.element(), - ); - - /** Whether the cell is active. */ - readonly active = computed(() => this.inputs.grid().activeCell() === this); - - /** The internal tab index calculation for the cell. */ - private readonly _tabIndex: SignalLike<-1 | 0> = computed(() => - this.inputs.grid().gridBehavior.cellTabIndex(this), - ); - - /** The `tabindex` for the cell. If the cell contains a widget, the cell's tabindex is -1. */ - readonly tabIndex: SignalLike<-1 | 0> = computed(() => - this.inputs.widget() !== undefined ? -1 : this._tabIndex(), - ); - - /** Whether the widget within the cell is activated. */ - readonly widgetActivated: SignalLike = computed( - () => this.inputs.widget()?.inputs.activate() ?? false, - ); - - constructor(readonly inputs: GridCellInputs) { - this.id = inputs.id; - this.disabled = inputs.disabled; - this.rowSpan = inputs.rowSpan; - this.colSpan = inputs.colSpan; - this.selected = inputs.selected; - this.selectable = inputs.selectable; - } - - /** Gets the `tabindex` for the widget within the cell. */ - widgetTabIndex(): -1 | 0 { - return this._tabIndex(); - } -} diff --git a/src/aria/ui-patterns/grid/grid.ts b/src/aria/ui-patterns/grid/grid.ts deleted file mode 100644 index 00480ab38f9e..000000000000 --- a/src/aria/ui-patterns/grid/grid.ts +++ /dev/null @@ -1,243 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {computed, signal} from '@angular/core'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; -import {KeyboardEventManager, PointerEventManager, Modifier} from '../behaviors/event-manager'; -import {Grid, GridInputs as GridBehaviorInputs} from '../behaviors/grid'; -import type {GridRowPattern} from './row'; -import type {GridCellPattern} from './cell'; - -/** Represents the required inputs for the grid pattern. */ -export interface GridInputs extends Omit, 'cells'> { - /** The html element of the grid. */ - element: SignalLike; - - /** The rows that make up the grid. */ - rows: SignalLike; - - /** A function that returns the grid cell associated with a given element. */ - getCell: (e: Element) => GridCellPattern | undefined; -} - -/** The UI pattern for a grid, handling keyboard navigation, focus, and selection. */ -export class GridPattern { - /** The underlying grid behavior that this pattern is built on. */ - readonly gridBehavior: Grid; - - /** The cells in the grid. */ - readonly cells = computed(() => this.gridBehavior.data.cells()); - - /** The tab index for the grid. */ - readonly tabIndex = computed(() => this.gridBehavior.gridTabIndex()); - - /** Whether the grid is disabled. */ - readonly disabled = computed(() => this.gridBehavior.gridDisabled()); - - /** The ID of the currently active descendant cell. */ - readonly activeDescendant = computed(() => this.gridBehavior.activeDescendant()); - - /** The currently active cell. */ - readonly activeCell = computed(() => this.gridBehavior.focusBehavior.activeCell()); - - /** Whether to pause grid navigation. */ - readonly pauseNavigation = computed(() => - this.gridBehavior.data - .cells() - .flat() - .reduce((res, c) => res || c.widgetActivated(), false), - ); - - /** Whether the focus is in the grid. */ - readonly isFocused = signal(false); - - /** Whether the user is currently dragging to select a range of cells. */ - readonly dragging = signal(false); - - /** The keydown event manager for the grid. */ - readonly keydown = computed(() => { - const manager = new KeyboardEventManager(); - - if (this.pauseNavigation()) { - return manager; - } - - manager - .on('ArrowUp', () => this.gridBehavior.up()) - .on('ArrowDown', () => this.gridBehavior.down()) - .on('ArrowLeft', () => this.gridBehavior.left()) - .on('ArrowRight', () => this.gridBehavior.right()) - .on('Home', () => this.gridBehavior.firstInRow()) - .on('End', () => this.gridBehavior.lastInRow()) - .on([Modifier.Ctrl], 'Home', () => this.gridBehavior.first()) - .on([Modifier.Ctrl], 'End', () => this.gridBehavior.last()); - - if (this.inputs.enableSelection()) { - manager - .on(Modifier.Shift, 'ArrowUp', () => this.gridBehavior.rangeSelectUp()) - .on(Modifier.Shift, 'ArrowDown', () => this.gridBehavior.rangeSelectDown()) - .on(Modifier.Shift, 'ArrowLeft', () => this.gridBehavior.rangeSelectLeft()) - .on(Modifier.Shift, 'ArrowRight', () => this.gridBehavior.rangeSelectRight()) - .on([Modifier.Ctrl, Modifier.Meta], 'A', () => this.gridBehavior.selectAll()) - .on([Modifier.Shift], ' ', () => this.gridBehavior.selectRow()) - .on([Modifier.Ctrl, Modifier.Meta], ' ', () => this.gridBehavior.selectCol()); - } - - return manager; - }); - - /** The pointerdown event manager for the grid. */ - readonly pointerdown = computed(() => { - const manager = new PointerEventManager(); - - manager.on(e => { - const cell = this.inputs.getCell(e.target as Element); - if (!cell) return; - - this.gridBehavior.gotoCell(cell); - - if (this.inputs.enableSelection()) { - this.dragging.set(true); - } - }); - - if (this.inputs.enableSelection()) { - manager - .on([Modifier.Ctrl, Modifier.Meta], e => { - const cell = this.inputs.getCell(e.target as Element); - if (!cell) return; - - this.gridBehavior.toggleSelect(cell); - }) - .on(Modifier.Shift, e => { - const cell = this.inputs.getCell(e.target as Element); - if (!cell) return; - - this.gridBehavior.rangeSelect(cell); - this.dragging.set(true); - }); - } - - return manager; - }); - - /** The pointerup event manager for the grid. */ - readonly pointerup = computed(() => { - const manager = new PointerEventManager(); - - if (this.inputs.enableSelection()) { - manager.on([Modifier.Shift, Modifier.None], () => { - this.dragging.set(false); - }); - } - - return manager; - }); - - constructor(readonly inputs: GridInputs) { - this.gridBehavior = new Grid({ - ...inputs, - cells: computed(() => this.inputs.rows().map(row => row.inputs.cells())), - }); - } - - /** Handles keydown events on the grid. */ - onKeydown(event: KeyboardEvent) { - if (!this.disabled()) { - this.keydown().handle(event); - } - } - - /** Handles pointerdown events on the grid. */ - onPointerdown(event: PointerEvent) { - if (!this.disabled()) { - this.pointerdown().handle(event); - } - } - - /** Handles pointermove events on the grid. */ - onPointermove(event: PointerEvent) { - if (this.disabled()) return; - if (!this.inputs.enableSelection()) return; - if (!this.dragging()) return; - - const cell = this.inputs.getCell(event.target as Element); - if (!cell) return; - - this.gridBehavior.rangeSelect(cell); - } - - /** Handles pointerup events on the grid. */ - onPointerup(event: PointerEvent) { - if (!this.disabled()) { - this.pointerup().handle(event); - } - } - - /** Handles focusin events on the grid. */ - onFocusIn(event: FocusEvent) { - this.isFocused.set(true); - - const cell = this.inputs.getCell(event.target as Element); - if (!cell) return; - - this.gridBehavior.gotoCell(cell); - } - - /** Indicates maybe the losing focus is caused by row/cell deletion. */ - private readonly _maybeDeletion = signal(false); - - /** Handles focusout events on the grid. */ - onFocusOut(event: FocusEvent) { - const parentEl = this.inputs.element(); - const targetEl = event.relatedTarget as Node | null; - - // If a `relatedTarget` is null, then it can be caused by either - // - Clicking on a non-focusable element, or - // - The focused element is removed from the page. - if (targetEl === null) { - this._maybeDeletion.set(true); - } - - if (parentEl.contains(targetEl)) return; - this.isFocused.set(false); - } - - /** Indicates the losing focus is certainly caused by row/cell deletion. */ - private readonly _deletion = signal(false); - - /** Resets the active state of the grid if it is empty or stale. */ - resetStateEffect(): void { - const hasReset = this.gridBehavior.resetState(); - - // If the active state has been reset right after a focusout event, then - // we know it's caused by a row/cell deletion. - if (hasReset && this._maybeDeletion()) { - this._deletion.set(true); - } - - if (this._maybeDeletion()) { - this._maybeDeletion.set(false); - } - } - - /** Focuses on the active cell element. */ - focusEffect(): void { - const activeCell = this.activeCell(); - const hasFocus = this.isFocused(); - const deletion = this._deletion(); - const isRoving = this.inputs.focusMode() === 'roving'; - if (activeCell !== undefined && isRoving && (hasFocus || deletion)) { - activeCell.element().focus(); - - if (deletion) { - this._deletion.set(false); - } - } - } -} diff --git a/src/aria/ui-patterns/grid/widget.ts b/src/aria/ui-patterns/grid/widget.ts deleted file mode 100644 index e25688dcda5b..000000000000 --- a/src/aria/ui-patterns/grid/widget.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {computed} from '@angular/core'; -import {SignalLike, WritableSignalLike} from '../behaviors/signal-like/signal-like'; -import type {GridCellPattern} from './cell'; - -/** The inputs for the `GridCellWidgetPattern`. */ -export interface GridCellWidgetInputs { - /** The `GridCellPattern` that this widget belongs to. */ - cell: SignalLike; - - /** The html element that should receive focus. */ - element: SignalLike; - - /** - * Whether the widget is activated, which pauses grid navigation to allow interaction - * with the widget. - */ - activate: WritableSignalLike; -} - -/** The UI pattern for a widget inside a grid cell. */ -export class GridCellWidgetPattern { - /** The html element that should receive focus. */ - readonly element: SignalLike; - - /** The `tabindex` for the widget. */ - readonly tabIndex: SignalLike<-1 | 0> = computed(() => this.inputs.cell().widgetTabIndex()); - - /** Whether the widget is in an active state (i.e. its containing cell is active). */ - readonly active: SignalLike = computed(() => this.inputs.cell().active()); - - constructor(readonly inputs: GridCellWidgetInputs) { - this.element = inputs.element; - } -} diff --git a/src/aria/ui-patterns/radio-group/BUILD.bazel b/src/aria/ui-patterns/radio-group/BUILD.bazel deleted file mode 100644 index 27756de9c140..000000000000 --- a/src/aria/ui-patterns/radio-group/BUILD.bazel +++ /dev/null @@ -1,37 +0,0 @@ -load("//tools:defaults.bzl", "ng_project", "ng_web_test_suite", "ts_project") - -package(default_visibility = ["//visibility:public"]) - -ts_project( - name = "radio-group", - srcs = [ - "radio-button.ts", - "radio-group.ts", - "toolbar-radio-group.ts", - ], - deps = [ - "//:node_modules/@angular/core", - "//src/aria/ui-patterns/behaviors/event-manager", - "//src/aria/ui-patterns/behaviors/list", - "//src/aria/ui-patterns/behaviors/signal-like", - "//src/aria/ui-patterns/toolbar", - ], -) - -ng_project( - name = "unit_test_sources", - testonly = True, - srcs = glob(["**/*.spec.ts"]), - deps = [ - ":radio-group", - "//:node_modules/@angular/core", - "//src/aria/ui-patterns/toolbar", - "//src/cdk/keycodes", - "//src/cdk/testing/private", - ], -) - -ng_web_test_suite( - name = "unit_tests", - deps = [":unit_test_sources"], -) diff --git a/src/aria/ui-patterns/radio-group/radio-button.ts b/src/aria/ui-patterns/radio-group/radio-button.ts deleted file mode 100644 index 5c4258301057..000000000000 --- a/src/aria/ui-patterns/radio-group/radio-button.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {computed} from '@angular/core'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; -import {ListItem} from '../behaviors/list/list'; -import type {RadioGroupPattern} from './radio-group'; - -/** Represents the required inputs for a radio button in a radio group. */ -export interface RadioButtonInputs - extends Omit, 'searchTerm' | 'index' | 'selectable'> { - /** A reference to the parent radio group. */ - group: SignalLike | undefined>; -} - -/** Represents a radio button within a radio group. */ -export class RadioButtonPattern { - /** A unique identifier for the radio button. */ - readonly id: SignalLike; - - /** The value associated with the radio button. */ - readonly value: SignalLike; - - /** The position of the radio button within the group. */ - readonly index: SignalLike = computed( - () => this.group()?.listBehavior.inputs.items().indexOf(this) ?? -1, - ); - - /** Whether the radio button is currently the active one (focused). */ - readonly active = computed(() => this.group()?.listBehavior.inputs.activeItem() === this); - - /** Whether the radio button is selected. */ - readonly selected: SignalLike = computed( - () => !!this.group()?.listBehavior.inputs.value().includes(this.value()), - ); - - /** Whether the radio button is selectable. */ - readonly selectable = () => true; - - /** Whether the radio button is disabled. */ - readonly disabled: SignalLike; - - /** A reference to the parent radio group. */ - readonly group: SignalLike | undefined>; - - /** The tabindex of the radio button. */ - readonly tabindex = computed(() => this.group()?.listBehavior.getItemTabindex(this)); - - /** The HTML element associated with the radio button. */ - readonly element: SignalLike; - - /** The search term for typeahead. */ - readonly searchTerm = () => ''; // Radio groups do not support typeahead. - - constructor(readonly inputs: RadioButtonInputs) { - this.id = inputs.id; - this.value = inputs.value; - this.group = inputs.group; - this.element = inputs.element; - this.disabled = inputs.disabled; - } -} diff --git a/src/aria/ui-patterns/radio-group/radio-group.ts b/src/aria/ui-patterns/radio-group/radio-group.ts deleted file mode 100644 index 93026a3decd9..000000000000 --- a/src/aria/ui-patterns/radio-group/radio-group.ts +++ /dev/null @@ -1,175 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {computed, signal} from '@angular/core'; -import {KeyboardEventManager, PointerEventManager} from '../behaviors/event-manager'; -import {List, ListInputs} from '../behaviors/list/list'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; -import {RadioButtonPattern} from './radio-button'; - -/** Represents the required inputs for a radio group. */ -export type RadioGroupInputs = Omit< - ListInputs, V>, - 'multi' | 'selectionMode' | 'wrap' | 'typeaheadDelay' -> & { - /** Whether the radio group is disabled. */ - disabled: SignalLike; - - /** Whether the radio group is readonly. */ - readonly: SignalLike; - - /** A function that returns the radio button associated with a given element. */ - getItem: (e: PointerEvent) => RadioButtonPattern | undefined; -}; - -/** Controls the state of a radio group. */ -export class RadioGroupPattern { - /** The list behavior for the radio group. */ - readonly listBehavior: List, V>; - - /** Whether the radio group is vertically or horizontally oriented. */ - readonly orientation: SignalLike<'vertical' | 'horizontal'>; - - /** Whether focus should wrap when navigating. */ - readonly wrap = signal(false); - - /** The selection strategy used by the radio group. */ - readonly selectionMode = signal<'follow' | 'explicit'>('follow'); - - /** Whether the radio group is disabled. */ - readonly disabled = computed(() => this.inputs.disabled() || this.listBehavior.disabled()); - - /** The currently selected radio button. */ - readonly selectedItem = computed(() => this.listBehavior.selectionBehavior.selectedItems()[0]); - - /** Whether the radio group is readonly. */ - readonly readonly = computed(() => this.selectedItem()?.disabled() || this.inputs.readonly()); - - /** The tabindex of the radio group. */ - readonly tabindex = computed(() => this.listBehavior.tabindex()); - - /** The id of the current active radio button (if using activedescendant). */ - readonly activedescendant = computed(() => this.listBehavior.activedescendant()); - - /** The key used to navigate to the previous radio button. */ - private readonly _prevKey = computed(() => { - if (this.inputs.orientation() === 'vertical') { - return 'ArrowUp'; - } - return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; - }); - - /** The key used to navigate to the next radio button. */ - private readonly _nextKey = computed(() => { - if (this.inputs.orientation() === 'vertical') { - return 'ArrowDown'; - } - return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; - }); - - /** The keydown event manager for the radio group. */ - readonly keydown = computed(() => { - const manager = new KeyboardEventManager(); - - // Readonly mode allows navigation but not selection changes. - if (this.readonly()) { - return manager - .on(this._prevKey, () => this.listBehavior.prev()) - .on(this._nextKey, () => this.listBehavior.next()) - .on('Home', () => this.listBehavior.first()) - .on('End', () => this.listBehavior.last()); - } - - // Default behavior: navigate and select on arrow keys, home, end. - // Space/Enter also select the focused item. - return manager - .on(this._prevKey, () => this.listBehavior.prev({selectOne: true})) - .on(this._nextKey, () => this.listBehavior.next({selectOne: true})) - .on('Home', () => this.listBehavior.first({selectOne: true})) - .on('End', () => this.listBehavior.last({selectOne: true})) - .on(' ', () => this.listBehavior.selectOne()) - .on('Enter', () => this.listBehavior.selectOne()); - }); - - /** The pointerdown event manager for the radio group. */ - readonly pointerdown = computed(() => { - const manager = new PointerEventManager(); - - if (this.readonly()) { - // Navigate focus only in readonly mode. - return manager.on(e => this.listBehavior.goto(this.inputs.getItem(e)!)); - } - - // Default behavior: navigate and select on click. - return manager.on(e => this.listBehavior.goto(this.inputs.getItem(e)!, {selectOne: true})); - }); - - constructor(readonly inputs: RadioGroupInputs) { - this.orientation = inputs.orientation; - this.listBehavior = new List({ - ...inputs, - wrap: this.wrap, - selectionMode: this.selectionMode, - multi: () => false, - typeaheadDelay: () => 0, // Radio groups do not support typeahead. - }); - } - - /** Handles keydown events for the radio group. */ - onKeydown(event: KeyboardEvent) { - if (!this.disabled()) { - this.keydown().handle(event); - } - } - - /** Handles pointerdown events for the radio group. */ - onPointerdown(event: PointerEvent) { - if (!this.disabled()) { - this.pointerdown().handle(event); - } - } - - /** - * Sets the radio group to its default initial state. - * - * Sets the active index to the selected radio button if one exists and is focusable. - * Otherwise, sets the active index to the first focusable radio button. - */ - setDefaultState() { - let firstItem: RadioButtonPattern | null = null; - - for (const item of this.inputs.items()) { - if (this.listBehavior.isFocusable(item)) { - if (!firstItem) { - firstItem = item; - } - if (item.selected()) { - this.inputs.activeItem.set(item); - return; - } - } - } - - if (firstItem) { - this.inputs.activeItem.set(firstItem); - } - } - - /** Validates the state of the radio group and returns a list of accessibility violations. */ - validate(): string[] { - const violations: string[] = []; - - if (this.selectedItem()?.disabled() && this.inputs.skipDisabled()) { - violations.push( - "Accessibility Violation: The selected radio button is disabled while 'skipDisabled' is true, making the selection unreachable via keyboard.", - ); - } - - return violations; - } -} diff --git a/src/aria/ui-patterns/radio-group/radio.spec.ts b/src/aria/ui-patterns/radio-group/radio.spec.ts deleted file mode 100644 index adff7b0ac5d2..000000000000 --- a/src/aria/ui-patterns/radio-group/radio.spec.ts +++ /dev/null @@ -1,308 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {signal, WritableSignal} from '@angular/core'; -import {RadioGroupInputs, RadioGroupPattern} from './radio-group'; -import {RadioButtonPattern} from './radio-button'; -import {createKeyboardEvent} from '@angular/cdk/testing/private'; -import {ModifierKeys} from '@angular/cdk/testing'; - -type TestInputs = RadioGroupInputs; -type TestRadio = RadioButtonPattern & { - disabled: WritableSignal; -}; -type TestRadioGroup = RadioGroupPattern; - -const up = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 38, 'ArrowUp', mods); -const down = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 40, 'ArrowDown', mods); -const left = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 37, 'ArrowLeft', mods); -const right = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 39, 'ArrowRight', mods); -const home = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 36, 'Home', mods); -const end = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 35, 'End', mods); -const space = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 32, ' ', mods); -const enter = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 13, 'Enter', mods); - -describe('RadioGroup Pattern', () => { - function getRadioGroup(inputs: Partial & Pick) { - return new RadioGroupPattern({ - items: inputs.items, - value: inputs.value ?? signal([]), - activeItem: signal(undefined), - element: signal(document.createElement('div')), - readonly: inputs.readonly ?? signal(false), - disabled: inputs.disabled ?? signal(false), - skipDisabled: inputs.skipDisabled ?? signal(true), - focusMode: inputs.focusMode ?? signal('roving'), - textDirection: inputs.textDirection ?? signal('ltr'), - orientation: inputs.orientation ?? signal('vertical'), - getItem: e => inputs.items().find(i => i.element() === e.target), - }); - } - - function getRadios(radioGroup: TestRadioGroup, values: string[]): TestRadio[] { - return values.map((value, index) => { - const element = document.createElement('div'); - element.role = 'radio'; - return new RadioButtonPattern({ - value: signal(value), - id: signal(`radio-${index}`), - disabled: signal(false), - group: signal(radioGroup), - element: signal(element), - }); - }) as TestRadio[]; - } - - function getPatterns(values: string[], inputs: Partial = {}) { - const radioButtons = signal([]); - const radioGroup = getRadioGroup({...inputs, items: radioButtons}); - radioButtons.set(getRadios(radioGroup, values)); - radioGroup.inputs.activeItem.set(radioButtons()[0]); - return {radioGroup, radioButtons: radioButtons()}; - } - - function getDefaultPatterns(inputs: Partial = {}) { - return getPatterns(['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'], inputs); - } - - describe('Keyboard Navigation', () => { - it('should navigate next on ArrowDown', () => { - const {radioGroup, radioButtons} = getDefaultPatterns(); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - radioGroup.onKeydown(down()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - }); - - it('should navigate prev on ArrowUp', () => { - const {radioGroup, radioButtons} = getDefaultPatterns(); - radioGroup.inputs.activeItem.set(radioButtons[1]); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - radioGroup.onKeydown(up()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should navigate next on ArrowRight (horizontal)', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({orientation: signal('horizontal')}); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - radioGroup.onKeydown(right()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - }); - - it('should navigate prev on ArrowLeft (horizontal)', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({orientation: signal('horizontal')}); - radioGroup.inputs.activeItem.set(radioButtons[1]); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - radioGroup.onKeydown(left()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should navigate next on ArrowLeft (horizontal & rtl)', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({ - textDirection: signal('rtl'), - orientation: signal('horizontal'), - }); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - radioGroup.onKeydown(left()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - }); - - it('should navigate prev on ArrowRight (horizontal & rtl)', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({ - textDirection: signal('rtl'), - orientation: signal('horizontal'), - }); - radioGroup.inputs.activeItem.set(radioButtons[1]); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - radioGroup.onKeydown(right()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should navigate to the first radio on Home', () => { - const {radioGroup, radioButtons} = getDefaultPatterns(); - radioGroup.inputs.activeItem.set(radioButtons[4]); - - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[4]); - radioGroup.onKeydown(home()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should navigate to the last radio on End', () => { - const {radioGroup, radioButtons} = getDefaultPatterns(); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - radioGroup.onKeydown(end()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[4]); - }); - - it('should skip disabled radios when skipDisabled is true', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({skipDisabled: signal(true)}); - radioButtons[1].disabled.set(true); - radioGroup.onKeydown(down()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[2]); - radioGroup.onKeydown(up()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should not skip disabled radios when skipDisabled is false', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({skipDisabled: signal(false)}); - radioButtons[1].disabled.set(true); - radioGroup.onKeydown(down()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - radioGroup.onKeydown(up()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should be able to navigate in readonly mode', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({readonly: signal(true)}); - radioGroup.onKeydown(down()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - radioGroup.onKeydown(up()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - radioGroup.onKeydown(end()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[4]); - radioGroup.onKeydown(home()); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - }); - - describe('Keyboard Selection', () => { - let radioGroup: TestRadioGroup; - - beforeEach(() => { - radioGroup = getDefaultPatterns({value: signal([])}).radioGroup; - }); - - it('should select a radio on Space', () => { - radioGroup.onKeydown(space()); - expect(radioGroup.inputs.value()).toEqual(['Apple']); - }); - - it('should select a radio on Enter', () => { - radioGroup.onKeydown(enter()); - expect(radioGroup.inputs.value()).toEqual(['Apple']); - }); - - it('should select the focused radio on navigation (implicit selection)', () => { - radioGroup.onKeydown(down()); - expect(radioGroup.inputs.value()).toEqual(['Banana']); - radioGroup.onKeydown(up()); - expect(radioGroup.inputs.value()).toEqual(['Apple']); - radioGroup.onKeydown(end()); - expect(radioGroup.inputs.value()).toEqual(['Elderberry']); - radioGroup.onKeydown(home()); - expect(radioGroup.inputs.value()).toEqual(['Apple']); - }); - - it('should not be able to change selection when in readonly mode', () => { - const readonly = radioGroup.inputs.readonly as WritableSignal; - readonly.set(true); - radioGroup.onKeydown(space()); - expect(radioGroup.inputs.value()).toEqual([]); - - radioGroup.onKeydown(down()); // Navigation still works - expect(radioGroup.inputs.activeItem()).toBe(radioGroup.inputs.items()[1]); - expect(radioGroup.inputs.value()).toEqual([]); // Selection doesn't change - - radioGroup.onKeydown(enter()); - expect(radioGroup.inputs.value()).toEqual([]); - }); - - it('should not select a disabled radio via keyboard', () => { - const {radioGroup, radioButtons} = getPatterns(['A', 'B', 'C'], { - skipDisabled: signal(false), - }); - radioButtons[1].disabled.set(true); - - radioGroup.onKeydown(down()); // Focus B (disabled) - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - expect(radioGroup.inputs.value()).toEqual([]); // Should not select B - - radioGroup.onKeydown(space()); // Try selecting B with space - expect(radioGroup.inputs.value()).toEqual([]); - - radioGroup.onKeydown(enter()); // Try selecting B with enter - expect(radioGroup.inputs.value()).toEqual([]); - - radioGroup.onKeydown(down()); // Focus C - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[2]); - expect(radioGroup.inputs.value()).toEqual(['C']); // Selects C on navigation - }); - }); - - describe('Pointer Events', () => { - function click(radios: TestRadio[], index: number) { - return { - target: radios[index].element(), - } as unknown as PointerEvent; - } - - it('should select a radio on click', () => { - const {radioGroup, radioButtons} = getDefaultPatterns(); - radioGroup.onPointerdown(click(radioButtons, 1)); - expect(radioGroup.inputs.value()).toEqual(['Banana']); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - }); - - it('should not select a disabled radio on click', () => { - const {radioGroup, radioButtons} = getDefaultPatterns(); - radioButtons[1].disabled.set(true); - radioGroup.onPointerdown(click(radioButtons, 1)); - expect(radioGroup.inputs.value()).toEqual([]); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); // Active index shouldn't change - }); - - it('should only update active index when readonly', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({readonly: signal(true)}); - radioGroup.onPointerdown(click(radioButtons, 1)); - expect(radioGroup.inputs.value()).toEqual([]); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); // Active index should update - }); - }); - - describe('#setDefaultState', () => { - it('should set the active index to the first radio', () => { - const {radioGroup, radioButtons} = getDefaultPatterns(); - radioGroup.setDefaultState(); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should set the active index to the first focusable radio', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({skipDisabled: signal(true)}); - radioButtons[0].disabled.set(true); - radioGroup.setDefaultState(); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - }); - - it('should set the active index to the selected radio', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({value: signal(['Cherry'])}); - radioGroup.setDefaultState(); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[2]); - }); - - it('should set the active index to the first focusable radio if selected is disabled', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({ - value: signal(['Cherry']), - skipDisabled: signal(true), - }); - radioButtons[2].disabled.set(true); // Disable Cherry - radioGroup.setDefaultState(); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); // Defaults to first focusable - }); - }); - - describe('validate', () => { - it('should report a violation if the selected item is disabled and skipDisabled is true', () => { - const {radioGroup, radioButtons} = getDefaultPatterns({ - value: signal(['Banana']), - skipDisabled: signal(true), - }); - radioButtons[1].disabled.set(true); // Disable the selected item. - const violations = radioGroup.validate(); - expect(violations.length).toBe(1); - }); - }); -}); diff --git a/src/aria/ui-patterns/radio-group/toolbar-radio-group.spec.ts b/src/aria/ui-patterns/radio-group/toolbar-radio-group.spec.ts deleted file mode 100644 index 6b009f8aae7c..000000000000 --- a/src/aria/ui-patterns/radio-group/toolbar-radio-group.spec.ts +++ /dev/null @@ -1,212 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {signal, WritableSignal} from '@angular/core'; -import {ToolbarRadioGroupInputs, ToolbarRadioGroupPattern} from './toolbar-radio-group'; -import {RadioButtonPattern} from './radio-button'; -import {ToolbarPattern} from './../toolbar/toolbar'; -import {createKeyboardEvent} from '@angular/cdk/testing/private'; -import {ModifierKeys} from '@angular/cdk/testing'; - -type TestInputs = ToolbarRadioGroupInputs; -type TestRadio = RadioButtonPattern & { - disabled: WritableSignal; -}; -type TestRadioGroup = ToolbarRadioGroupPattern; - -const down = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 40, 'ArrowDown', mods); -const space = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 32, ' ', mods); -const enter = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 13, 'Enter', mods); - -describe('ToolbarRadioGroup Pattern', () => { - function getToolbarRadioGroup(inputs: Partial & Pick) { - return new ToolbarRadioGroupPattern({ - items: inputs.items, - value: inputs.value ?? signal([]), - activeItem: signal(undefined), - element: signal(document.createElement('div')), - readonly: inputs.readonly ?? signal(false), - disabled: inputs.disabled ?? signal(false), - skipDisabled: inputs.skipDisabled ?? signal(true), - focusMode: inputs.focusMode ?? signal('roving'), - textDirection: inputs.textDirection ?? signal('ltr'), - orientation: inputs.orientation ?? signal('vertical'), - toolbar: inputs.toolbar ?? signal(undefined), - getItem: e => inputs.items().find(i => i.element() === e.target), - }); - } - - function getRadios(radioGroup: TestRadioGroup, values: string[]): TestRadio[] { - return values.map((value, index) => { - const element = document.createElement('div'); - element.role = 'radio'; - return new RadioButtonPattern({ - value: signal(value), - id: signal(`radio-${index}`), - disabled: signal(false), - group: signal(radioGroup), - element: signal(element), - }); - }) as TestRadio[]; - } - - function getPatterns(values: string[], inputs: Partial = {}) { - const radioButtons = signal([]); - const radioGroup = getToolbarRadioGroup({...inputs, items: radioButtons}); - radioButtons.set(getRadios(radioGroup, values)); - radioGroup.inputs.activeItem.set(radioButtons()[0]); - return {radioGroup, radioButtons: radioButtons()}; - } - - function getDefaultPatterns(inputs: Partial = {}) { - return getPatterns(['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'], inputs); - } - - let radioGroup: TestRadioGroup; - let radioButtons: TestRadio[]; - let toolbar: ToolbarPattern; - - beforeEach(() => { - toolbar = new ToolbarPattern({ - items: signal([]), - activeItem: signal(undefined), - element: signal(document.createElement('div')), - orientation: signal('horizontal'), - textDirection: signal('ltr'), - disabled: signal(false), - skipDisabled: signal(true), - wrap: signal(false), - getItem: (e: Element) => undefined, - }); - const patterns = getDefaultPatterns({ - toolbar: signal(toolbar), - }); - radioButtons = patterns.radioButtons; - radioGroup = patterns.radioGroup; - }); - - it('should ignore keyboard navigation when within a toolbar', () => { - radioGroup.inputs.activeItem.set(radioButtons[0]); - const initialActive = radioGroup.inputs.activeItem(); - radioGroup.onKeydown(down()); - expect(radioGroup.inputs.activeItem()).toBe(initialActive); - }); - - it('should ignore keyboard selection when within a toolbar', () => { - expect(radioGroup.inputs.value()).toEqual([]); - radioGroup.onKeydown(space()); - expect(radioGroup.inputs.value()).toEqual([]); - radioGroup.onKeydown(enter()); - expect(radioGroup.inputs.value()).toEqual([]); - }); - - it('should ignore pointer events when within a toolbar', () => { - radioGroup.inputs.activeItem.set(radioButtons[0]); - const initialActive = radioGroup.inputs.activeItem(); - expect(radioGroup.inputs.value()).toEqual([]); - - const clickEvent = { - target: radioButtons[1].element(), - } as unknown as PointerEvent; - radioGroup.onPointerdown(clickEvent); - - expect(radioGroup.inputs.activeItem()).toBe(initialActive); - expect(radioGroup.inputs.value()).toEqual([]); - }); - - describe('Toolbar Widget Group controls', () => { - beforeEach(() => { - radioGroup.inputs.activeItem.set(radioButtons[0]); - }); - - it('should correctly report when on the first item', () => { - radioGroup.inputs.activeItem.set(radioButtons[0]); - expect(radioGroup.isOnFirstItem()).toBe(true); - radioGroup.inputs.activeItem.set(radioButtons[1]); - expect(radioGroup.isOnFirstItem()).toBe(false); - }); - - it('should correctly report when on the last item', () => { - radioGroup.inputs.activeItem.set(radioButtons[4]); - expect(radioGroup.isOnLastItem()).toBe(true); - radioGroup.inputs.activeItem.set(radioButtons[3]); - expect(radioGroup.isOnLastItem()).toBe(false); - }); - - it('should handle "next" control', () => { - radioGroup.next(false); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[1]); - }); - - it('should handle "prev" control', () => { - radioGroup.inputs.activeItem.set(radioButtons[1]); - radioGroup.prev(false); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should handle "first" control', () => { - radioGroup.first(); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should handle "last" control', () => { - radioGroup.last(); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[4]); - }); - - it('should handle "unfocus" control by clearing active item', () => { - radioGroup.unfocus(); - expect(radioGroup.inputs.activeItem()).toBe(undefined); - }); - - it('should handle "trigger" control to select an item', () => { - expect(radioGroup.inputs.value()).toEqual([]); - radioGroup.trigger(); - expect(radioGroup.inputs.value()).toEqual(['Apple']); - }); - - it('should not "trigger" selection when readonly', () => { - (radioGroup.inputs.readonly as WritableSignal).set(true); - expect(radioGroup.inputs.value()).toEqual([]); - radioGroup.trigger(); - expect(radioGroup.inputs.value()).toEqual([]); - }); - - it('should handle "goto" control', () => { - const event = {target: radioButtons[2].element()} as unknown as PointerEvent; - radioGroup.goto(event); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[2]); - expect(radioGroup.inputs.value()).toEqual(['Cherry']); - }); - - it('should handle "goto" control in readonly mode (no selection)', () => { - (radioGroup.inputs.readonly as WritableSignal).set(true); - const event = {target: radioButtons[2].element()} as unknown as PointerEvent; - radioGroup.goto(event); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[2]); - expect(radioGroup.inputs.value()).toEqual([]); - }); - - it('should handle "setDefaultState" control', () => { - radioGroup.inputs.activeItem.set(undefined); - radioGroup.setDefaultState(); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should wrap on "next" with wrap', () => { - radioGroup.inputs.activeItem.set(radioButtons[4]); - radioGroup.next(true); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[0]); - }); - - it('should wrap on "prev" with wrap', () => { - radioGroup.prev(true); - expect(radioGroup.inputs.activeItem()).toBe(radioButtons[4]); - }); - }); -}); diff --git a/src/aria/ui-patterns/radio-group/toolbar-radio-group.ts b/src/aria/ui-patterns/radio-group/toolbar-radio-group.ts deleted file mode 100644 index 80b7d0de16c8..000000000000 --- a/src/aria/ui-patterns/radio-group/toolbar-radio-group.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {SignalLike} from '../behaviors/signal-like/signal-like'; -import {RadioGroupInputs, RadioGroupPattern} from './radio-group'; -import type {ToolbarPattern} from '../toolbar/toolbar'; -import type {ToolbarWidgetGroupControls} from '../toolbar/toolbar-widget-group'; - -/** Represents the required inputs for a toolbar controlled radio group. */ -export type ToolbarRadioGroupInputs = RadioGroupInputs & { - /** The toolbar controlling the radio group. */ - toolbar: SignalLike | undefined>; -}; - -/** Controls the state of a radio group in a toolbar. */ -export class ToolbarRadioGroupPattern - extends RadioGroupPattern - implements ToolbarWidgetGroupControls -{ - constructor(override readonly inputs: ToolbarRadioGroupInputs) { - if (!!inputs.toolbar()) { - inputs.orientation = inputs.toolbar()!.orientation; - inputs.skipDisabled = inputs.toolbar()!.skipDisabled; - } - - super(inputs); - } - - /** Noop. The toolbar handles keydown events. */ - override onKeydown(_: KeyboardEvent): void {} - - /** Noop. The toolbar handles pointerdown events. */ - override onPointerdown(_: PointerEvent): void {} - - /** Whether the radio group is currently on the first item. */ - isOnFirstItem() { - return this.listBehavior.navigationBehavior.peekPrev() === undefined; - } - - /** Whether the radio group is currently on the last item. */ - isOnLastItem() { - return this.listBehavior.navigationBehavior.peekNext() === undefined; - } - - /** Navigates to the next radio button in the group. */ - next(wrap: boolean) { - this.wrap.set(wrap); - this.listBehavior.next(); - this.wrap.set(false); - } - - /** Navigates to the previous radio button in the group. */ - prev(wrap: boolean) { - this.wrap.set(wrap); - this.listBehavior.prev(); - this.wrap.set(false); - } - - /** Navigates to the first radio button in the group. */ - first() { - this.listBehavior.first(); - } - - /** Navigates to the last radio button in the group. */ - last() { - this.listBehavior.last(); - } - - /** Removes focus from the radio group. */ - unfocus() { - this.inputs.activeItem.set(undefined); - } - - /** Triggers the action of the currently active radio button in the group. */ - trigger() { - if (this.readonly()) return; - this.listBehavior.selectOne(); - } - - /** Navigates to the radio button targeted by a pointer event. */ - goto(e: PointerEvent) { - this.listBehavior.goto(this.inputs.getItem(e)!, { - selectOne: !this.readonly(), - }); - } -} diff --git a/src/aria/ui-patterns/tabs/tabs.spec.ts b/src/aria/ui-patterns/tabs/tabs.spec.ts deleted file mode 100644 index 6e7d381480a7..000000000000 --- a/src/aria/ui-patterns/tabs/tabs.spec.ts +++ /dev/null @@ -1,361 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {signal} from '@angular/core'; -import { - TabInputs, - TabPattern, - TabListInputs, - TabListPattern, - TabPanelInputs, - TabPanelPattern, -} from './tabs'; -import {SignalLike, WritableSignalLike} from '../behaviors/signal-like/signal-like'; -import {createKeyboardEvent} from '@angular/cdk/testing/private'; -import {ModifierKeys} from '@angular/cdk/testing'; - -// Converts the SignalLike type to WritableSignalLike type for controlling test inputs. -type WritableSignalOverrides = { - [K in keyof O as O[K] extends SignalLike ? K : never]: O[K] extends SignalLike - ? WritableSignalLike - : never; -}; - -type TestTabListInputs = TabListInputs & WritableSignalOverrides; -type TestTabInputs = TabInputs & WritableSignalOverrides; -type TestTabPanelInputs = TabPanelInputs & WritableSignalOverrides; - -const up = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 38, 'ArrowUp', mods); -const down = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 40, 'ArrowDown', mods); -const left = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 37, 'ArrowLeft', mods); -const right = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 39, 'ArrowRight', mods); -const home = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 36, 'Home', mods); -const end = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 35, 'End', mods); -const space = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 32, ' ', mods); -const enter = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 13, 'Enter', mods); - -function createTabElement(): HTMLElement { - const element = document.createElement('div'); - element.role = 'tab'; - return element; -} - -describe('Tabs Pattern', () => { - let tabListInputs: TestTabListInputs; - let tabListPattern: TabListPattern; - let tabInputs: TestTabInputs[]; - let tabPatterns: TabPattern[]; - let tabPanelInputs: TestTabPanelInputs[]; - let tabPanelPatterns: TabPanelPattern[]; - - beforeEach(() => { - // Initiate TabListPattern. - tabListInputs = { - orientation: signal('horizontal'), - wrap: signal(true), - textDirection: signal('ltr'), - selectionMode: signal('follow'), - focusMode: signal('roving'), - disabled: signal(false), - activeItem: signal(undefined), - skipDisabled: signal(true), - items: signal([]), - value: signal(['tab-1']), - element: signal(document.createElement('div')), - }; - tabListPattern = new TabListPattern(tabListInputs); - - // Initiate a list of TabPatterns. - tabInputs = [ - { - tablist: signal(tabListPattern), - tabpanel: signal(undefined), - id: signal('tab-1-id'), - element: signal(createTabElement()), - disabled: signal(false), - value: signal('tab-1'), - }, - { - tablist: signal(tabListPattern), - tabpanel: signal(undefined), - id: signal('tab-2-id'), - element: signal(createTabElement()), - disabled: signal(false), - value: signal('tab-2'), - }, - { - tablist: signal(tabListPattern), - tabpanel: signal(undefined), - id: signal('tab-3-id'), - element: signal(createTabElement()), - disabled: signal(false), - value: signal('tab-3'), - }, - ]; - tabPatterns = [ - new TabPattern(tabInputs[0]), - new TabPattern(tabInputs[1]), - new TabPattern(tabInputs[2]), - ]; - - // Initiate a list of TabPanelPatterns. - tabPanelInputs = [ - { - id: signal('tabpanel-1-id'), - tab: signal(undefined), - value: signal('tab-1'), - }, - { - id: signal('tabpanel-2-id'), - tab: signal(undefined), - value: signal('tab-2'), - }, - { - id: signal('tabpanel-3-id'), - tab: signal(undefined), - value: signal('tab-3'), - }, - ]; - tabPanelPatterns = [ - new TabPanelPattern(tabPanelInputs[0]), - new TabPanelPattern(tabPanelInputs[1]), - new TabPanelPattern(tabPanelInputs[2]), - ]; - - // Binding between tabs and tabpanels. - tabInputs[0].tabpanel.set(tabPanelPatterns[0]); - tabInputs[1].tabpanel.set(tabPanelPatterns[1]); - tabInputs[2].tabpanel.set(tabPanelPatterns[2]); - tabPanelInputs[0].tab.set(tabPatterns[0]); - tabPanelInputs[1].tab.set(tabPatterns[1]); - tabPanelInputs[2].tab.set(tabPatterns[2]); - tabListInputs.items.set(tabPatterns); - tabListInputs.activeItem.set(tabPatterns[0]); - }); - - it('sets the selected tab by setting `value`.', () => { - expect(tabPatterns[0].selected()).toBeTrue(); - expect(tabPatterns[1].selected()).toBeFalse(); - tabListInputs.value.set(['tab-2']); - expect(tabPatterns[0].selected()).toBeFalse(); - expect(tabPatterns[1].selected()).toBeTrue(); - }); - - it('sets a tabpanel to be not hidden if a tab is selected.', () => { - tabListInputs.value.set(['tab-1']); - expect(tabPatterns[0].selected()).toBeTrue(); - expect(tabPanelPatterns[0].hidden()).toBeFalse(); - }); - - it('sets a tabpanel to be hidden if a tab is not selected.', () => { - tabListInputs.value.set(['tab-1']); - expect(tabPatterns[1].selected()).toBeFalse(); - expect(tabPanelPatterns[1].hidden()).toBeTrue(); - }); - - it('should set a tabpanel tabindex to 0 if the tab is selected.', () => { - tabListInputs.value.set(['tab-1']); - expect(tabPatterns[0].tabindex()).toBe(0); - }); - - it('should set a tabpanel tabindex to -1 if the tab is not selected.', () => { - tabListInputs.value.set(['tab-1']); - expect(tabPatterns[1].tabindex()).toBe(-1); - expect(tabPatterns[2].tabindex()).toBe(-1); - }); - - it('should set a tabpanel aria-labelledby pointing to its tab id.', () => { - expect(tabPanelPatterns[0].labelledBy()).toBe('tab-1-id'); - expect(tabPanelPatterns[1].labelledBy()).toBe('tab-2-id'); - expect(tabPanelPatterns[2].labelledBy()).toBe('tab-3-id'); - }); - - it('gets a controlled tabpanel id from a tab.', () => { - expect(tabPanelPatterns[0].id()).toBe('tabpanel-1-id'); - expect(tabPatterns[0].controls()).toBe('tabpanel-1-id'); - expect(tabPanelPatterns[1].id()).toBe('tabpanel-2-id'); - expect(tabPatterns[1].controls()).toBe('tabpanel-2-id'); - expect(tabPanelPatterns[2].id()).toBe('tabpanel-3-id'); - expect(tabPatterns[2].controls()).toBe('tabpanel-3-id'); - }); - - describe('#setDefaultState', () => { - it('should not set activeIndex if there are no tabs', () => { - tabListInputs.items.set([]); - tabListInputs.activeItem.set(tabPatterns[10]); - tabListPattern.setDefaultState(); - expect(tabListInputs.activeItem()).toBe(tabPatterns[10]); - }); - - it('should not set activeIndex if no tabs are focusable', () => { - tabInputs.forEach(input => input.disabled.set(true)); - tabListInputs.activeItem.set(tabPatterns[10]); - tabListPattern.setDefaultState(); - expect(tabListInputs.activeItem()).toBe(tabPatterns[10]); - }); - - it('should set activeIndex to the first focusable tab if no tabs are selected', () => { - tabListInputs.activeItem.set(tabPatterns[2]); - tabListInputs.value.set([]); - tabInputs[0].disabled.set(true); - tabListPattern.setDefaultState(); - expect(tabListInputs.activeItem()).toBe(tabPatterns[1]); - }); - - it('should set activeIndex to the first focusable and selected tab', () => { - tabListInputs.activeItem.set(tabPatterns[0]); - tabListInputs.value.set([tabPatterns[2].value()]); - tabListPattern.setDefaultState(); - expect(tabListInputs.activeItem()).toBe(tabPatterns[2]); - }); - - it('should set activeIndex to the first focusable tab when the selected tab is not focusable', () => { - tabListInputs.value.set([tabPatterns[1].value()]); - tabInputs[1].disabled.set(true); - tabListPattern.setDefaultState(); - expect(tabListInputs.activeItem()).toBe(tabPatterns[0]); - }); - }); - - describe('Keyboard Navigation', () => { - it('does not handle keyboard event if a tablist is disabled.', () => { - expect(tabPatterns[1].active()).toBeFalse(); - tabListInputs.disabled.set(true); - tabListPattern.onKeydown(right()); - expect(tabPatterns[1].active()).toBeFalse(); - }); - - it('skips the disabled tab when `skipDisabled` is set to true.', () => { - tabInputs[1].disabled.set(true); - tabListPattern.onKeydown(right()); - expect(tabPatterns[0].active()).toBeFalse(); - expect(tabPatterns[1].active()).toBeFalse(); - expect(tabPatterns[2].active()).toBeTrue(); - }); - - it('does not skip the disabled tab when `skipDisabled` is set to false.', () => { - tabListInputs.skipDisabled.set(false); - tabInputs[1].disabled.set(true); - tabListPattern.onKeydown(right()); - expect(tabPatterns[0].active()).toBeFalse(); - expect(tabPatterns[1].active()).toBeTrue(); - expect(tabPatterns[2].active()).toBeFalse(); - }); - - it('selects a tab by focus if `selectionMode` is "follow".', () => { - expect(tabPatterns[0].selected()).toBeTrue(); - expect(tabPatterns[1].selected()).toBeFalse(); - tabListPattern.onKeydown(right()); - expect(tabPatterns[0].selected()).toBeFalse(); - expect(tabPatterns[1].selected()).toBeTrue(); - }); - - it('selects a tab by enter key if `selectionMode` is "explicit".', () => { - tabListInputs.selectionMode.set('explicit'); - expect(tabPatterns[0].selected()).toBeTrue(); - expect(tabPatterns[1].selected()).toBeFalse(); - tabListPattern.onKeydown(right()); - expect(tabPatterns[0].selected()).toBeTrue(); - expect(tabPatterns[1].selected()).toBeFalse(); - tabListPattern.onKeydown(enter()); - expect(tabPatterns[0].selected()).toBeFalse(); - expect(tabPatterns[1].selected()).toBeTrue(); - }); - - it('selects a tab by space key if `selectionMode` is "explicit".', () => { - tabListInputs.selectionMode.set('explicit'); - expect(tabPatterns[0].selected()).toBeTrue(); - expect(tabPatterns[1].selected()).toBeFalse(); - tabListPattern.onKeydown(right()); - expect(tabPatterns[0].selected()).toBeTrue(); - expect(tabPatterns[1].selected()).toBeFalse(); - tabListPattern.onKeydown(space()); - expect(tabPatterns[0].selected()).toBeFalse(); - expect(tabPatterns[1].selected()).toBeTrue(); - }); - - it('uses left key to navigate to the previous tab when `orientation` is set to "horizontal".', () => { - tabListInputs.activeItem.set(tabPatterns[1]); - expect(tabPatterns[1].active()).toBeTrue(); - tabListPattern.onKeydown(left()); - expect(tabPatterns[0].active()).toBeTrue(); - }); - - it('uses right key to navigate to the next tab when `orientation` is set to "horizontal".', () => { - tabListInputs.activeItem.set(tabPatterns[1]); - expect(tabPatterns[1].active()).toBeTrue(); - tabListPattern.onKeydown(right()); - expect(tabPatterns[2].active()).toBeTrue(); - }); - - it('uses up key to navigate to the previous tab when `orientation` is set to "vertical".', () => { - tabListInputs.orientation.set('vertical'); - tabListInputs.activeItem.set(tabPatterns[1]); - expect(tabPatterns[1].active()).toBeTrue(); - tabListPattern.onKeydown(up()); - expect(tabPatterns[0].active()).toBeTrue(); - }); - - it('uses down key to navigate to the next tab when `orientation` is set to "vertical".', () => { - tabListInputs.orientation.set('vertical'); - tabListInputs.activeItem.set(tabPatterns[1]); - expect(tabPatterns[1].active()).toBeTrue(); - tabListPattern.onKeydown(down()); - expect(tabPatterns[2].active()).toBeTrue(); - }); - - it('uses home key to navigate to the first tab.', () => { - tabListInputs.activeItem.set(tabPatterns[1]); - expect(tabPatterns[1].active()).toBeTrue(); - tabListPattern.onKeydown(home()); - expect(tabPatterns[0].active()).toBeTrue(); - }); - - it('uses end key to navigate to the last tab.', () => { - tabListInputs.activeItem.set(tabPatterns[1]); - expect(tabPatterns[1].active()).toBeTrue(); - tabListPattern.onKeydown(end()); - expect(tabPatterns[2].active()).toBeTrue(); - }); - - it('moves to the last tab from first tab when navigating to the previous tab if `wrap` is set to true', () => { - expect(tabPatterns[0].active()).toBeTrue(); - tabListPattern.onKeydown(left()); - expect(tabPatterns[2].active()).toBeTrue(); - }); - - it('moves to the first tab from last tab when navigating to the next tab if `wrap` is set to true', () => { - tabListPattern.onKeydown(end()); - expect(tabPatterns[2].active()).toBeTrue(); - tabListPattern.onKeydown(right()); - expect(tabPatterns[0].active()).toBeTrue(); - }); - - it('stays on the first tab when navigating to the previous tab if `wrap` is set to false', () => { - tabListInputs.wrap.set(false); - expect(tabPatterns[0].active()).toBeTrue(); - tabListPattern.onKeydown(left()); - expect(tabPatterns[0].active()).toBeTrue(); - }); - - it('stays on the last tab when navigating to the next tab if `wrap` is set to false', () => { - tabListInputs.wrap.set(false); - tabListPattern.onKeydown(end()); - expect(tabPatterns[2].active()).toBeTrue(); - tabListPattern.onKeydown(right()); - expect(tabPatterns[2].active()).toBeTrue(); - }); - - it('changes the navigation direction with `rtl` mode.', () => { - tabListInputs.textDirection.set('rtl'); - tabListInputs.activeItem.set(tabPatterns[1]); - tabListPattern.onKeydown(left()); - expect(tabPatterns[2].active()).toBeTrue(); - }); - }); -}); diff --git a/src/aria/ui-patterns/toolbar/toolbar-widget-group.ts b/src/aria/ui-patterns/toolbar/toolbar-widget-group.ts deleted file mode 100644 index 297dafa1a0a7..000000000000 --- a/src/aria/ui-patterns/toolbar/toolbar-widget-group.ts +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {computed} from '@angular/core'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; -import {ListItem} from '../behaviors/list/list'; -import type {ToolbarPattern} from './toolbar'; - -/** An interface that allows sub patterns to expose the necessary controls for the toolbar. */ -export interface ToolbarWidgetGroupControls { - /** Whether the widget group is currently on the first item. */ - isOnFirstItem(): boolean; - - /** Whether the widget group is currently on the last item. */ - isOnLastItem(): boolean; - - /** Navigates to the next widget in the group. */ - next(wrap: boolean): void; - - /** Navigates to the previous widget in the group. */ - prev(wrap: boolean): void; - - /** Navigates to the first widget in the group. */ - first(): void; - - /** Navigates to the last widget in the group. */ - last(): void; - - /** Removes focus from the widget group. */ - unfocus(): void; - - /** Triggers the action of the currently active widget in the group. */ - trigger(): void; - - /** Navigates to the widget targeted by a pointer event. */ - goto(event: PointerEvent): void; - - /** Sets the widget group to its default initial state. */ - setDefaultState(): void; -} - -/** Represents the required inputs for a toolbar widget group. */ -export interface ToolbarWidgetGroupInputs - extends Omit, 'searchTerm' | 'value' | 'index' | 'selectable'> { - /** A reference to the parent toolbar. */ - toolbar: SignalLike | undefined>; - - /** The controls for the sub patterns associated with the toolbar. */ - controls: SignalLike; -} - -/** A group of widgets within a toolbar that provides nested navigation. */ -export class ToolbarWidgetGroupPattern implements ListItem { - /** A unique identifier for the widget. */ - readonly id: SignalLike; - - /** The html element that should receive focus. */ - readonly element: SignalLike; - - /** Whether the widget is disabled. */ - readonly disabled: SignalLike; - - /** A reference to the parent toolbar. */ - readonly toolbar: SignalLike | undefined>; - - /** The text used by the typeahead search. */ - readonly searchTerm = () => ''; // Unused because toolbar does not support typeahead. - - /** The value associated with the widget. */ - readonly value = () => '' as V; // Unused because toolbar does not support selection. - - /** Whether the widget is selectable. */ - readonly selectable = () => true; // Unused because toolbar does not support selection. - - /** The position of the widget within the toolbar. */ - readonly index = computed(() => this.toolbar()?.inputs.items().indexOf(this) ?? -1); - - /** The actions that can be performed on the widget group. */ - readonly controls: SignalLike = computed( - () => this.inputs.controls() ?? this._defaultControls, - ); - - /** Default toolbar widget group controls when no controls provided. */ - private readonly _defaultControls: ToolbarWidgetGroupControls = { - isOnFirstItem: () => true, - isOnLastItem: () => true, - next: () => {}, - prev: () => {}, - first: () => {}, - last: () => {}, - unfocus: () => {}, - trigger: () => {}, - goto: () => {}, - setDefaultState: () => {}, - }; - - constructor(readonly inputs: ToolbarWidgetGroupInputs) { - this.id = inputs.id; - this.element = inputs.element; - this.disabled = inputs.disabled; - this.toolbar = inputs.toolbar; - } -} diff --git a/src/aria/ui-patterns/toolbar/toolbar.spec.ts b/src/aria/ui-patterns/toolbar/toolbar.spec.ts deleted file mode 100644 index 2f1cfa673f27..000000000000 --- a/src/aria/ui-patterns/toolbar/toolbar.spec.ts +++ /dev/null @@ -1,466 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {signal, WritableSignal} from '@angular/core'; -import {ToolbarInputs, ToolbarPattern} from './toolbar'; -import {ToolbarWidgetInputs, ToolbarWidgetPattern} from './toolbar-widget'; -import { - ToolbarWidgetGroupControls, - ToolbarWidgetGroupInputs, - ToolbarWidgetGroupPattern, -} from './toolbar-widget-group'; -import {createKeyboardEvent} from '@angular/cdk/testing/private'; -import {ModifierKeys} from '@angular/cdk/testing'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; - -// Converts the SignalLike type to WritableSignal type for controlling test inputs. -type WritableSignalOverrides = { - [K in keyof O as O[K] extends SignalLike ? K : never]: O[K] extends SignalLike - ? WritableSignal - : never; -}; - -type TestToolbarInputs = Omit< - ToolbarInputs & WritableSignalOverrides>, - 'items' | 'element' | 'getItem' ->; -type TestToolbarWidgetInputs = Omit< - ToolbarWidgetInputs & WritableSignalOverrides>, - 'element' | 'id' | 'toolbar' ->; -type TestToolbarWidgetGroupInputs = Omit< - ToolbarWidgetGroupInputs & WritableSignalOverrides>, - 'element' | 'id' | 'toolbar' ->; - -const up = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 38, 'ArrowUp', mods); -const down = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 40, 'ArrowDown', mods); -const left = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 37, 'ArrowLeft', mods); -const right = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 39, 'ArrowRight', mods); -const home = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 36, 'Home', mods); -const end = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 35, 'End', mods); -const space = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 32, ' ', mods); -const enter = (mods?: ModifierKeys) => createKeyboardEvent('keydown', 13, 'Enter', mods); -const click = (target: Element) => - ({target, stopPropagation: () => {}, preventDefault: () => {}}) as unknown as PointerEvent; - -describe('Toolbar Pattern', () => { - function createToolbar( - widgets: (TestToolbarWidgetInputs | TestToolbarWidgetGroupInputs)[], - toolbarInputs: TestToolbarInputs, - ) { - const items = signal<(ToolbarWidgetPattern | ToolbarWidgetGroupPattern)[]>([]); - const toolbar = new ToolbarPattern({ - ...toolbarInputs, - items, - element: signal(document.createElement('div')), - getItem: target => items().find(widget => widget.element() === target), - }); - - const widgetPatterns = widgets.map((widgetInputs, index) => { - const id = `widget-${index}`; - const element = document.createElement('div'); - element.id = id; - - if ('controls' in widgetInputs) { - // It's a group - element.classList.add('toolbar-widget-group'); - return new ToolbarWidgetGroupPattern({ - ...widgetInputs, - id: signal(id), - element: signal(element), - toolbar: signal(toolbar), - }); - } else { - // It's a widget - element.classList.add('toolbar-widget'); - return new ToolbarWidgetPattern({ - ...widgetInputs, - id: signal(id), - element: signal(element), - toolbar: signal(toolbar), - }); - } - }); - items.set(widgetPatterns); - return {toolbar, items: widgetPatterns}; - } - - describe('Keyboard Navigation', () => { - let toolbar: ToolbarPattern; - let toolbarInputs: TestToolbarInputs; - let widgetInputs: (TestToolbarWidgetInputs | TestToolbarWidgetGroupInputs)[]; - let items: (ToolbarWidgetPattern | ToolbarWidgetGroupPattern)[]; - - beforeEach(() => { - toolbarInputs = { - activeItem: signal(undefined), - orientation: signal('horizontal'), - textDirection: signal('ltr'), - disabled: signal(false), - skipDisabled: signal(true), - wrap: signal(false), - }; - widgetInputs = [ - {disabled: signal(false)}, - {disabled: signal(false)}, - { - disabled: signal(false), - controls: signal(undefined), - }, - {disabled: signal(false)}, - ]; - const {toolbar: newToolbar, items: newItems} = createToolbar( - widgetInputs, - toolbarInputs, - ); - toolbar = newToolbar; - items = newItems; - toolbarInputs.activeItem.set(items[0]); - }); - - it('should navigate next on ArrowRight (horizontal)', () => { - toolbar.onKeydown(right()); - expect(toolbarInputs.activeItem()).toBe(items[1]); - }); - - it('should navigate prev on ArrowLeft (horizontal)', () => { - toolbarInputs.activeItem.set(items[1]); - toolbar.onKeydown(left()); - expect(toolbarInputs.activeItem()).toBe(items[0]); - }); - - it('should navigate next on ArrowDown (vertical)', () => { - toolbarInputs.orientation.set('vertical'); - toolbar.onKeydown(down()); - expect(toolbarInputs.activeItem()).toBe(items[1]); - }); - - it('should navigate prev on ArrowUp (vertical)', () => { - toolbarInputs.orientation.set('vertical'); - toolbarInputs.activeItem.set(items[1]); - toolbar.onKeydown(up()); - expect(toolbarInputs.activeItem()).toBe(items[0]); - }); - - it('should navigate next on ArrowLeft (rtl)', () => { - toolbarInputs.textDirection.set('rtl'); - toolbar.onKeydown(left()); - expect(toolbarInputs.activeItem()).toBe(items[1]); - }); - - it('should navigate prev on ArrowRight (rtl)', () => { - toolbarInputs.textDirection.set('rtl'); - toolbarInputs.activeItem.set(items[1]); - toolbar.onKeydown(right()); - expect(toolbarInputs.activeItem()).toBe(items[0]); - }); - - it('should navigate to the first item on Home', () => { - toolbarInputs.activeItem.set(items[3]); - toolbar.onKeydown(home()); - expect(toolbarInputs.activeItem()).toBe(items[0]); - }); - - it('should navigate to the last item on End', () => { - toolbar.onKeydown(end()); - expect(toolbarInputs.activeItem()).toBe(items[3]); - }); - - it('should skip a disabled toolbar widget when skipDisabled is true', () => { - widgetInputs[1].disabled.set(true); - toolbar.onKeydown(right()); - expect(toolbarInputs.activeItem()).toBe(items[2]); - }); - - it('should not skip disabled items when skipDisabled is false', () => { - toolbarInputs.skipDisabled.set(false); - widgetInputs[1].disabled.set(true); - toolbar.onKeydown(right()); - expect(toolbarInputs.activeItem()).toBe(items[1]); - }); - - it('should wrap back to the first item when wrap is true', () => { - toolbarInputs.wrap.set(true); - toolbarInputs.activeItem.set(items[3]); - toolbar.onKeydown(right()); - expect(toolbarInputs.activeItem()).toBe(items[0]); - }); - - it('should not wrap when wrap is false', () => { - toolbarInputs.activeItem.set(items[3]); - toolbar.onKeydown(right()); - expect(toolbarInputs.activeItem()).toBe(items[3]); - }); - - it('should not navigate when the toolbar is disabled', () => { - toolbarInputs.disabled.set(true); - toolbar.onKeydown(right()); - expect(toolbarInputs.activeItem()).toBe(items[0]); - }); - }); - - describe('Pointer Events', () => { - let toolbar: ToolbarPattern; - let toolbarInputs: TestToolbarInputs; - let items: (ToolbarWidgetPattern | ToolbarWidgetGroupPattern)[]; - - beforeEach(() => { - toolbarInputs = { - activeItem: signal(undefined), - orientation: signal('horizontal'), - textDirection: signal('ltr'), - disabled: signal(false), - skipDisabled: signal(true), - wrap: signal(false), - }; - const widgetInputs = [ - {disabled: signal(false)}, - {disabled: signal(false)}, - { - disabled: signal(false), - controls: signal(undefined), - }, - {disabled: signal(false)}, - ]; - const {toolbar: newToolbar, items: newItems} = createToolbar( - widgetInputs, - toolbarInputs, - ); - toolbar = newToolbar; - items = newItems; - toolbarInputs.activeItem.set(items[0]); - }); - - it('should set the active item on pointerdown', () => { - toolbar.onPointerdown(click(items[1].element())); - expect(toolbarInputs.activeItem()).toBe(items[1]); - }); - - it('should not set the active item on pointerdown if the toolbar is disabled', () => { - toolbarInputs.disabled.set(true); - toolbar.onPointerdown(click(items[1].element())); - expect(toolbarInputs.activeItem()).toBe(items[0]); - }); - }); - - describe('#setDefaultState', () => { - let toolbar: ToolbarPattern; - let toolbarInputs: TestToolbarInputs; - let widgetInputs: (TestToolbarWidgetInputs | TestToolbarWidgetGroupInputs)[]; - let items: (ToolbarWidgetPattern | ToolbarWidgetGroupPattern)[]; - - beforeEach(() => { - toolbarInputs = { - activeItem: signal(undefined), - orientation: signal('horizontal'), - textDirection: signal('ltr'), - disabled: signal(false), - skipDisabled: signal(true), - wrap: signal(false), - }; - widgetInputs = [ - {disabled: signal(false)}, - {disabled: signal(false)}, - { - disabled: signal(false), - controls: signal(undefined), - }, - ]; - const {toolbar: newToolbar, items: newItems} = createToolbar( - widgetInputs, - toolbarInputs, - ); - toolbar = newToolbar; - items = newItems; - }); - - it('should set the active item to the first focusable widget', () => { - toolbar.setDefaultState(); - expect(toolbarInputs.activeItem()).toBe(items[0]); - }); - - it('should skip disabled widgets and set the next focusable widget as active', () => { - widgetInputs[0].disabled.set(true); - toolbar.setDefaultState(); - expect(toolbarInputs.activeItem()).toBe(items[1]); - }); - - it('should call "setDefaultState" on a widget group if it is the first focusable item', () => { - const fakeControls = jasmine.createSpyObj('fakeControls', [ - 'setDefaultState', - ]); - (widgetInputs[2] as TestToolbarWidgetGroupInputs).controls.set(fakeControls); - - widgetInputs[0].disabled.set(true); - widgetInputs[1].disabled.set(true); - toolbar.setDefaultState(); - expect(toolbarInputs.activeItem()).toBe(items[2]); - expect(fakeControls.setDefaultState).toHaveBeenCalled(); - }); - }); - - describe('Widget Group', () => { - let toolbar: ToolbarPattern; - let toolbarInputs: TestToolbarInputs; - let items: (ToolbarWidgetPattern | ToolbarWidgetGroupPattern)[]; - let fakeControls: jasmine.SpyObj; - - beforeEach(() => { - fakeControls = jasmine.createSpyObj('fakeControls', [ - 'next', - 'prev', - 'first', - 'last', - 'unfocus', - 'trigger', - 'goto', - 'setDefaultState', - 'isOnFirstItem', - 'isOnLastItem', - ]); - toolbarInputs = { - activeItem: signal(undefined), - orientation: signal('horizontal'), - textDirection: signal('ltr'), - disabled: signal(false), - skipDisabled: signal(true), - wrap: signal(false), - }; - const widgetInputs = [ - {disabled: signal(false)}, - { - disabled: signal(false), - controls: signal(fakeControls), - }, - {disabled: signal(false)}, - ]; - const {toolbar: newToolbar, items: newItems} = createToolbar( - widgetInputs, - toolbarInputs, - ); - toolbar = newToolbar; - items = newItems; - - // Set the widget group as the active item for tests. - toolbarInputs.activeItem.set(items[1]); - }); - - it('should call "next" on the group handler when navigating next (horizontal)', () => { - fakeControls.isOnLastItem.and.returnValue(false); - toolbar.onKeydown(right()); - expect(fakeControls.next).toHaveBeenCalledWith(false); - }); - - it('should call "next" on the group handler when navigating next (vertical)', () => { - fakeControls.isOnLastItem.and.returnValue(false); - toolbarInputs.orientation.set('vertical'); - toolbar.onKeydown(down()); - expect(fakeControls.next).toHaveBeenCalledWith(false); - }); - - it('should navigate to the next widget if the group allows it', () => { - fakeControls.isOnLastItem.and.returnValue(true); - toolbar.onKeydown(right()); - expect(toolbarInputs.activeItem()).toBe(items[2]); - expect(fakeControls.unfocus).toHaveBeenCalled(); - }); - - it('should not navigate to the next widget if the group prevents it', () => { - fakeControls.isOnLastItem.and.returnValue(false); - toolbar.onKeydown(right()); - expect(toolbarInputs.activeItem()).toBe(items[1]); - expect(fakeControls.next).toHaveBeenCalledWith(false); - }); - - it('should call "prev" on the group handler when navigating previous (horizontal)', () => { - fakeControls.isOnFirstItem.and.returnValue(false); - toolbar.onKeydown(left()); - expect(fakeControls.prev).toHaveBeenCalledWith(false); - }); - - it('should call "prev" on the group handler when navigating previous (vertical)', () => { - fakeControls.isOnFirstItem.and.returnValue(false); - toolbarInputs.orientation.set('vertical'); - toolbar.onKeydown(up()); - expect(fakeControls.prev).toHaveBeenCalledWith(false); - }); - - it('should navigate to the previous widget if the group allows it', () => { - fakeControls.isOnFirstItem.and.returnValue(true); - toolbar.onKeydown(left()); - expect(toolbarInputs.activeItem()).toBe(items[0]); - expect(fakeControls.unfocus).toHaveBeenCalled(); - }); - - it('should not navigate to the previous widget if the group prevents it', () => { - fakeControls.isOnFirstItem.and.returnValue(false); - toolbar.onKeydown(left()); - expect(toolbarInputs.activeItem()).toBe(items[1]); - expect(fakeControls.prev).toHaveBeenCalledWith(false); - }); - - it('should call "unfocus" on the group handler on Home', () => { - toolbar.onKeydown(home()); - expect(fakeControls.unfocus).toHaveBeenCalled(); - expect(toolbarInputs.activeItem()).toBe(items[0]); // Also moves focus - }); - - it('should call "unfocus" on the group handler on End', () => { - toolbar.onKeydown(end()); - expect(fakeControls.unfocus).toHaveBeenCalled(); - expect(toolbarInputs.activeItem()).toBe(items[2]); // Also moves focus - }); - - it('should call "trigger" on the group handler on Enter', () => { - toolbar.onKeydown(enter()); - expect(fakeControls.trigger).toHaveBeenCalled(); - }); - - it('should call "trigger" on the group handler on Space', () => { - toolbar.onKeydown(space()); - expect(fakeControls.trigger).toHaveBeenCalled(); - }); - - it('should call "next" with wrap on the group handler (horizontal)', () => { - toolbar.onKeydown(down()); - expect(fakeControls.next).toHaveBeenCalledWith(true); - }); - - it('should call "next" with wrap on the group handler (vertical)', () => { - toolbarInputs.orientation.set('vertical'); - toolbar.onKeydown(right()); - expect(fakeControls.next).toHaveBeenCalledWith(true); - }); - - it('should call "prev" with wrap on the group handler (horizontal)', () => { - toolbar.onKeydown(up()); - expect(fakeControls.prev).toHaveBeenCalledWith(true); - }); - - it('should call "prev" with wrap on the group handler (vertical)', () => { - toolbarInputs.orientation.set('vertical'); - toolbar.onKeydown(left()); - expect(fakeControls.prev).toHaveBeenCalledWith(true); - }); - - it('should call "first" when navigating into a group from the previous item', () => { - toolbarInputs.activeItem.set(items[0]); - toolbar.onKeydown(right()); - expect(toolbarInputs.activeItem()).toBe(items[1]); - expect(fakeControls.first).toHaveBeenCalled(); - }); - - it('should call "last" when navigating into a group from the next item', () => { - toolbarInputs.activeItem.set(items[2]); - toolbar.onKeydown(left()); - expect(toolbarInputs.activeItem()).toBe(items[1]); - expect(fakeControls.last).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/aria/ui-patterns/toolbar/toolbar.ts b/src/aria/ui-patterns/toolbar/toolbar.ts deleted file mode 100644 index ff704976cc6a..000000000000 --- a/src/aria/ui-patterns/toolbar/toolbar.ts +++ /dev/null @@ -1,247 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {computed, signal} from '@angular/core'; -import {SignalLike} from '../behaviors/signal-like/signal-like'; -import {KeyboardEventManager, PointerEventManager} from '../behaviors/event-manager'; -import {List, ListInputs} from '../behaviors/list/list'; -import {ToolbarWidgetPattern} from './toolbar-widget'; -import {ToolbarWidgetGroupPattern} from './toolbar-widget-group'; - -/** Represents the required inputs for a toolbar. */ -export type ToolbarInputs = Omit< - ListInputs | ToolbarWidgetGroupPattern, V>, - 'multi' | 'typeaheadDelay' | 'value' | 'selectionMode' | 'focusMode' -> & { - /** A function that returns the toolbar item associated with a given element. */ - getItem: (e: Element) => ToolbarWidgetPattern | ToolbarWidgetGroupPattern | undefined; -}; - -/** Controls the state of a toolbar. */ -export class ToolbarPattern { - /** The list behavior for the toolbar. */ - readonly listBehavior: List | ToolbarWidgetGroupPattern, V>; - - /** Whether the tablist is vertically or horizontally oriented. */ - readonly orientation: SignalLike<'vertical' | 'horizontal'>; - - /** Whether disabled items in the group should be skipped when navigating. */ - readonly skipDisabled: SignalLike; - - /** Whether the toolbar is disabled. */ - readonly disabled = computed(() => this.listBehavior.disabled()); - - /** The tabindex of the toolbar (if using activedescendant). */ - readonly tabindex = computed(() => this.listBehavior.tabindex()); - - /** The id of the current active widget (if using activedescendant). */ - readonly activedescendant = computed(() => this.listBehavior.activedescendant()); - - /** The key used to navigate to the previous widget. */ - private readonly _prevKey = computed(() => { - if (this.inputs.orientation() === 'vertical') { - return 'ArrowUp'; - } - return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; - }); - - /** The key used to navigate to the next widget. */ - private readonly _nextKey = computed(() => { - if (this.inputs.orientation() === 'vertical') { - return 'ArrowDown'; - } - return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; - }); - - /** The alternate key used to navigate to the previous widget. */ - private readonly _altPrevKey = computed(() => { - if (this.inputs.orientation() === 'vertical') { - return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; - } - return 'ArrowUp'; - }); - - /** The alternate key used to navigate to the next widget. */ - private readonly _altNextKey = computed(() => { - if (this.inputs.orientation() === 'vertical') { - return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; - } - return 'ArrowDown'; - }); - - /** The keydown event manager for the toolbar. */ - private readonly _keydown = computed(() => { - const manager = new KeyboardEventManager(); - - return manager - .on(this._nextKey, () => this._next()) - .on(this._prevKey, () => this._prev()) - .on(this._altNextKey, () => this._groupNext()) - .on(this._altPrevKey, () => this._groupPrev()) - .on(' ', () => this._trigger()) - .on('Enter', () => this._trigger()) - .on('Home', () => this._first()) - .on('End', () => this._last()); - }); - - /** The pointerdown event manager for the toolbar. */ - private readonly _pointerdown = computed(() => new PointerEventManager().on(e => this._goto(e))); - - /** Navigates to the next widget in the toolbar. */ - private _next() { - const item = this.inputs.activeItem(); - if (item instanceof ToolbarWidgetGroupPattern) { - if (!item.disabled() && !item.controls().isOnLastItem()) { - item.controls().next(false); - return; - } - item.controls().unfocus(); - } - - this.listBehavior.next(); - const newItem = this.inputs.activeItem(); - if (newItem instanceof ToolbarWidgetGroupPattern) { - newItem.controls().first(); - } - } - - /** Navigates to the previous widget in the toolbar. */ - private _prev() { - const item = this.inputs.activeItem(); - if (item instanceof ToolbarWidgetGroupPattern) { - if (!item.disabled() && !item.controls().isOnFirstItem()) { - item.controls().prev(false); - return; - } - item.controls().unfocus(); - } - - this.listBehavior.prev(); - const newItem = this.inputs.activeItem(); - if (newItem instanceof ToolbarWidgetGroupPattern) { - newItem.controls().last(); - } - } - - private _groupNext() { - const item = this.inputs.activeItem(); - if (item instanceof ToolbarWidgetPattern) return; - item?.controls().next(true); - } - - private _groupPrev() { - const item = this.inputs.activeItem(); - if (item instanceof ToolbarWidgetPattern) return; - item?.controls().prev(true); - } - - /** Triggers the action of the currently active widget. */ - private _trigger() { - const item = this.inputs.activeItem(); - if (item instanceof ToolbarWidgetGroupPattern) { - item.controls().trigger(); - } - } - - /** Navigates to the first widget in the toolbar. */ - private _first() { - const item = this.inputs.activeItem(); - if (item instanceof ToolbarWidgetGroupPattern) { - item.controls().unfocus(); - } - - this.listBehavior.first(); - const newItem = this.inputs.activeItem(); - if (newItem instanceof ToolbarWidgetGroupPattern) { - newItem.controls().first(); - } - } - - /** Navigates to the last widget in the toolbar. */ - private _last() { - const item = this.inputs.activeItem(); - if (item instanceof ToolbarWidgetGroupPattern) { - item.controls().unfocus(); - } - - this.listBehavior.last(); - const newItem = this.inputs.activeItem(); - if (newItem instanceof ToolbarWidgetGroupPattern) { - newItem.controls().last(); - } - } - - /** Navigates to the widget targeted by a pointer event. */ - private _goto(e: PointerEvent) { - const item = this.inputs.getItem(e.target as Element); - if (!item) return; - - this.listBehavior.goto(item); - if (item instanceof ToolbarWidgetGroupPattern) { - item.controls().goto(e); - } - } - - constructor(readonly inputs: ToolbarInputs) { - this.orientation = inputs.orientation; - this.skipDisabled = inputs.skipDisabled; - - this.listBehavior = new List({ - ...inputs, - multi: () => false, - focusMode: () => 'roving', - selectionMode: () => 'explicit', - value: signal([] as V[]), - typeaheadDelay: () => 0, // Toolbar widgets do not support typeahead. - }); - } - - /** Handles keydown events for the toolbar. */ - onKeydown(event: KeyboardEvent) { - if (this.disabled()) return; - this._keydown().handle(event); - } - - /** Handles pointerdown events for the toolbar. */ - onPointerdown(event: PointerEvent) { - if (this.disabled()) return; - this._pointerdown().handle(event); - } - - /** - * Sets the toolbar to its default initial state. - * - * Sets the active index to the selected widget if one exists and is focusable. - * Otherwise, sets the active index to the first focusable widget. - */ - setDefaultState() { - let firstItem: ToolbarWidgetPattern | ToolbarWidgetGroupPattern | null = null; - - for (const item of this.inputs.items()) { - if (this.listBehavior.isFocusable(item)) { - if (!firstItem) { - firstItem = item; - } - } - } - - if (firstItem) { - this.inputs.activeItem.set(firstItem); - } - if (firstItem instanceof ToolbarWidgetGroupPattern) { - firstItem.controls().setDefaultState(); - } - } - - /** Validates the state of the toolbar and returns a list of accessibility violations. */ - validate(): string[] { - const violations: string[] = []; - - return violations; - } -} diff --git a/src/aria/version.ts b/src/aria/version.ts index 4093760bb305..4229bfc1984e 100644 --- a/src/aria/version.ts +++ b/src/aria/version.ts @@ -8,5 +8,5 @@ import {Version} from '@angular/core'; -/** Current version of the CDK Experimental package. */ +/** Current version of the Aria package. */ export const VERSION = new Version('0.0.0-PLACEHOLDER'); diff --git a/src/cdk/BUILD.bazel b/src/cdk/BUILD.bazel index f259d341b810..252314d2d142 100644 --- a/src/cdk/BUILD.bazel +++ b/src/cdk/BUILD.bazel @@ -60,8 +60,10 @@ ng_package( ] + prebuiltStyleTargets + CDK_SCSS_LIBS, nested_packages = [ "//src/cdk/schematics:npm_package", - ":adev_assets", - ], + ] + select({ + "//:snapshot_adev_assets": [":adev_assets"], + "//conditions:default": [], + }), replace_prefixes = { "adev_assets/": "_adev_assets/", }, diff --git a/src/cdk/a11y/id-generator.ts b/src/cdk/a11y/id-generator.ts index 55bae7a0a551..843940cf0b85 100644 --- a/src/cdk/a11y/id-generator.ts +++ b/src/cdk/a11y/id-generator.ts @@ -19,12 +19,14 @@ const counters: Record = {}; @Injectable({providedIn: 'root'}) export class _IdGenerator { private _appId = inject(APP_ID); + private static _infix = `a${Math.floor(Math.random() * 100000).toString()}`; /** * Generates a unique ID with a specific prefix. * @param prefix Prefix to add to the ID. + * @param randomize Add a randomized infix string. */ - getId(prefix: string): string { + getId(prefix: string, randomize: boolean = false): string { // Omit the app ID if it's the default `ng`. Since the vast majority of pages have one // Angular app on them, we can reduce the amount of breakages by not adding it. if (this._appId !== 'ng') { @@ -35,6 +37,6 @@ export class _IdGenerator { counters[prefix] = 0; } - return `${prefix}${counters[prefix]++}`; + return `${prefix}${randomize ? _IdGenerator._infix + '-' : ''}${counters[prefix]++}`; } } diff --git a/src/cdk/clipboard/BUILD.bazel b/src/cdk/clipboard/BUILD.bazel index 8672cd4fcd42..75b33a24cb4f 100644 --- a/src/cdk/clipboard/BUILD.bazel +++ b/src/cdk/clipboard/BUILD.bazel @@ -8,7 +8,6 @@ ng_project( ["**/*.ts"], exclude = ["**/*.spec.ts"], ), - assets = glob(["**/*.html"]), deps = [ "//:node_modules/@angular/common", "//:node_modules/@angular/core", diff --git a/src/cdk/collections/dispose-view-repeater-strategy.ts b/src/cdk/collections/dispose-view-repeater-strategy.ts index 3404ee747942..91eb5cf7fe3f 100644 --- a/src/cdk/collections/dispose-view-repeater-strategy.ts +++ b/src/cdk/collections/dispose-view-repeater-strategy.ts @@ -30,9 +30,11 @@ import { * @template R The type for the item in each IterableDiffer change record. * @template C The type for the context passed to each embedded view. */ -export class _DisposeViewRepeaterStrategy> - implements _ViewRepeater -{ +export class _DisposeViewRepeaterStrategy< + T, + R, + C extends _ViewRepeaterItemContext, +> implements _ViewRepeater { applyChanges( changes: IterableChanges, viewContainerRef: ViewContainerRef, diff --git a/src/cdk/collections/recycle-view-repeater-strategy.ts b/src/cdk/collections/recycle-view-repeater-strategy.ts index 735e32aec9de..9296bbff8b4d 100644 --- a/src/cdk/collections/recycle-view-repeater-strategy.ts +++ b/src/cdk/collections/recycle-view-repeater-strategy.ts @@ -33,9 +33,11 @@ import { * @template R The type for the item in each IterableDiffer change record. * @template C The type for the context passed to each embedded view. */ -export class _RecycleViewRepeaterStrategy> - implements _ViewRepeater -{ +export class _RecycleViewRepeaterStrategy< + T, + R, + C extends _ViewRepeaterItemContext, +> implements _ViewRepeater { /** * The size of the cache used to store unused views. * Setting the cache size to `0` will disable caching. Defaults to 20 views. diff --git a/src/cdk/dialog/dialog.ts b/src/cdk/dialog/dialog.ts index 45ac68f5961c..93ea177750bf 100644 --- a/src/cdk/dialog/dialog.ts +++ b/src/cdk/dialog/dialog.ts @@ -401,7 +401,8 @@ export class Dialog implements OnDestroy { sibling !== overlayContainer && sibling.nodeName !== 'SCRIPT' && sibling.nodeName !== 'STYLE' && - !sibling.hasAttribute('aria-live') + !sibling.hasAttribute('aria-live') && + !sibling.hasAttribute('popover') ) { this._ariaHiddenElements.set(sibling, sibling.getAttribute('aria-hidden')); sibling.setAttribute('aria-hidden', 'true'); diff --git a/src/cdk/menu/context-menu-trigger.ts b/src/cdk/menu/context-menu-trigger.ts index bf1b5a86ea67..bc6cac4f2798 100644 --- a/src/cdk/menu/context-menu-trigger.ts +++ b/src/cdk/menu/context-menu-trigger.ts @@ -62,6 +62,7 @@ export type ContextMenuCoordinates = {x: number; y: number}; {name: 'menuTemplateRef', alias: 'cdkContextMenuTriggerFor'}, {name: 'menuPosition', alias: 'cdkContextMenuPosition'}, {name: 'menuData', alias: 'cdkContextMenuTriggerData'}, + {name: 'transformOriginSelector', alias: 'cdkContextMenuTriggerTransformOriginOn'}, ], outputs: ['opened: cdkContextMenuOpened', 'closed: cdkContextMenuClosed'], providers: [ @@ -147,10 +148,16 @@ export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestr private _getOverlayPositionStrategy( coordinates: ContextMenuCoordinates, ): FlexibleConnectedPositionStrategy { - return createFlexibleConnectedPositionStrategy(this._injector, coordinates) + const strategy = createFlexibleConnectedPositionStrategy(this._injector, coordinates) .withLockedPosition() .withGrowAfterOpen() .withPositions(this.menuPosition ?? CONTEXT_MENU_POSITIONS); + + if (this.transformOriginSelector) { + strategy.withTransformOriginOn(this.transformOriginSelector); + } + + return strategy; } /** Subscribe to the menu stack close events and close this menu when requested. */ diff --git a/src/cdk/menu/menu-trigger-base.ts b/src/cdk/menu/menu-trigger-base.ts index 7656603cc00a..e5addfc550d6 100644 --- a/src/cdk/menu/menu-trigger-base.ts +++ b/src/cdk/menu/menu-trigger-base.ts @@ -102,6 +102,12 @@ export abstract class CdkMenuTriggerBase implements OnDestroy { /** Context data to be passed along to the menu template */ menuData: unknown; + /** + * Selector for the element on which to set the transform origin once the menu is open. + * This makes it easier to implement animations that start from the attachment point of the menu. + */ + transformOriginSelector: string | null = null; + /** Close the opened menu. */ abstract close(): void; diff --git a/src/cdk/menu/menu-trigger.ts b/src/cdk/menu/menu-trigger.ts index d37ab81a4205..3b4d5b48dee3 100644 --- a/src/cdk/menu/menu-trigger.ts +++ b/src/cdk/menu/menu-trigger.ts @@ -69,6 +69,7 @@ import {eventDispatchesNativeClick} from './event-detection'; {name: 'menuTemplateRef', alias: 'cdkMenuTriggerFor'}, {name: 'menuPosition', alias: 'cdkMenuPosition'}, {name: 'menuData', alias: 'cdkMenuTriggerData'}, + {name: 'transformOriginSelector', alias: 'cdkMenuTriggerTransformOriginOn'}, ], outputs: ['opened: cdkMenuOpened', 'closed: cdkMenuClosed'], providers: [ @@ -281,10 +282,16 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD /** Build the position strategy for the overlay which specifies where to place the menu. */ private _getOverlayPositionStrategy(): FlexibleConnectedPositionStrategy { - return createFlexibleConnectedPositionStrategy(this._injector, this._elementRef) + const strategy = createFlexibleConnectedPositionStrategy(this._injector, this._elementRef) .withLockedPosition() .withFlexibleDimensions(false) .withPositions(this._getOverlayPositions()); + + if (this.transformOriginSelector) { + strategy.withTransformOriginOn(this.transformOriginSelector); + } + + return strategy; } /** Get the preferred positions for the opened menu relative to the menu item. */ diff --git a/src/cdk/overlay/_index.scss b/src/cdk/overlay/_index.scss index 6952e9dcb9ba..db174855c55b 100644 --- a/src/cdk/overlay/_index.scss +++ b/src/cdk/overlay/_index.scss @@ -185,6 +185,41 @@ $backdrop-animation-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !default; // block scrolling on a page that doesn't have a scrollbar in the first place. overflow-y: scroll; } + + .cdk-overlay-popover { + background: none; + border: none; + padding: 0; + outline: 0; + overflow: visible; + position: fixed; + pointer-events: none; + white-space: normal; + color: inherit; + text-decoration: none; + + // These are important so the overlay can be measured before it's fully inserted. + width: 100%; + height: 100%; + + // Chrome sets a user agent style of `inset: 0` which combined + // with `align-self` can break the positioning (see #29809). + inset: auto; + + // Some older versions of Chrome won't render the popover properly without these. + top: 0; + left: 0; + + // For the time being we're using our `.cdk-overlay-backdrop` element instead of the native one. + &::backdrop { + display: none; + } + + .cdk-overlay-backdrop { + position: fixed; + z-index: auto; + } + } } /// Emits structural styles required for cdk/overlay to function. diff --git a/src/cdk/overlay/overlay-config.ts b/src/cdk/overlay/overlay-config.ts index fa1d96551280..c49ed9c1eb2b 100644 --- a/src/cdk/overlay/overlay-config.ts +++ b/src/cdk/overlay/overlay-config.ts @@ -61,6 +61,12 @@ export class OverlayConfig { */ disposeOnNavigation?: boolean = false; + /** + * Whether the overlay should be rendered as a native popover element, + * rather than placing it inside of the overlay container. + */ + usePopover?: boolean; + constructor(config?: OverlayConfig) { if (config) { // Use `Iterable` instead of `Array` because TypeScript, as of 3.6.3, diff --git a/src/cdk/overlay/overlay-directives.spec.ts b/src/cdk/overlay/overlay-directives.spec.ts index 22a161ba1889..ef11a388e13a 100644 --- a/src/cdk/overlay/overlay-directives.spec.ts +++ b/src/cdk/overlay/overlay-directives.spec.ts @@ -626,6 +626,19 @@ describe('Overlay directives', () => { expect(target.style.transformOrigin).toContain('left bottom'); }); + + it('should match the trigger width', () => { + const trigger = fixture.nativeElement.querySelector('#trigger') as HTMLElement; + trigger.style.width = '128px'; + + fixture.componentInstance.matchWidth = true; + fixture.componentInstance.isOpen = true; + fixture.changeDetectorRef.markForCheck(); + fixture.detectChanges(); + + const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + expect(pane.style.width).toBe('128px'); + }); }); describe('outputs', () => { @@ -742,11 +755,11 @@ describe('Overlay directives', () => { @Component({ template: ` - - + + - { [cdkConnectedOverlayMinWidth]="minWidth" [cdkConnectedOverlayMinHeight]="minHeight" [cdkConnectedOverlayPositions]="positionOverrides" - [cdkConnectedOverlayTransformOriginOn]="transformOriginSelector"> + [cdkConnectedOverlayTransformOriginOn]="transformOriginSelector" + [cdkConnectedOverlayMatchWidth]="matchWidth">

        Menu content

        `, imports: [OverlayModule], @@ -809,12 +823,14 @@ class ConnectedOverlayDirectiveTest { detachHandler = jasmine.createSpy('detachHandler'); attachResult: HTMLElement; transformOriginSelector: string; + matchWidth = false; } @Component({ template: ` - - Menu content`, + + Menu content + `, imports: [OverlayModule], }) class ConnectedOverlayPropertyInitOrder { diff --git a/src/cdk/overlay/overlay-directives.ts b/src/cdk/overlay/overlay-directives.ts index 5f4e711b7fc9..f69d079035a9 100644 --- a/src/cdk/overlay/overlay-directives.ts +++ b/src/cdk/overlay/overlay-directives.ts @@ -29,7 +29,7 @@ import { import {_getEventTarget} from '../platform'; import {Subscription} from 'rxjs'; import {takeWhile} from 'rxjs/operators'; -import {createOverlayRef} from './overlay'; +import {createOverlayRef, OVERLAY_DEFAULT_CONFIG} from './overlay'; import {OverlayConfig} from './overlay-config'; import {OverlayRef} from './overlay-ref'; import {ConnectedOverlayPositionChange, ViewportMargin} from './position/connected-position'; @@ -38,6 +38,7 @@ import { createFlexibleConnectedPositionStrategy, FlexibleConnectedPositionStrategy, FlexibleConnectedPositionStrategyOrigin, + FlexibleOverlayPopoverLocation, } from './position/flexible-connected-position-strategy'; import {createRepositionScrollStrategy, ScrollStrategy} from './scroll/index'; @@ -96,6 +97,41 @@ export class CdkOverlayOrigin { constructor() {} } +/** + * Injection token that can be used to configure the + * default options for the `CdkConnectedOverlay` directive. + */ +export const CDK_CONNECTED_OVERLAY_DEFAULT_CONFIG = new InjectionToken( + 'cdk-connected-overlay-default-config', +); + +/** Object used to configure the `CdkConnectedOverlay` directive. */ +export interface CdkConnectedOverlayConfig { + origin?: CdkOverlayOrigin | FlexibleConnectedPositionStrategyOrigin; + positions?: ConnectedPosition[]; + positionStrategy?: FlexibleConnectedPositionStrategy; + offsetX?: number; + offsetY?: number; + width?: number | string; + height?: number | string; + minWidth?: number | string; + minHeight?: number | string; + backdropClass?: string | string[]; + panelClass?: string | string[]; + viewportMargin?: ViewportMargin; + scrollStrategy?: ScrollStrategy; + disableClose?: boolean; + transformOriginSelector?: string; + hasBackdrop?: boolean; + lockPosition?: boolean; + flexibleDimensions?: boolean; + growAfterOpen?: boolean; + push?: boolean; + disposeOnNavigation?: boolean; + usePopover?: FlexibleOverlayPopoverLocation | null; + matchWidth?: boolean; +} + /** * Directive to facilitate declarative creation of an * Overlay using a FlexibleConnectedPositionStrategy. @@ -118,7 +154,6 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { private _offsetY: number; private _position: FlexibleConnectedPositionStrategy; private _scrollStrategyFactory = inject(CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY); - private _disposeOnNavigation = false; private _ngZone = inject(NgZone); /** Origin for the connected overlay. */ @@ -214,11 +249,22 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { /** Whether the overlay should be disposed of when the user goes backwards/forwards in history. */ @Input({alias: 'cdkConnectedOverlayDisposeOnNavigation', transform: booleanAttribute}) - get disposeOnNavigation(): boolean { - return this._disposeOnNavigation; - } - set disposeOnNavigation(value: boolean) { - this._disposeOnNavigation = value; + disposeOnNavigation: boolean = false; + + /** Whether the connected overlay should be rendered inside a popover element or the overlay container. */ + @Input({alias: 'cdkConnectedOverlayUsePopover'}) + usePopover: FlexibleOverlayPopoverLocation | null; + + /** Whether the overlay should match the trigger's width. */ + @Input({alias: 'cdkConnectedOverlayMatchWidth', transform: booleanAttribute}) + matchWidth: boolean = false; + + /** Shorthand for setting multiple overlay options at once. */ + @Input('cdkConnectedOverlay') + set _config(value: string | CdkConnectedOverlayConfig) { + if (typeof value !== 'string') { + this._assignConfig(value); + } } /** Event emitted when the backdrop is clicked. */ @@ -246,9 +292,16 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { constructor() { const templateRef = inject>(TemplateRef); const viewContainerRef = inject(ViewContainerRef); + const defaultConfig = inject(CDK_CONNECTED_OVERLAY_DEFAULT_CONFIG, {optional: true}); + const globalConfig = inject(OVERLAY_DEFAULT_CONFIG, {optional: true}); + this.usePopover = globalConfig?.usePopover === false ? null : 'global'; this._templatePortal = new TemplatePortal(templateRef, viewContainerRef); this.scrollStrategy = this._scrollStrategyFactory(); + + if (defaultConfig) { + this._assignConfig(defaultConfig); + } } /** The associated overlay reference. */ @@ -273,7 +326,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { if (this._position) { this._updatePositionStrategy(this._position); this._overlayRef?.updateSize({ - width: this.width, + width: this._getWidth(), minWidth: this.minWidth, height: this.height, minHeight: this.minHeight, @@ -327,12 +380,9 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { scrollStrategy: this.scrollStrategy, hasBackdrop: this.hasBackdrop, disposeOnNavigation: this.disposeOnNavigation, + usePopover: !!this.usePopover, }); - if (this.width || this.width === 0) { - overlayConfig.width = this.width; - } - if (this.height || this.height === 0) { overlayConfig.height = this.height; } @@ -376,7 +426,8 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { .withGrowAfterOpen(this.growAfterOpen) .withViewportMargin(this.viewportMargin) .withLockedPosition(this.lockPosition) - .withTransformOriginOn(this.transformOriginSelector); + .withTransformOriginOn(this.transformOriginSelector) + .withPopoverLocation(this.usePopover === null ? 'global' : this.usePopover); } /** Returns the position strategy of the overlay to be set on the overlay config */ @@ -410,23 +461,35 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { return null; } + private _getWidth() { + if (this.width) { + return this.width; + } + + // Null check `getBoundingClientRect` in case this is called during SSR. + return this.matchWidth ? this._getOriginElement()?.getBoundingClientRect?.().width : undefined; + } + /** Attaches the overlay. */ attachOverlay() { if (!this._overlayRef) { this._createOverlay(); - } else { - // Update the overlay size, in case the directive's inputs have changed - this._overlayRef.getConfig().hasBackdrop = this.hasBackdrop; } - if (!this._overlayRef!.hasAttached()) { - this._overlayRef!.attach(this._templatePortal); + const ref = this._overlayRef!; + + // Update the overlay size, in case the directive's inputs have changed + ref.getConfig().hasBackdrop = this.hasBackdrop; + ref.updateSize({width: this._getWidth()}); + + if (!ref.hasAttached()) { + ref.attach(this._templatePortal); } if (this.hasBackdrop) { - this._backdropSubscription = this._overlayRef!.backdropClick().subscribe(event => { - this.backdropClick.emit(event); - }); + this._backdropSubscription = ref + .backdropClick() + .subscribe(event => this.backdropClick.emit(event)); } else { this._backdropSubscription.unsubscribe(); } @@ -457,4 +520,30 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { this._positionSubscription.unsubscribe(); this.open = false; } + + private _assignConfig(config: CdkConnectedOverlayConfig) { + this.origin = config.origin ?? this.origin; + this.positions = config.positions ?? this.positions; + this.positionStrategy = config.positionStrategy ?? this.positionStrategy; + this.offsetX = config.offsetX ?? this.offsetX; + this.offsetY = config.offsetY ?? this.offsetY; + this.width = config.width ?? this.width; + this.height = config.height ?? this.height; + this.minWidth = config.minWidth ?? this.minWidth; + this.minHeight = config.minHeight ?? this.minHeight; + this.backdropClass = config.backdropClass ?? this.backdropClass; + this.panelClass = config.panelClass ?? this.panelClass; + this.viewportMargin = config.viewportMargin ?? this.viewportMargin; + this.scrollStrategy = config.scrollStrategy ?? this.scrollStrategy; + this.disableClose = config.disableClose ?? this.disableClose; + this.transformOriginSelector = config.transformOriginSelector ?? this.transformOriginSelector; + this.hasBackdrop = config.hasBackdrop ?? this.hasBackdrop; + this.lockPosition = config.lockPosition ?? this.lockPosition; + this.flexibleDimensions = config.flexibleDimensions ?? this.flexibleDimensions; + this.growAfterOpen = config.growAfterOpen ?? this.growAfterOpen; + this.push = config.push ?? this.push; + this.disposeOnNavigation = config.disposeOnNavigation ?? this.disposeOnNavigation; + this.usePopover = config.usePopover ?? this.usePopover; + this.matchWidth = config.matchWidth ?? this.matchWidth; + } } diff --git a/src/cdk/overlay/overlay-ref.ts b/src/cdk/overlay/overlay-ref.ts index 4a0ef74ca1a6..ab9bae62f63c 100644 --- a/src/cdk/overlay/overlay-ref.ts +++ b/src/cdk/overlay/overlay-ref.ts @@ -32,6 +32,11 @@ export type ImmutableObject = { readonly [P in keyof T]: T[P]; }; +/** Checks if a value is an element. */ +export function isElement(value: any): value is Element { + return value && (value as Element).nodeType === 1; +} + /** * Reference to an overlay that has been created with the Overlay service. * Used to manipulate or dispose of said overlay. @@ -46,6 +51,7 @@ export class OverlayRef implements PortalOutlet { private _backdropRef: BackdropRef | null = null; private _detachContentMutationObserver: MutationObserver | undefined; private _detachContentAfterRenderRef: AfterRenderRef | undefined; + private _disposed: boolean; /** * Reference to the parent of the `_host` at the time it was detached. Used to restore @@ -115,18 +121,16 @@ export class OverlayRef implements PortalOutlet { * @returns The portal attachment result. */ attach(portal: Portal): any { + if (this._disposed) { + return null; + } + // Insert the host into the DOM before attaching the portal, otherwise // the animations module will skip animations on repeat attachments. - if (!this._host.parentElement && this._previousHostParent) { - this._previousHostParent.appendChild(this._host); - } + this._attachHost(); const attachResult = this._portalOutlet.attach(portal); - - if (this._positionStrategy) { - this._positionStrategy.attach(this); - } - + this._positionStrategy?.attach(this); this._updateStackingOrder(); this._updateElementSize(); this._updateElementDirection(); @@ -241,6 +245,10 @@ export class OverlayRef implements PortalOutlet { /** Cleans up the overlay from the DOM. */ dispose(): void { + if (this._disposed) { + return; + } + const isAttached = this.hasAttached(); if (this._positionStrategy) { @@ -267,6 +275,7 @@ export class OverlayRef implements PortalOutlet { this._detachments.complete(); this._completeDetachContent(); + this._disposed = true; } /** Whether the overlay has attached content. */ @@ -409,6 +418,31 @@ export class OverlayRef implements PortalOutlet { this._pane.style.pointerEvents = enablePointer ? '' : 'none'; } + private _attachHost() { + if (!this._host.parentElement) { + const customInsertionPoint = this._config.usePopover + ? this._positionStrategy?.getPopoverInsertionPoint?.() + : null; + + if (isElement(customInsertionPoint)) { + customInsertionPoint.after(this._host); + } else if (customInsertionPoint?.type === 'parent') { + customInsertionPoint.element.appendChild(this._host); + } else { + this._previousHostParent?.appendChild(this._host); + } + } + + if (this._config.usePopover) { + // We need the try/catch because the browser will throw if the + // host or any of the parents are outside the DOM. Also note + // the string access which is there for compatibility with Closure. + try { + this._host['showPopover'](); + } catch {} + } + } + /** Attaches a backdrop for this overlay. */ private _attachBackdrop() { const showingClass = 'cdk-overlay-backdrop-showing'; @@ -426,9 +460,14 @@ export class OverlayRef implements PortalOutlet { this._toggleClasses(this._backdropRef.element, this._config.backdropClass, true); } - // Insert the backdrop before the pane in the DOM order, - // in order to handle stacked overlays properly. - this._host.parentElement!.insertBefore(this._backdropRef.element, this._host); + if (this._config.usePopover) { + // When using popovers, the backdrop needs to be inside the popover. + this._host.prepend(this._backdropRef.element); + } else { + // Insert the backdrop before the pane in the DOM order, + // in order to handle stacked overlays properly. + this._host.parentElement!.insertBefore(this._backdropRef.element, this._host); + } // Add class to fade-in the backdrop after one frame. if (!this._animationsDisabled && typeof requestAnimationFrame !== 'undefined') { @@ -448,7 +487,7 @@ export class OverlayRef implements PortalOutlet { * in its original DOM position. */ private _updateStackingOrder() { - if (this._host.nextSibling) { + if (!this._config.usePopover && this._host.nextSibling) { this._host.parentNode!.appendChild(this._host); } } diff --git a/src/cdk/overlay/overlay.spec.ts b/src/cdk/overlay/overlay.spec.ts index 20fcb3f9d5b1..c2c0ac0aebd5 100644 --- a/src/cdk/overlay/overlay.spec.ts +++ b/src/cdk/overlay/overlay.spec.ts @@ -141,9 +141,9 @@ describe('Overlay', () => { expect(overlayContainerElement.textContent).toBe(''); }); - it('should ensure that the most-recently-attached overlay is on top', () => { - let pizzaOverlayRef = createOverlayRef(injector); - let cakeOverlayRef = createOverlayRef(injector); + it('should ensure that the most-recently-attached overlay is on top when popovers are disabled', () => { + let pizzaOverlayRef = createOverlayRef(injector, {usePopover: false}); + let cakeOverlayRef = createOverlayRef(injector, {usePopover: false}); pizzaOverlayRef.attach(componentPortal); cakeOverlayRef.attach(templatePortal); @@ -495,6 +495,13 @@ describe('Overlay', () => { expect(paneElement.childNodes.length).toBe(0); })); + it('should do nothing when trying to attach a disposed overlay', () => { + const overlayRef = createOverlayRef(injector); + overlayRef.dispose(); + overlayRef.attach(componentPortal); + expect(document.querySelector('.cdk-overlay-pane')).toBeFalsy(); + }); + describe('positioning', () => { let config: OverlayConfig; @@ -850,7 +857,7 @@ describe('Overlay', () => { }); it('should insert the backdrop before the overlay host in the DOM order', () => { - const overlayRef = createOverlayRef(injector, config); + const overlayRef = createOverlayRef(injector, {...config, usePopover: false}); overlayRef.attach(componentPortal); viewContainerFixture.detectChanges(); diff --git a/src/cdk/overlay/overlay.ts b/src/cdk/overlay/overlay.ts index 935196bd2c3e..18c016236c2a 100644 --- a/src/cdk/overlay/overlay.ts +++ b/src/cdk/overlay/overlay.ts @@ -20,6 +20,7 @@ import { RendererFactory2, DOCUMENT, Renderer2, + InjectionToken, } from '@angular/core'; import {_IdGenerator} from '../a11y'; import {_CdkPrivateStyleLoader} from '../private'; @@ -27,10 +28,20 @@ import {OverlayKeyboardDispatcher} from './dispatchers/overlay-keyboard-dispatch import {OverlayOutsideClickDispatcher} from './dispatchers/overlay-outside-click-dispatcher'; import {OverlayConfig} from './overlay-config'; import {_CdkOverlayStyleLoader, OverlayContainer} from './overlay-container'; -import {OverlayRef} from './overlay-ref'; +import {isElement, OverlayRef} from './overlay-ref'; import {OverlayPositionBuilder} from './position/overlay-position-builder'; import {ScrollStrategyOptions} from './scroll/index'; +/** Object used to configure the default options for overlays. */ +export interface OverlayDefaultConfig { + usePopover?: boolean; +} + +/** Injection token used to configure the default options for CDK overlays. */ +export const OVERLAY_DEFAULT_CONFIG = new InjectionToken( + 'OVERLAY_DEFAULT_CONFIG', +); + /** * Creates an overlay. * @param injector Injector to use when resolving the overlay's dependencies. @@ -47,25 +58,50 @@ export function createOverlayRef(injector: Injector, config?: OverlayConfig): Ov const idGenerator = injector.get(_IdGenerator); const appRef = injector.get(ApplicationRef); const directionality = injector.get(Directionality); + const renderer = + injector.get(Renderer2, null, {optional: true}) || + injector.get(RendererFactory2).createRenderer(null, null); - const host = doc.createElement('div'); - const pane = doc.createElement('div'); + const overlayConfig = new OverlayConfig(config); + const defaultUsePopover = + injector.get(OVERLAY_DEFAULT_CONFIG, null, {optional: true})?.usePopover ?? true; + + overlayConfig.direction = overlayConfig.direction || directionality.value; + + if (!('showPopover' in doc.body)) { + overlayConfig.usePopover = false; + } else { + overlayConfig.usePopover = config?.usePopover ?? defaultUsePopover; + } + const pane = doc.createElement('div'); + const host = doc.createElement('div'); pane.id = idGenerator.getId('cdk-overlay-'); pane.classList.add('cdk-overlay-pane'); host.appendChild(pane); - overlayContainer.getContainerElement().appendChild(host); - const portalOutlet = new DomPortalOutlet(pane, appRef, injector); - const overlayConfig = new OverlayConfig(config); - const renderer = - injector.get(Renderer2, null, {optional: true}) || - injector.get(RendererFactory2).createRenderer(null, null); + if (overlayConfig.usePopover) { + host.setAttribute('popover', 'manual'); + host.classList.add('cdk-overlay-popover'); + } - overlayConfig.direction = overlayConfig.direction || directionality.value; + const customInsertionPoint = overlayConfig.usePopover + ? overlayConfig.positionStrategy?.getPopoverInsertionPoint?.() + : null; + + // Note: this is redundant since the host will be moved into its final location immediately + // after. We're keeping it as a temporary workaround, because an internal team depends on + // this behavior. We can roll this back after January 5th 2026. + overlayContainer.getContainerElement().appendChild(host); + + if (isElement(customInsertionPoint)) { + customInsertionPoint.after(host); + } else if (customInsertionPoint?.type === 'parent') { + customInsertionPoint.element.appendChild(host); + } return new OverlayRef( - portalOutlet, + new DomPortalOutlet(pane, appRef, injector), host, pane, overlayConfig, diff --git a/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts b/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts index 2f09db158279..45014d01ed85 100644 --- a/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts +++ b/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts @@ -33,6 +33,7 @@ describe('FlexibleConnectedPositionStrategy', () => { let overlayRef: OverlayRef; let viewport: ViewportRuler; let injector: Injector; + let portal: ComponentPortal; beforeEach(() => { injector = TestBed.inject(Injector); @@ -50,7 +51,8 @@ describe('FlexibleConnectedPositionStrategy', () => { function attachOverlay(config: OverlayConfig) { overlayRef = createOverlayRef(injector, config); - overlayRef.attach(new ComponentPortal(TestOverlay)); + portal = new ComponentPortal(TestOverlay); + overlayRef.attach(portal); TestBed.inject(ApplicationRef).tick(); } @@ -125,7 +127,7 @@ describe('FlexibleConnectedPositionStrategy', () => { origin.remove(); }); - it('should for the virtual keyboard offset when positioning the overlay', () => { + it('should account for the virtual keyboard offset when positioning the overlay', () => { const originElement = createPositionedBlockElement(); document.body.appendChild(originElement); @@ -138,6 +140,7 @@ describe('FlexibleConnectedPositionStrategy', () => { overlayContainer.getContainerElement().style.top = '-100px'; attachOverlay({ + usePopover: false, positionStrategy: createFlexibleConnectedPositionStrategy(injector, originElement) .withFlexibleDimensions(false) .withPush(false) @@ -2640,7 +2643,7 @@ describe('FlexibleConnectedPositionStrategy', () => { attachOverlay({positionStrategy}); expect(overlayRef.hostElement.style.left).toBeTruthy(); - expect(overlayRef.hostElement.style.right).toBeFalsy(); + expect(overlayRef.hostElement.style.right).toBe('auto'); }); it('should use `right` when positioning an element at the end', () => { @@ -2656,7 +2659,7 @@ describe('FlexibleConnectedPositionStrategy', () => { attachOverlay({positionStrategy}); expect(overlayRef.hostElement.style.right).toBeTruthy(); - expect(overlayRef.hostElement.style.left).toBeFalsy(); + expect(overlayRef.hostElement.style.left).toBe('auto'); }); }); @@ -2677,7 +2680,7 @@ describe('FlexibleConnectedPositionStrategy', () => { }); expect(overlayRef.hostElement.style.right).toBeTruthy(); - expect(overlayRef.hostElement.style.left).toBeFalsy(); + expect(overlayRef.hostElement.style.left).toBe('auto'); }); it('should use `left` when positioning an element at the end', () => { @@ -2693,7 +2696,7 @@ describe('FlexibleConnectedPositionStrategy', () => { attachOverlay({positionStrategy, direction: 'rtl'}); expect(overlayRef.hostElement.style.left).toBeTruthy(); - expect(overlayRef.hostElement.style.right).toBeFalsy(); + expect(overlayRef.hostElement.style.right).toBe('auto'); }); }); @@ -2711,7 +2714,7 @@ describe('FlexibleConnectedPositionStrategy', () => { attachOverlay({positionStrategy}); expect(overlayRef.hostElement.style.top).toBeTruthy(); - expect(overlayRef.hostElement.style.bottom).toBeFalsy(); + expect(overlayRef.hostElement.style.bottom).toBe('auto'); }); it('should use `bottom` when positioning at element along the bottom', () => { @@ -2727,7 +2730,7 @@ describe('FlexibleConnectedPositionStrategy', () => { attachOverlay({positionStrategy}); expect(overlayRef.hostElement.style.bottom).toBeTruthy(); - expect(overlayRef.hostElement.style.top).toBeFalsy(); + expect(overlayRef.hostElement.style.top).toBe('auto'); }); }); }); @@ -2951,6 +2954,97 @@ describe('FlexibleConnectedPositionStrategy', () => { expect(overlayClassList).toContain('custom-panel-class'); }); }); + + describe('DOM location', () => { + let positionStrategy: FlexibleConnectedPositionStrategy; + let containerElement: HTMLElement; + let originElement: HTMLElement; + let customHostElement: HTMLElement; + + beforeEach(() => { + containerElement = overlayContainer.getContainerElement(); + originElement = createPositionedBlockElement(); + customHostElement = createBlockElement('span'); + document.body.appendChild(originElement); + document.body.appendChild(customHostElement); + + positionStrategy = createFlexibleConnectedPositionStrategy(injector, originElement) + .withPopoverLocation('inline') + .withPositions([ + { + overlayX: 'start', + overlayY: 'top', + originX: 'start', + originY: 'bottom', + }, + ]); + }); + + afterEach(() => { + originElement.remove(); + customHostElement.remove(); + }); + + it('should place the overlay inside the overlay container by default', () => { + attachOverlay({positionStrategy, usePopover: false}); + expect(containerElement.contains(overlayRef.hostElement)).toBe(true); + expect(overlayRef.hostElement.getAttribute('popover')).toBeFalsy(); + }); + + it('should be able to opt into placing the overlay inside an adjacent popover element', () => { + if (!('showPopover' in document.body)) { + return; + } + + attachOverlay({positionStrategy, usePopover: true}); + + expect(containerElement.contains(overlayRef.hostElement)).toBe(false); + expect(originElement.nextElementSibling).toBe(overlayRef.hostElement); + expect(overlayRef.hostElement.getAttribute('popover')).toBe('manual'); + }); + + it('should re-attach the popover next to the origin element', () => { + if (!('showPopover' in document.body)) { + return; + } + + attachOverlay({positionStrategy, usePopover: true}); + expect(originElement.nextElementSibling).toBe(overlayRef.hostElement); + + overlayRef.detach(); + TestBed.inject(ApplicationRef).tick(); + expect(overlayRef.hostElement.parentNode).toBeFalsy(); + + overlayRef.attach(portal); + expect(originElement.nextElementSibling).toBe(overlayRef.hostElement); + }); + + it('should insert the overlay as a child of a custom element', () => { + if (!('showPopover' in document.body)) { + return; + } + + positionStrategy.withPopoverLocation({type: 'parent', element: customHostElement}); + attachOverlay({positionStrategy, usePopover: true}); + + expect(containerElement.contains(overlayRef.hostElement)).toBe(false); + expect(customHostElement.contains(overlayRef.hostElement)).toBe(true); + expect(overlayRef.hostElement.getAttribute('popover')).toBe('manual'); + }); + + it('should insert the overlay as a child of the origin', () => { + if (!('showPopover' in document.body)) { + return; + } + + positionStrategy.withPopoverLocation({type: 'parent', element: originElement}); + attachOverlay({positionStrategy, usePopover: true}); + + expect(containerElement.contains(overlayRef.hostElement)).toBe(false); + expect(originElement.contains(overlayRef.hostElement)).toBe(true); + expect(overlayRef.hostElement.getAttribute('popover')).toBe('manual'); + }); + }); }); /** Creates an absolutely positioned, display: block element with a default size. */ diff --git a/src/cdk/overlay/position/flexible-connected-position-strategy.ts b/src/cdk/overlay/position/flexible-connected-position-strategy.ts index fbc133659c0b..b31c87411b08 100644 --- a/src/cdk/overlay/position/flexible-connected-position-strategy.ts +++ b/src/cdk/overlay/position/flexible-connected-position-strategy.ts @@ -22,7 +22,7 @@ import {isElementScrolledOutsideView, isElementClippedByScrolling} from './scrol import {coerceCssPixelValue, coerceArray} from '../../coercion'; import {Platform} from '../../platform'; import {OverlayContainer} from '../overlay-container'; -import {OverlayRef} from '../overlay-ref'; +import {isElement, OverlayRef} from '../overlay-ref'; // TODO: refactor clipping detection into a separate thing (part of scrolling module) // TODO: doesn't handle both flexible width and height when it has to scroll along both axis. @@ -63,6 +63,12 @@ export function createFlexibleConnectedPositionStrategy( ); } +/** Supported locations in the DOM for connected overlays. */ +export type FlexibleOverlayPopoverLocation = + | 'global' + | 'inline' + | {type: 'parent'; element: Element}; + /** * A strategy for positioning overlays. Using this strategy, an overlay is given an * implicit position relative some origin element. The relative position is defined in terms of @@ -158,6 +164,9 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { /** Amount by which the overlay was pushed in each axis during the last time it was positioned. */ private _previousPushAmount: {x: number; y: number} | null; + /** Configures where in the DOM to insert the overlay when popovers are enabled. */ + private _popoverLocation: FlexibleOverlayPopoverLocation = 'global'; + /** Observable sequence of position changes. */ positionChanges: Observable = this._positionChanges; @@ -511,6 +520,36 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { return this; } + /** + * Determines where in the DOM the overlay will be rendered when popover mode is enabled. + * @param location Configures the location in the DOM. Supports the following values: + * - `global` - The default which inserts the overlay inside the overlay container. + * - `inline` - Inserts the overlay next to the trigger. + * - {type: 'parent', element: element} - Inserts the overlay to a child of a custom parent + * element. + */ + withPopoverLocation(location: FlexibleOverlayPopoverLocation): this { + this._popoverLocation = location; + return this; + } + + /** @docs-private */ + getPopoverInsertionPoint(): Element | null | {type: 'parent'; element: Element} { + if (this._popoverLocation === 'global') { + return null; + } else if (this._popoverLocation !== 'inline') { + return this._popoverLocation; + } + + if (this._origin instanceof ElementRef) { + return this._origin.nativeElement; + } else if (isElement(this._origin)) { + return this._origin; + } else { + return null; + } + } + /** * Gets the (x, y) coordinate of a connection point on the origin based on a relative position. */ @@ -889,18 +928,19 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { if (this._hasExactPosition()) { styles.top = styles.left = '0'; - styles.bottom = styles.right = styles.maxHeight = styles.maxWidth = ''; + styles.bottom = styles.right = 'auto'; + styles.maxHeight = styles.maxWidth = ''; styles.width = styles.height = '100%'; } else { const maxHeight = this._overlayRef.getConfig().maxHeight; const maxWidth = this._overlayRef.getConfig().maxWidth; - styles.height = coerceCssPixelValue(boundingBoxRect.height); - styles.top = coerceCssPixelValue(boundingBoxRect.top); - styles.bottom = coerceCssPixelValue(boundingBoxRect.bottom); styles.width = coerceCssPixelValue(boundingBoxRect.width); - styles.left = coerceCssPixelValue(boundingBoxRect.left); - styles.right = coerceCssPixelValue(boundingBoxRect.right); + styles.height = coerceCssPixelValue(boundingBoxRect.height); + styles.top = coerceCssPixelValue(boundingBoxRect.top) || 'auto'; + styles.bottom = coerceCssPixelValue(boundingBoxRect.bottom) || 'auto'; + styles.left = coerceCssPixelValue(boundingBoxRect.left) || 'auto'; + styles.right = coerceCssPixelValue(boundingBoxRect.right) || 'auto'; // Push the pane content towards the proper direction. if (position.overlayX === 'center') { diff --git a/src/cdk/overlay/position/global-position-strategy.spec.ts b/src/cdk/overlay/position/global-position-strategy.spec.ts index 7897d619beb2..9d83675b063f 100644 --- a/src/cdk/overlay/position/global-position-strategy.spec.ts +++ b/src/cdk/overlay/position/global-position-strategy.spec.ts @@ -12,6 +12,7 @@ import { describe('GlobalPositonStrategy', () => { let overlayRef: OverlayRef; let injector: Injector; + let portal: ComponentPortal; beforeEach(() => { injector = TestBed.inject(Injector); @@ -25,7 +26,7 @@ describe('GlobalPositonStrategy', () => { }); function attachOverlay(config: OverlayConfig): OverlayRef { - const portal = new ComponentPortal(BlankPortal); + portal = new ComponentPortal(BlankPortal); overlayRef = createOverlayRef(injector, config); overlayRef.attach(portal); TestBed.inject(ApplicationRef).tick(); diff --git a/src/cdk/overlay/position/global-position-strategy.ts b/src/cdk/overlay/position/global-position-strategy.ts index c174079b2b4a..2c0f11dabcc4 100644 --- a/src/cdk/overlay/position/global-position-strategy.ts +++ b/src/cdk/overlay/position/global-position-strategy.ts @@ -18,8 +18,6 @@ const wrapperClass = 'cdk-global-overlay-wrapper'; * @param injector Injector used to resolve dependencies for the strategy. */ export function createGlobalPositionStrategy(_injector: Injector): GlobalPositionStrategy { - // Note: `injector` is unused, but we may need it in - // the future which would introduce a breaking change. return new GlobalPositionStrategy(); } diff --git a/src/cdk/overlay/position/position-strategy.ts b/src/cdk/overlay/position/position-strategy.ts index 3138281fa66d..34c548d1da13 100644 --- a/src/cdk/overlay/position/position-strategy.ts +++ b/src/cdk/overlay/position/position-strategy.ts @@ -21,4 +21,10 @@ export interface PositionStrategy { /** Cleans up any DOM modifications made by the position strategy, if necessary. */ dispose(): void; + + /** + * Gets the element in the DOM after which to insert + * the overlay when it is rendered out as a popover. + */ + getPopoverInsertionPoint?(): Element | null | {type: 'parent'; element: Element}; } diff --git a/src/cdk/overlay/public-api.ts b/src/cdk/overlay/public-api.ts index 43a89dfdffea..95819b1ce4ea 100644 --- a/src/cdk/overlay/public-api.ts +++ b/src/cdk/overlay/public-api.ts @@ -11,9 +11,14 @@ export * from './position/connected-position'; export * from './scroll/index'; export * from './overlay-module'; export * from './dispatchers/index'; -export {Overlay, createOverlayRef} from './overlay'; +export {Overlay, createOverlayRef, OverlayDefaultConfig, OVERLAY_DEFAULT_CONFIG} from './overlay'; export {OverlayContainer} from './overlay-container'; -export {CdkOverlayOrigin, CdkConnectedOverlay} from './overlay-directives'; +export { + CdkOverlayOrigin, + CdkConnectedOverlay, + CdkConnectedOverlayConfig, + CDK_CONNECTED_OVERLAY_DEFAULT_CONFIG, +} from './overlay-directives'; export {FullscreenOverlayContainer} from './fullscreen-overlay-container'; export {OverlayRef, OverlaySizeConfig} from './overlay-ref'; export {ViewportRuler} from '../scrolling'; @@ -27,6 +32,7 @@ export { createGlobalPositionStrategy, } from './position/global-position-strategy'; export { + FlexibleOverlayPopoverLocation, ConnectedPosition, FlexibleConnectedPositionStrategy, FlexibleConnectedPositionStrategyOrigin, diff --git a/src/cdk/private/BUILD.bazel b/src/cdk/private/BUILD.bazel index 47ab5a1a5b2f..82598dc142ea 100644 --- a/src/cdk/private/BUILD.bazel +++ b/src/cdk/private/BUILD.bazel @@ -11,6 +11,7 @@ ng_project( assets = [":visually-hidden-styles"], deps = [ "//:node_modules/@angular/core", + "//:node_modules/@angular/platform-browser", ], ) diff --git a/src/cdk/private/inner-html.ts b/src/cdk/private/inner-html.ts new file mode 100644 index 000000000000..d7417e7daa94 --- /dev/null +++ b/src/cdk/private/inner-html.ts @@ -0,0 +1,26 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {SecurityContext} from '@angular/core'; +import {DomSanitizer, SafeHtml} from '@angular/platform-browser'; +import {trustedHTMLFromString} from './trusted-types'; + +// !!!Note!!! this file isn't synced into g3, but is replaced with a version that uses +// internal-specific APIs. The internal version may have to be updated if the signature of +// the function changes. + +/** Sanitizes and sets the `innerHTML` of an element. */ +export function _setInnerHtml(element: HTMLElement, html: SafeHtml, sanitizer: DomSanitizer): void { + const cleanHtml = sanitizer.sanitize(SecurityContext.HTML, html); + + if (cleanHtml === null && (typeof ngDevMode === 'undefined' || ngDevMode)) { + throw new Error(`Could not sanitize HTML: ${html}`); + } + + element.innerHTML = trustedHTMLFromString(cleanHtml || '') as unknown as string; +} diff --git a/src/cdk/private/public-api.ts b/src/cdk/private/public-api.ts index daa7b818d389..195f75b68f0c 100644 --- a/src/cdk/private/public-api.ts +++ b/src/cdk/private/public-api.ts @@ -8,3 +8,4 @@ export * from './style-loader'; export * from './visually-hidden/visually-hidden'; +export {TrustedHTML, trustedHTMLFromString} from './trusted-types'; diff --git a/src/material/icon/trusted-types.ts b/src/cdk/private/trusted-types.ts similarity index 75% rename from src/material/icon/trusted-types.ts rename to src/cdk/private/trusted-types.ts index 01f75fa2640b..febe9fa717f6 100644 --- a/src/material/icon/trusted-types.ts +++ b/src/cdk/private/trusted-types.ts @@ -6,21 +6,17 @@ * found in the LICENSE file at https://angular.dev/license */ -/** - * @fileoverview - * A module to facilitate use of a Trusted Types policy internally within - * Angular Material. It lazily constructs the Trusted Types policy, providing - * helper utilities for promoting strings to Trusted Types. When Trusted Types - * are not available, strings are used as a fallback. - * @security All use of this module is security-sensitive and should go through - * security review. - */ +// A module to facilitate use of a Trusted Types policy internally within +// Angular Material. It lazily constructs the Trusted Types policy, providing +// helper utilities for promoting strings to Trusted Types. When Trusted Types +// are not available, strings are used as a fallback. +// All use of this module is security-sensitive and should go through security review. -export declare interface TrustedHTML { +export interface TrustedHTML { __brand__: 'TrustedHTML'; } -export declare interface TrustedTypePolicyFactory { +interface TrustedTypePolicyFactory { createPolicy( policyName: string, policyOptions: { @@ -29,7 +25,7 @@ export declare interface TrustedTypePolicyFactory { ): TrustedTypePolicy; } -export declare interface TrustedTypePolicy { +interface TrustedTypePolicy { createHTML(input: string): TrustedHTML; } @@ -61,7 +57,8 @@ function getPolicy(): TrustedTypePolicy | null { /** * Unsafely promote a string to a TrustedHTML, falling back to strings when * Trusted Types are not available. - * @security This is a security-sensitive function; any use of this function + * + * Important!!! This is a security-sensitive function; any use of this function * must go through security review. In particular, it must be assured that the * provided string will never cause an XSS vulnerability if used in a context * that will be interpreted as HTML by a browser, e.g. when assigning to diff --git a/src/cdk/schematics/BUILD.bazel b/src/cdk/schematics/BUILD.bazel index f646e959fcec..9aa20e413dc6 100644 --- a/src/cdk/schematics/BUILD.bazel +++ b/src/cdk/schematics/BUILD.bazel @@ -93,6 +93,7 @@ ts_project( "//:node_modules/@schematics/angular", "//:node_modules/@types/jasmine", "//:node_modules/@types/node", + "//:node_modules/parse5", "//:node_modules/typescript", "//src/cdk/schematics/testing", "//src/cdk/schematics/update-tool", diff --git a/src/cdk/table/table-errors.ts b/src/cdk/table/table-errors.ts index 53c9be1c5b95..29681d52ce2c 100644 --- a/src/cdk/table/table-errors.ts +++ b/src/cdk/table/table-errors.ts @@ -30,7 +30,7 @@ export function getTableDuplicateColumnNameError(name: string) { export function getTableMultipleDefaultRowDefsError() { return Error( `There can only be one default row without a when predicate function. ` + - 'Or set `multiTemplateDataRows`.' + 'Or set `multiTemplateDataRows`.', ); } diff --git a/src/cdk/table/table.ts b/src/cdk/table/table.ts index c704690e1163..e431b58792cc 100644 --- a/src/cdk/table/table.ts +++ b/src/cdk/table/table.ts @@ -188,8 +188,7 @@ export class NoDataRowOutlet implements RowOutlet { * @docs-private */ export interface RowContext - extends CdkCellOutletMultiRowContext, - CdkCellOutletRowContext {} + extends CdkCellOutletMultiRowContext, CdkCellOutletRowContext {} /** * Class used to conveniently type the embedded view ref for rows with a context. diff --git a/src/cdk/testing/BUILD.bazel b/src/cdk/testing/BUILD.bazel index 4e8f56df7047..794c651cb5a0 100644 --- a/src/cdk/testing/BUILD.bazel +++ b/src/cdk/testing/BUILD.bazel @@ -1,6 +1,6 @@ +load("//src/cdk/testing/tests:webdriver-test.bzl", "webdriver_test") load("//src/e2e-app:test_suite.bzl", "e2e_test_suite") load("//tools:defaults.bzl", "markdown_to_html", "ng_web_test_suite", "ts_project") -load("//src/cdk/testing/tests:webdriver-test.bzl", "webdriver_test") load("//tools/adev-api-extraction:extract_api_to_json.bzl", "extract_api_to_json") package(default_visibility = ["//visibility:public"]) diff --git a/src/cdk/testing/testbed/fake-events/event-objects.ts b/src/cdk/testing/testbed/fake-events/event-objects.ts index 5674f1a77cf2..dd3cc6b62517 100644 --- a/src/cdk/testing/testbed/fake-events/event-objects.ts +++ b/src/cdk/testing/testbed/fake-events/event-objects.ts @@ -35,7 +35,7 @@ export function createMouseEvent( bubbles: true, cancelable: true, composed: true, // Required for shadow DOM events. - view: window, + view: getEventView(), detail: 1, relatedTarget: null, screenX, @@ -85,7 +85,7 @@ export function createPointerEvent( bubbles: true, cancelable: true, composed: true, // Required for shadow DOM events. - view: window, + view: getEventView(), clientX, clientY, ...options, @@ -139,7 +139,7 @@ export function createKeyboardEvent( bubbles: true, cancelable: true, composed: true, // Required for shadow DOM events. - view: window, + view: getEventView(), keyCode, key, shiftKey: modifiers.shift, @@ -165,3 +165,13 @@ export function createFakeEvent(type: string, bubbles = false, cancelable = true function defineReadonlyEventProperty(event: Event, propertyName: string, value: any) { Object.defineProperty(event, propertyName, {get: () => value, configurable: true}); } + +/** Gets the `view` that should be passed to synthetically-created DOM events */ +function getEventView(): Window | undefined { + // Passing `window` as the `view` on for events when the environment is using jsdom + // ends up throwing `member view is not of type Window` (see #32389). Leave it as + // `undefined` for such cases. + return typeof window !== 'undefined' && window && !(window as Window & {jsdom?: unknown}).jsdom + ? window + : undefined; +} diff --git a/src/cdk/testing/testbed/task-state-zone-interceptor.ts b/src/cdk/testing/testbed/task-state-zone-interceptor.ts index 1b91aaad34ca..91accb92016b 100644 --- a/src/cdk/testing/testbed/task-state-zone-interceptor.ts +++ b/src/cdk/testing/testbed/task-state-zone-interceptor.ts @@ -56,6 +56,13 @@ export class TaskStateZoneInterceptor { return {stable: !state.macroTask && !state.microTask}; } + static isInProxyZone(): boolean { + if (typeof Zone === 'undefined') { + return false; + } + return ((Zone as any)['ProxyZoneSpec'] as ProxyZoneStatic | undefined)?.get() !== undefined; + } + /** * Sets up the custom task state Zone interceptor in the `ProxyZone`. Throws if * no `ProxyZone` could be found. diff --git a/src/cdk/testing/testbed/testbed-harness-environment.ts b/src/cdk/testing/testbed/testbed-harness-environment.ts index 11805d6b0fe4..eab4dfc8bf5b 100644 --- a/src/cdk/testing/testbed/testbed-harness-environment.ts +++ b/src/cdk/testing/testbed/testbed-harness-environment.ts @@ -106,7 +106,7 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment { ) { super(rawRootElement); this._options = {...defaultEnvironmentOptions, ...options}; - if (typeof Zone !== 'undefined') { + if (TaskStateZoneInterceptor.isInProxyZone()) { this._taskState = TaskStateZoneInterceptor.setup(); } this._stabilizeCallback = () => this.forceStabilize(); @@ -178,6 +178,9 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment { /** * Waits for all scheduled or running async tasks to complete. This allows harness * authors to wait for async tasks outside of the Angular zone. + * + * This only works when Zone.js is present _and_ patches are applied to the test framework + * by `zone.js/testing` (Jasmine and Jest only) or another script. */ async waitForTasksOutsideAngular(): Promise { // If we run in the fake async zone, we run "flush" to run any scheduled tasks. This diff --git a/src/components-examples/aria/accordion/accordion-configurable/accordion-configurable-example.html b/src/components-examples/aria/accordion/accordion-configurable/accordion-configurable-example.html index 28b6ca833bae..212a917e6252 100644 --- a/src/components-examples/aria/accordion/accordion-configurable/accordion-configurable-example.html +++ b/src/components-examples/aria/accordion/accordion-configurable/accordion-configurable-example.html @@ -2,16 +2,7 @@ Wrap (ArrowKey-only) Multi Disabled - Skip Disabled - - - Expanded Items - - @for (item of items; track item) { - {{item}} - } - - + Soft Disabled

        -

        -
        +

        This is the content for Item 1.

        @@ -40,12 +30,12 @@

        -

        -
        +

        This is the content for Item 2.

        @@ -55,12 +45,12 @@

        -

        -
        +

        This is the content for Item 3.

        @@ -69,12 +59,12 @@

        -

        -
        +

        This is the content for Item 4

        @@ -83,12 +73,12 @@

        -

        -
        +

        This is the content for Item 5

        diff --git a/src/components-examples/aria/accordion/accordion-configurable/accordion-configurable-example.ts b/src/components-examples/aria/accordion/accordion-configurable/accordion-configurable-example.ts index 8f238c915eb8..039c82777309 100644 --- a/src/components-examples/aria/accordion/accordion-configurable/accordion-configurable-example.ts +++ b/src/components-examples/aria/accordion/accordion-configurable/accordion-configurable-example.ts @@ -1,4 +1,4 @@ -import {Component, computed, model, Signal} from '@angular/core'; +import {Component, computed, Signal, viewChildren} from '@angular/core'; import {FormControl, ReactiveFormsModule} from '@angular/forms'; import {MatCheckboxModule} from '@angular/material/checkbox'; import {MatFormFieldModule} from '@angular/material/form-field'; @@ -35,8 +35,14 @@ export class AccordionConfigurableExample { wrap = new FormControl(true, {nonNullable: true}); multi = new FormControl(true, {nonNullable: true}); disabled = new FormControl(false, {nonNullable: true}); - skipDisabled = new FormControl(true, {nonNullable: true}); - expandedIds = model(['item1']); + softDisabled = new FormControl(true, {nonNullable: true}); + + triggers = viewChildren(AccordionTrigger); + expandedIds = computed(() => + this.triggers() + .filter(t => t.expanded()) + .map(t => t.panelId()), + ); // Example items items = ['item1', 'item2', 'item3', 'item4', 'item5']; diff --git a/src/components-examples/aria/accordion/accordion-disabled-focusable/accordion-disabled-focusable-example.html b/src/components-examples/aria/accordion/accordion-disabled-focusable/accordion-disabled-focusable-example.html index cda513b3a334..abc529f832c8 100644 --- a/src/components-examples/aria/accordion/accordion-disabled-focusable/accordion-disabled-focusable-example.html +++ b/src/components-examples/aria/accordion/accordion-disabled-focusable/accordion-disabled-focusable-example.html @@ -2,17 +2,16 @@ ngAccordionGroup class="example-accordion-group" [multiExpandable]="true" - [skipDisabled]="false" - [(value)]="expandedIds" + [softDisabled]="true" >

        -

        -
        +

        This is the content for Item 1.

        @@ -21,12 +20,12 @@

        -

        -
        +

        This is the content for Item 2. This should not be expandable if trigger is disabled.

        @@ -35,12 +34,12 @@

        -

        -
        +

        This is the content for Item 3.

        @@ -49,12 +48,12 @@

        -

        -
        +

        This is the content for Item 4

        @@ -63,12 +62,12 @@

        -

        -
        +

        This is the content for Item 5

        diff --git a/src/components-examples/aria/accordion/accordion-disabled-focusable/accordion-disabled-focusable-example.ts b/src/components-examples/aria/accordion/accordion-disabled-focusable/accordion-disabled-focusable-example.ts index f695846b5237..2194152013e0 100644 --- a/src/components-examples/aria/accordion/accordion-disabled-focusable/accordion-disabled-focusable-example.ts +++ b/src/components-examples/aria/accordion/accordion-disabled-focusable/accordion-disabled-focusable-example.ts @@ -1,4 +1,4 @@ -import {Component, computed, model, Signal} from '@angular/core'; +import {Component, computed, Signal, viewChildren} from '@angular/core'; import {MatIconModule} from '@angular/material/icon'; import { AccordionGroup, @@ -15,7 +15,12 @@ import { imports: [MatIconModule, AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent], }) export class AccordionDisabledFocusableExample { - expandedIds = model([]); + triggers = viewChildren(AccordionTrigger); + expandedIds = computed(() => + this.triggers() + .filter(t => t.expanded()) + .map(t => t.panelId()), + ); expansionIcon(item: string): Signal { return computed(() => (this.expandedIds().includes(item) ? 'expand_less' : 'expand_more')); diff --git a/src/components-examples/aria/accordion/accordion-disabled-skipped/accordion-disabled-skipped-example.html b/src/components-examples/aria/accordion/accordion-disabled-skipped/accordion-disabled-skipped-example.html index 5ab83008e14d..3b4a6bdd8f0f 100644 --- a/src/components-examples/aria/accordion/accordion-disabled-skipped/accordion-disabled-skipped-example.html +++ b/src/components-examples/aria/accordion/accordion-disabled-skipped/accordion-disabled-skipped-example.html @@ -2,17 +2,16 @@ ngAccordionGroup class="example-accordion-group" [multiExpandable]="true" - [skipDisabled]="true" - [(value)]="expandedIds" + [softDisabled]="false" >

        -

        -
        +

        This is the content for Item 1.

        @@ -21,12 +20,12 @@

        -

        -
        +

        This is the content for Item 2. This should not be reachable or expandable.

        @@ -35,12 +34,12 @@

        -

        -
        +

        This is the content for Item 3.

        @@ -49,12 +48,12 @@

        -

        -
        +

        This is the content for Item 4

        @@ -63,12 +62,12 @@

        -

        -
        +

        This is the content for Item 5

        diff --git a/src/components-examples/aria/accordion/accordion-disabled-skipped/accordion-disabled-skipped-example.ts b/src/components-examples/aria/accordion/accordion-disabled-skipped/accordion-disabled-skipped-example.ts index 7eb682a25c9e..696db21568d1 100644 --- a/src/components-examples/aria/accordion/accordion-disabled-skipped/accordion-disabled-skipped-example.ts +++ b/src/components-examples/aria/accordion/accordion-disabled-skipped/accordion-disabled-skipped-example.ts @@ -1,4 +1,4 @@ -import {Component, computed, model, Signal} from '@angular/core'; +import {Component, computed, Signal, viewChildren} from '@angular/core'; import {MatIconModule} from '@angular/material/icon'; import { AccordionGroup, @@ -15,7 +15,12 @@ import { imports: [MatIconModule, AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent], }) export class AccordionDisabledSkippedExample { - expandedIds = model([]); + triggers = viewChildren(AccordionTrigger); + expandedIds = computed(() => + this.triggers() + .filter(t => t.expanded()) + .map(t => t.panelId()), + ); expansionIcon(item: string): Signal { return computed(() => (this.expandedIds().includes(item) ? 'expand_less' : 'expand_more')); diff --git a/src/components-examples/aria/accordion/accordion-disabled/accordion-disabled-example.html b/src/components-examples/aria/accordion/accordion-disabled/accordion-disabled-example.html index c77ba9d15824..572a4d5ca697 100644 --- a/src/components-examples/aria/accordion/accordion-disabled/accordion-disabled-example.html +++ b/src/components-examples/aria/accordion/accordion-disabled/accordion-disabled-example.html @@ -1,12 +1,12 @@ -
        +

        -

        -
        +

        This is the content for Item 1.

        @@ -16,12 +16,12 @@

        -

        -
        +

        This is the content for Item 2.

        @@ -31,12 +31,12 @@

        -

        -
        +

        This is the content for Item 3.

        @@ -45,12 +45,12 @@

        -

        -
        +

        This is the content for Item 4

        @@ -59,12 +59,12 @@

        -

        -
        +

        This is the content for Item 5

        diff --git a/src/components-examples/aria/accordion/accordion-disabled/accordion-disabled-example.ts b/src/components-examples/aria/accordion/accordion-disabled/accordion-disabled-example.ts index f00ed2704457..d668c9be4e43 100644 --- a/src/components-examples/aria/accordion/accordion-disabled/accordion-disabled-example.ts +++ b/src/components-examples/aria/accordion/accordion-disabled/accordion-disabled-example.ts @@ -1,4 +1,4 @@ -import {Component, computed, model, Signal} from '@angular/core'; +import {Component, computed, Signal, viewChildren} from '@angular/core'; import {MatIconModule} from '@angular/material/icon'; import { AccordionGroup, @@ -15,7 +15,12 @@ import { imports: [MatIconModule, AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent], }) export class AccordionDisabledExample { - expandedIds = model(['item1']); + triggers = viewChildren(AccordionTrigger); + expandedIds = computed(() => + this.triggers() + .filter(t => t.expanded()) + .map(t => t.panelId()), + ); expansionIcon(item: string): Signal { return computed(() => (this.expandedIds().includes(item) ? 'expand_less' : 'expand_more')); diff --git a/src/components-examples/aria/accordion/accordion-multi-expansion/accordion-multi-expansion-example.html b/src/components-examples/aria/accordion/accordion-multi-expansion/accordion-multi-expansion-example.html index fdcc50516d28..b657bce20ff5 100644 --- a/src/components-examples/aria/accordion/accordion-multi-expansion/accordion-multi-expansion-example.html +++ b/src/components-examples/aria/accordion/accordion-multi-expansion/accordion-multi-expansion-example.html @@ -2,16 +2,15 @@ ngAccordionGroup class="example-accordion-group" [multiExpandable]="true" - [(value)]="expandedIds" >

        -

        -
        +

        This is the content for Item 1. Multiple items can be expanded.

        @@ -21,12 +20,12 @@

        -

        -
        +

        This is the content for Item 2.

        @@ -36,14 +35,14 @@

        -

        @@ -54,14 +53,14 @@

        -

        @@ -72,14 +71,14 @@

        -

        diff --git a/src/components-examples/aria/accordion/accordion-multi-expansion/accordion-multi-expansion-example.ts b/src/components-examples/aria/accordion/accordion-multi-expansion/accordion-multi-expansion-example.ts index 910a4bef104c..41d0b82cde32 100644 --- a/src/components-examples/aria/accordion/accordion-multi-expansion/accordion-multi-expansion-example.ts +++ b/src/components-examples/aria/accordion/accordion-multi-expansion/accordion-multi-expansion-example.ts @@ -1,4 +1,4 @@ -import {Component, computed, model, Signal} from '@angular/core'; +import {Component, computed, Signal, viewChildren} from '@angular/core'; import {MatIconModule} from '@angular/material/icon'; import { AccordionGroup, @@ -15,7 +15,12 @@ import { imports: [MatIconModule, AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent], }) export class AccordionMultiExpansionExample { - expandedIds = model([]); + triggers = viewChildren(AccordionTrigger); + expandedIds = computed(() => + this.triggers() + .filter(t => t.expanded()) + .map(t => t.panelId()), + ); expansionIcon(item: string): Signal { return computed(() => (this.expandedIds().includes(item) ? 'expand_less' : 'expand_more')); diff --git a/src/components-examples/aria/accordion/accordion-single-expansion/accordion-single-expansion-example.html b/src/components-examples/aria/accordion/accordion-single-expansion/accordion-single-expansion-example.html index 0a29a42116f1..fca03e697d10 100644 --- a/src/components-examples/aria/accordion/accordion-single-expansion/accordion-single-expansion-example.html +++ b/src/components-examples/aria/accordion/accordion-single-expansion/accordion-single-expansion-example.html @@ -2,16 +2,15 @@ ngAccordionGroup class="example-accordion-group" [multiExpandable]="false" - [(value)]="expandedIds" >

        -

        -
        +

        This is the content for Item 1.

        @@ -21,12 +20,12 @@

        -

        -
        +

        This is the content for Item 2.

        @@ -36,14 +35,14 @@

        -

        @@ -54,14 +53,14 @@

        -

        @@ -72,14 +71,14 @@

        -

        diff --git a/src/components-examples/aria/accordion/accordion-single-expansion/accordion-single-expansion-example.ts b/src/components-examples/aria/accordion/accordion-single-expansion/accordion-single-expansion-example.ts index 7804ed8a4baf..a9558c406eb3 100644 --- a/src/components-examples/aria/accordion/accordion-single-expansion/accordion-single-expansion-example.ts +++ b/src/components-examples/aria/accordion/accordion-single-expansion/accordion-single-expansion-example.ts @@ -1,4 +1,4 @@ -import {Component, computed, model, Signal} from '@angular/core'; +import {Component, computed, Signal, viewChildren} from '@angular/core'; import {MatIconModule} from '@angular/material/icon'; import { AccordionGroup, @@ -15,7 +15,12 @@ import { imports: [MatIconModule, AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent], }) export class AccordionSingleExpansionExample { - expandedIds = model([]); + triggers = viewChildren(AccordionTrigger); + expandedIds = computed(() => + this.triggers() + .filter(t => t.expanded()) + .map(t => t.panelId()), + ); expansionIcon(item: string): Signal { return computed(() => (this.expandedIds().includes(item) ? 'expand_less' : 'expand_more')); diff --git a/src/components-examples/aria/accordion/cdk-accordion-configurable/cdk-accordion-configurable-example.html b/src/components-examples/aria/accordion/cdk-accordion-configurable/cdk-accordion-configurable-example.html index 8827996ad539..c2dcc08d4ca7 100644 --- a/src/components-examples/aria/accordion/cdk-accordion-configurable/cdk-accordion-configurable-example.html +++ b/src/components-examples/aria/accordion/cdk-accordion-configurable/cdk-accordion-configurable-example.html @@ -2,7 +2,7 @@ Wrap (ArrowKey-only) Multi Disabled - Skip Disabled + Soft Disabled Expanded Items @@ -19,18 +19,18 @@ class="example-accordion-group" [multiExpandable]="multi.value" [disabled]="disabled.value" - [skipDisabled]="skipDisabled.value" + [softDisabled]="softDisabled.value" [wrap]="wrap.value" - [(value)]="expandedIds" + [(expandedPanels)]="expandedIds" >

        -

        -
        +

        This is the content for Item 1.

        @@ -40,12 +40,12 @@

        -

        -
        +

        This is the content for Item 2.

        @@ -55,14 +55,14 @@

        -

        @@ -73,14 +73,14 @@

        -

        @@ -91,14 +91,14 @@

        -

        diff --git a/src/components-examples/aria/radio-group/BUILD.bazel b/src/components-examples/aria/autocomplete/BUILD.bazel similarity index 72% rename from src/components-examples/aria/radio-group/BUILD.bazel rename to src/components-examples/aria/autocomplete/BUILD.bazel index fa62632483d9..7b5c57c7ef81 100644 --- a/src/components-examples/aria/radio-group/BUILD.bazel +++ b/src/components-examples/aria/autocomplete/BUILD.bazel @@ -3,19 +3,19 @@ load("//tools:defaults.bzl", "ng_project") package(default_visibility = ["//visibility:public"]) ng_project( - name = "radio-group", + name = "autocomplete", srcs = glob(["**/*.ts"]), assets = glob([ "**/*.html", "**/*.css", ]), deps = [ + "//:node_modules/@angular/common", "//:node_modules/@angular/core", "//:node_modules/@angular/forms", - "//src/aria/radio-group", - "//src/material/checkbox", - "//src/material/form-field", - "//src/material/select", + "//src/aria/combobox", + "//src/aria/listbox", + "//src/cdk/overlay", ], ) diff --git a/src/components-examples/aria/autocomplete/autocomplete-auto-select/autocomplete-auto-select-example.html b/src/components-examples/aria/autocomplete/autocomplete-auto-select/autocomplete-auto-select-example.html new file mode 100644 index 000000000000..5d9fdbde2464 --- /dev/null +++ b/src/components-examples/aria/autocomplete/autocomplete-auto-select/autocomplete-auto-select-example.html @@ -0,0 +1,41 @@ +
        +
        + search + + +
        + + + +
        + @if (countries().length === 0) { +
        No results found
        + } + +
        + @for (country of countries(); track country) { +
        + {{country}} + check +
        + } +
        +
        +
        +
        +
        diff --git a/src/components-examples/aria/autocomplete/autocomplete-auto-select/autocomplete-auto-select-example.ts b/src/components-examples/aria/autocomplete/autocomplete-auto-select/autocomplete-auto-select-example.ts new file mode 100644 index 000000000000..2fcf8cf96214 --- /dev/null +++ b/src/components-examples/aria/autocomplete/autocomplete-auto-select/autocomplete-auto-select-example.ts @@ -0,0 +1,88 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + computed, + signal, + viewChild, + viewChildren, +} from '@angular/core'; +import {COUNTRIES} from '../countries'; +import {OverlayModule} from '@angular/cdk/overlay'; +import {FormsModule} from '@angular/forms'; + +/** @title Autocomplete with auto-select filtering. */ +@Component({ + selector: 'autocomplete-auto-select-example', + templateUrl: 'autocomplete-auto-select-example.html', + styleUrl: '../autocomplete.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + OverlayModule, + FormsModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AutocompleteAutoSelectExample { + /** The selected value of the combobox. */ + listbox = viewChild>(Listbox); + + /** The options available in the listbox. */ + options = viewChildren>(Option); + + /** A reference to the ng aria combobox. */ + combobox = viewChild>(Combobox); + + /** The query string used to filter the list of countries. */ + query = signal(''); + + /** The list of countries filtered by the query. */ + countries = computed(() => + COUNTRIES.filter(country => country.toLowerCase().startsWith(this.query().toLowerCase())), + ); + + constructor() { + // Scrolls to the active item when the active option changes. + afterRenderEffect(() => { + if (this.combobox()?.expanded()) { + const option = this.options().find(opt => opt.active()); + option?.element.scrollIntoView({block: 'nearest'}); + } + }); + } + + /** Clears the query and the listbox value. */ + clear(): void { + this.query.set(''); + this.listbox?.()?.values.set([]); + } + + /** Handles keydown events on the clear button. */ + onKeydown(event: KeyboardEvent): void { + if (event.key === 'Enter') { + this.clear(); + this.combobox?.()?.close(); + event.stopPropagation(); + } + } +} diff --git a/src/components-examples/aria/autocomplete/autocomplete-disabled/autocomplete-disabled-example.html b/src/components-examples/aria/autocomplete/autocomplete-disabled/autocomplete-disabled-example.html new file mode 100644 index 000000000000..2fb1aed3365c --- /dev/null +++ b/src/components-examples/aria/autocomplete/autocomplete-disabled/autocomplete-disabled-example.html @@ -0,0 +1,33 @@ +
        +
        + search + +
        + + + +
        + @if (countries().length === 0) { +
        No results found
        + } + +
        + @for (country of countries(); track country) { +
        + {{country}} + check +
        + } +
        +
        +
        +
        +
        diff --git a/src/components-examples/aria/autocomplete/autocomplete-disabled/autocomplete-disabled-example.ts b/src/components-examples/aria/autocomplete/autocomplete-disabled/autocomplete-disabled-example.ts new file mode 100644 index 000000000000..ed590c7f3411 --- /dev/null +++ b/src/components-examples/aria/autocomplete/autocomplete-disabled/autocomplete-disabled-example.ts @@ -0,0 +1,70 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + computed, + signal, + viewChild, + viewChildren, +} from '@angular/core'; +import {COUNTRIES} from '../countries'; +import {OverlayModule} from '@angular/cdk/overlay'; +import {FormsModule} from '@angular/forms'; + +/** @title Disabled autocomplete. */ +@Component({ + selector: 'autocomplete-disabled-example', + templateUrl: 'autocomplete-disabled-example.html', + styleUrl: '../autocomplete.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + OverlayModule, + FormsModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AutocompleteDisabledExample { + /** The options available in the listbox. */ + options = viewChildren>(Option); + + /** A reference to the ng aria combobox. */ + combobox = viewChild>(Combobox); + + /** The query string used to filter the list of countries. */ + query = signal('United States of America'); + + /** The list of countries filtered by the query. */ + countries = computed(() => + COUNTRIES.filter(country => country.toLowerCase().startsWith(this.query().toLowerCase())), + ); + + constructor() { + // Scrolls to the active item when the active option changes. + afterRenderEffect(() => { + if (this.combobox()?.expanded()) { + const option = this.options().find(opt => opt.active()); + option?.element.scrollIntoView({block: 'nearest'}); + } + }); + } +} diff --git a/src/components-examples/aria/autocomplete/autocomplete-highlight/autocomplete-highlight-example.html b/src/components-examples/aria/autocomplete/autocomplete-highlight/autocomplete-highlight-example.html new file mode 100644 index 000000000000..8a546dedfbc6 --- /dev/null +++ b/src/components-examples/aria/autocomplete/autocomplete-highlight/autocomplete-highlight-example.html @@ -0,0 +1,41 @@ +
        +
        + search + + +
        + + + +
        + @if (countries().length === 0) { +
        No results found
        + } + +
        + @for (country of countries(); track country) { +
        + {{country}} + check +
        + } +
        +
        +
        +
        +
        diff --git a/src/components-examples/aria/autocomplete/autocomplete-highlight/autocomplete-highlight-example.ts b/src/components-examples/aria/autocomplete/autocomplete-highlight/autocomplete-highlight-example.ts new file mode 100644 index 000000000000..6c2423e751ff --- /dev/null +++ b/src/components-examples/aria/autocomplete/autocomplete-highlight/autocomplete-highlight-example.ts @@ -0,0 +1,88 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + computed, + signal, + viewChild, + viewChildren, +} from '@angular/core'; +import {COUNTRIES} from '../countries'; +import {OverlayModule} from '@angular/cdk/overlay'; +import {FormsModule} from '@angular/forms'; + +/** @title Autocomplete with highlighted filtering. */ +@Component({ + selector: 'autocomplete-highlight-example', + templateUrl: 'autocomplete-highlight-example.html', + styleUrl: '../autocomplete.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + OverlayModule, + FormsModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AutocompleteHighlightExample { + /** The selected value of the combobox. */ + listbox = viewChild>(Listbox); + + /** The options available in the listbox. */ + options = viewChildren>(Option); + + /** A reference to the ng aria combobox. */ + combobox = viewChild>(Combobox); + + /** The query string used to filter the list of countries. */ + query = signal(''); + + /** The list of countries filtered by the query. */ + countries = computed(() => + COUNTRIES.filter(country => country.toLowerCase().startsWith(this.query().toLowerCase())), + ); + + constructor() { + // Scrolls to the active item when the active option changes. + afterRenderEffect(() => { + if (this.combobox()?.expanded()) { + const option = this.options().find(opt => opt.active()); + option?.element.scrollIntoView({block: 'nearest'}); + } + }); + } + + /** Clears the query and the listbox value. */ + clear(): void { + this.query.set(''); + this.listbox?.()?.values.set([]); + } + + /** Handles keydown events on the clear button. */ + onKeydown(event: KeyboardEvent): void { + if (event.key === 'Enter') { + this.clear(); + this.combobox?.()?.close(); + event.stopPropagation(); + } + } +} diff --git a/src/components-examples/aria/autocomplete/autocomplete-manual/autocomplete-manual-example.html b/src/components-examples/aria/autocomplete/autocomplete-manual/autocomplete-manual-example.html new file mode 100644 index 000000000000..a7aa84d01760 --- /dev/null +++ b/src/components-examples/aria/autocomplete/autocomplete-manual/autocomplete-manual-example.html @@ -0,0 +1,41 @@ +
        +
        + search + + +
        + + + +
        + @if (countries().length === 0) { +
        No results found
        + } + +
        + @for (country of countries(); track country) { +
        + {{country}} + check +
        + } +
        +
        +
        +
        +
        diff --git a/src/components-examples/aria/autocomplete/autocomplete-manual/autocomplete-manual-example.ts b/src/components-examples/aria/autocomplete/autocomplete-manual/autocomplete-manual-example.ts new file mode 100644 index 000000000000..a37dea64f2e8 --- /dev/null +++ b/src/components-examples/aria/autocomplete/autocomplete-manual/autocomplete-manual-example.ts @@ -0,0 +1,88 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + computed, + signal, + viewChild, + viewChildren, +} from '@angular/core'; +import {COUNTRIES} from '../countries'; +import {OverlayModule} from '@angular/cdk/overlay'; +import {FormsModule} from '@angular/forms'; + +/** @title Autocomplete with manual filtering. */ +@Component({ + selector: 'autocomplete-manual-example', + templateUrl: 'autocomplete-manual-example.html', + styleUrl: '../autocomplete.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + OverlayModule, + FormsModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AutocompleteManualExample { + /** The selected value of the combobox. */ + listbox = viewChild>(Listbox); + + /** The options available in the listbox. */ + options = viewChildren>(Option); + + /** A reference to the ng aria combobox. */ + combobox = viewChild>(Combobox); + + /** The query string used to filter the list of countries. */ + query = signal(''); + + /** The list of countries filtered by the query. */ + countries = computed(() => + COUNTRIES.filter(country => country.toLowerCase().startsWith(this.query().toLowerCase())), + ); + + constructor() { + // Scrolls to the active item when the active option changes. + afterRenderEffect(() => { + if (this.combobox()?.expanded()) { + const option = this.options().find(opt => opt.active()); + option?.element.scrollIntoView({block: 'nearest'}); + } + }); + } + + /** Clears the query and the listbox value. */ + clear(): void { + this.query.set(''); + this.listbox?.()?.values.set([]); + } + + /** Handles keydown events on the clear button. */ + onKeydown(event: KeyboardEvent): void { + if (event.key === 'Enter') { + this.clear(); + this.combobox?.()?.close(); + event.stopPropagation(); + } + } +} diff --git a/src/components-examples/aria/autocomplete/autocomplete.css b/src/components-examples/aria/autocomplete/autocomplete.css new file mode 100644 index 000000000000..2c77dbb51211 --- /dev/null +++ b/src/components-examples/aria/autocomplete/autocomplete.css @@ -0,0 +1,119 @@ +.example-autocomplete { + display: flex; + position: relative; + align-items: center; + + /* stylelint-disable-next-line material/no-prefixes -- Valid in all remotely recent browsers. */ + width: fit-content; +} + +.example-search-icon, +.example-check-icon { + font-size: 1.25rem; + pointer-events: none; +} + +.example-search-icon { + left: 0.75rem; + position: absolute; +} + +[ngComboboxInput] { + width: 13rem; + font-size: 0.9rem; + border-radius: var(--mat-sys-corner-extra-small); + padding: 0.7rem 2.5rem; + outline-color: var(--mat-sys-primary); + border: 1px solid var(--mat-sys-outline); + background-color: var(--mat-sys-surface); +} + +[ngComboboxInput][aria-disabled='true'] { + cursor: default; + opacity: 0.5; + background-color: var(--mat-sys-surface-dim); +} + +[ngCombobox]:has([aria-expanded='false']) .example-popup { + display: none; +} + +.example-clear-button { + position: absolute; + right: 0.5rem; + background-color: transparent; + border: none; + display: flex; + width: 2rem; + height: 2rem; + align-items: center; + cursor: pointer; +} + +.example-clear-icon { + font-size: 1.25rem; +} + +.example-popup { + width: 100%; + margin-top: 2px; + padding: 0.1rem; + max-height: 11rem; + border-radius: var(--mat-sys-corner-extra-small); + background-color: var(--mat-sys-surface); + border: 1px solid var(--mat-sys-outline); +} + +.example-no-results { + padding: 1rem; +} + +[ngListbox] { + gap: 2px; + height: 100%; + display: flex; + overflow: auto; + flex-direction: column; +} + +[ngOption] { + display: flex; + cursor: pointer; + align-items: center; + margin: 1px; + font-size: 0.9rem; + padding: 0.7rem; + border-radius: var(--mat-sys-corner-extra-small); +} + +[ngOption][aria-disabled='true'] { + cursor: default; + opacity: 0.5; + background-color: var(--mat-sys-surface-dim); +} + +[ngOption]:hover { + background-color: color-mix(in srgb, var(--mat-sys-primary) 5%, transparent); +} + +[ngOption][data-active='true'] { + outline-offset: -2px; + outline: 2px solid var(--mat-sys-primary); +} + +[ngOption][aria-selected='true'] { + color: var(--mat-sys-primary); + background-color: color-mix(in srgb, var(--mat-sys-primary) 10%, transparent); +} + +[ngOption]:not([aria-selected='true']) .example-check-icon { + display: none; +} + +.example-option-label { + flex: 1; +} + +.example-check-icon { + font-size: 0.9rem; +} diff --git a/src/components-examples/aria/autocomplete/countries.ts b/src/components-examples/aria/autocomplete/countries.ts new file mode 100644 index 000000000000..3d9c4ba4f079 --- /dev/null +++ b/src/components-examples/aria/autocomplete/countries.ts @@ -0,0 +1,197 @@ +export const COUNTRIES = [ + 'Afghanistan', + 'Albania', + 'Algeria', + 'Andorra', + 'Angola', + 'Antigua and Barbuda', + 'Argentina', + 'Armenia', + 'Australia', + 'Austria', + 'Azerbaijan', + 'Bahamas', + 'Bahrain', + 'Bangladesh', + 'Barbados', + 'Belarus', + 'Belgium', + 'Belize', + 'Benin', + 'Bhutan', + 'Bolivia', + 'Bosnia and Herzegovina', + 'Botswana', + 'Brazil', + 'Brunei', + 'Bulgaria', + 'Burkina Faso', + 'Burundi', + 'Cabo Verde', + 'Cambodia', + 'Cameroon', + 'Canada', + 'Central African Republic', + 'Chad', + 'Chile', + 'China', + 'Colombia', + 'Comoros', + 'Congo (Congo-Brazzaville)', + 'Costa Rica', + "Côte d'Ivoire", + 'Croatia', + 'Cuba', + 'Cyprus', + 'Czechia (Czech Republic)', + 'Democratic Republic of the Congo', + 'Denmark', + 'Djibouti', + 'Dominica', + 'Dominican Republic', + 'Ecuador', + 'Egypt', + 'El Salvador', + 'Equatorial Guinea', + 'Eritrea', + 'Estonia', + 'Eswatini (fmr. ""Swaziland"")', + 'Ethiopia', + 'Fiji', + 'Finland', + 'France', + 'Gabon', + 'Gambia', + 'Georgia', + 'Germany', + 'Ghana', + 'Greece', + 'Grenada', + 'Guatemala', + 'Guinea', + 'Guinea-Bissau', + 'Guyana', + 'Haiti', + 'Holy See', + 'Honduras', + 'Hungary', + 'Iceland', + 'India', + 'Indonesia', + 'Iran', + 'Iraq', + 'Ireland', + 'Israel', + 'Italy', + 'Jamaica', + 'Japan', + 'Jordan', + 'Kazakhstan', + 'Kenya', + 'Kiribati', + 'Kuwait', + 'Kyrgyzstan', + 'Laos', + 'Latvia', + 'Lebanon', + 'Lesotho', + 'Liberia', + 'Libya', + 'Liechtenstein', + 'Lithuania', + 'Luxembourg', + 'Madagascar', + 'Malawi', + 'Malaysia', + 'Maldives', + 'Mali', + 'Malta', + 'Marshall Islands', + 'Mauritania', + 'Mauritius', + 'Mexico', + 'Micronesia', + 'Moldova', + 'Monaco', + 'Mongolia', + 'Montenegro', + 'Morocco', + 'Mozambique', + 'Myanmar (formerly Burma)', + 'Namibia', + 'Nauru', + 'Nepal', + 'Netherlands', + 'New Zealand', + 'Nicaragua', + 'Niger', + 'Nigeria', + 'North Korea', + 'North Macedonia', + 'Norway', + 'Oman', + 'Pakistan', + 'Palau', + 'Palestine State', + 'Panama', + 'Papua New Guinea', + 'Paraguay', + 'Peru', + 'Philippines', + 'Poland', + 'Portugal', + 'Qatar', + 'Romania', + 'Russia', + 'Rwanda', + 'Saint Kitts and Nevis', + 'Saint Lucia', + 'Saint Vincent and the Grenadines', + 'Samoa', + 'San Marino', + 'Sao Tome and Principe', + 'Saudi Arabia', + 'Senegal', + 'Serbia', + 'Seychelles', + 'Sierra Leone', + 'Singapore', + 'Slovakia', + 'Slovenia', + 'Solomon Islands', + 'Somalia', + 'South Africa', + 'South Korea', + 'South Sudan', + 'Spain', + 'Sri Lanka', + 'Sudan', + 'Suriname', + 'Sweden', + 'Switzerland', + 'Syria', + 'Tajikistan', + 'Tanzania', + 'Thailand', + 'Timor-Leste', + 'Togo', + 'Tonga', + 'Trinidad and Tobago', + 'Tunisia', + 'Turkey', + 'Turkmenistan', + 'Tuvalu', + 'Uganda', + 'Ukraine', + 'United Arab Emirates', + 'United Kingdom', + 'United States of America', + 'Uruguay', + 'Uzbekistan', + 'Vanuatu', + 'Venezuela', + 'Vietnam', + 'Yemen', + 'Zambia', + 'Zimbabwe', +]; diff --git a/src/components-examples/aria/autocomplete/index.ts b/src/components-examples/aria/autocomplete/index.ts new file mode 100644 index 000000000000..15cb925c5e28 --- /dev/null +++ b/src/components-examples/aria/autocomplete/index.ts @@ -0,0 +1,4 @@ +export {AutocompleteAutoSelectExample} from './autocomplete-auto-select/autocomplete-auto-select-example'; +export {AutocompleteManualExample} from './autocomplete-manual/autocomplete-manual-example'; +export {AutocompleteHighlightExample} from './autocomplete-highlight/autocomplete-highlight-example'; +export {AutocompleteDisabledExample} from './autocomplete-disabled/autocomplete-disabled-example'; diff --git a/src/components-examples/aria/combobox/BUILD.bazel b/src/components-examples/aria/combobox/BUILD.bazel index 6d08b7469803..7eebc8fcaf3a 100644 --- a/src/components-examples/aria/combobox/BUILD.bazel +++ b/src/components-examples/aria/combobox/BUILD.bazel @@ -16,6 +16,7 @@ ng_project( "//src/aria/combobox", "//src/aria/listbox", "//src/aria/tree", + "//src/cdk/overlay", ], ) diff --git a/src/components-examples/aria/combobox/combobox-auto-select/combobox-auto-select-example.ts b/src/components-examples/aria/combobox/combobox-auto-select/combobox-auto-select-example.ts index a2cb39aef496..5393e0af1fd3 100644 --- a/src/components-examples/aria/combobox/combobox-auto-select/combobox-auto-select-example.ts +++ b/src/components-examples/aria/combobox/combobox-auto-select/combobox-auto-select-example.ts @@ -46,10 +46,8 @@ export class ComboboxAutoSelectExample { afterRenderEffect(() => { const popover = this.popover()!; const combobox = this.combobox()!; - combobox.pattern.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); - - // TODO(wagnermaciel): Make this easier for developers to do. - this.listbox()?.pattern.inputs.activeItem()?.element().scrollIntoView({block: 'nearest'}); + combobox.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); + this.listbox()?.scrollActiveItemIntoView(); }); } @@ -57,12 +55,12 @@ export class ComboboxAutoSelectExample { const popover = this.popover()!; const combobox = this.combobox()!; - const comboboxRect = combobox.pattern.inputs.inputEl()?.getBoundingClientRect(); + const comboboxRect = combobox.inputElement()?.getBoundingClientRect(); const popoverEl = popover.nativeElement; if (comboboxRect) { popoverEl.style.width = `${comboboxRect.width}px`; - popoverEl.style.top = `${comboboxRect.bottom}px`; + popoverEl.style.top = `${comboboxRect.bottom + 4}px`; popoverEl.style.left = `${comboboxRect.left - 1}px`; } diff --git a/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.css b/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.css new file mode 100644 index 000000000000..68d4cf47c377 --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.css @@ -0,0 +1,222 @@ +.example-combobox-container { + position: relative; + width: 100%; + display: flex; + flex-direction: column; + border: 1px solid var(--mat-sys-outline); + border-radius: var(--mat-sys-corner-extra-small); +} + +.example-combobox-container:has([readonly='true']) { + width: 225px; +} + +.example-combobox-input-container { + display: flex; + position: relative; + align-items: center; + border-radius: var(--mat-sys-corner-extra-small); +} + +.example-combobox-input { + border-radius: var(--mat-sys-corner-extra-small); +} + +.example-combobox-input[readonly='true'] { + cursor: pointer; + padding: 0.7rem 1rem; +} + +.example-combobox-container:focus-within .example-combobox-input { + outline: 1.5px solid var(--mat-sys-primary); + box-shadow: 0 0 0 4px color-mix(in srgb, var(--mat-sys-primary) 25%, transparent); +} + +.example-icon { + width: 24px; + height: 24px; + font-size: 20px; + display: grid; + place-items: center; + pointer-events: none; +} + +.example-search-icon { + padding: 0 0.5rem; + position: absolute; + opacity: 0.8; +} + +.example-arrow-icon { + padding: 0 0.5rem; + position: absolute; + right: 0; + opacity: 0.8; + transition: transform 0.2s ease; +} + +.example-combobox-input[aria-expanded='true'] + .example-arrow-icon { + transform: rotate(180deg); +} + +.example-combobox-input { + width: 100%; + border: none; + outline: none; + font-size: 1rem; + padding: 0.7rem 1rem 0.7rem 2.5rem; + background-color: var(--mat-sys-surface); +} + +.example-popover { + margin: 0; + padding: 0; + border: 1px solid var(--mat-sys-outline); + border-radius: var(--mat-sys-corner-extra-small); + background-color: var(--mat-sys-surface); +} + +.example-listbox { + display: flex; + flex-direction: column; + overflow: auto; + max-height: 10rem; + padding: 0.5rem; + gap: 4px; +} + +.example-option { + cursor: pointer; + padding: 0.3rem 1rem; + border-radius: var(--mat-sys-corner-extra-small); + display: flex; + overflow: hidden; + flex-shrink: 0; + align-items: center; + justify-content: space-between; + gap: 1rem; +} + +.example-option-text { + flex: 1; +} + +.example-checkbox-blank-icon, +.example-option[aria-selected='true'] .example-checkbox-filled-icon { + display: flex; + align-items: center; +} + +.example-checkbox-filled-icon, +.example-option[aria-selected='true'] .example-checkbox-blank-icon { + display: none; +} + +.example-checkbox-blank-icon { + opacity: 0.6; +} + +.example-selected-icon { + visibility: hidden; +} + +.example-option[aria-selected='true'] .example-selected-icon { + visibility: visible; +} + +.example-option[aria-selected='true'] { + color: var(--mat-sys-primary); + background-color: color-mix(in srgb, var(--mat-sys-primary) 10%, transparent); +} + +.example-option:hover { + background-color: color-mix(in srgb, var(--mat-sys-on-surface) 10%, transparent); +} + +.example-combobox-container:focus-within [data-active='true'] { + outline: 2px solid color-mix(in srgb, var(--mat-sys-primary) 80%, transparent); +} + +.example-tree { + padding: 10px; + overflow-x: scroll; +} + +.example-tree-item { + cursor: pointer; + list-style: none; + text-decoration: none; + display: flex; + align-items: center; + gap: 1rem; + padding: 0.3rem 1rem; +} + +li[aria-expanded='false'] + ul[role='group'] { + display: none; +} + +ul[role='group'] { + padding-inline-start: 1rem; +} + +.example-icon { + margin: 0; + width: 24px; +} + +.example-parent-icon { + transition: transform 0.2s ease; +} + +.example-tree-item[aria-expanded='true'] .example-parent-icon { + transform: rotate(90deg); +} + +.example-selected-icon { + visibility: hidden; + margin-left: auto; +} + +.example-tree-item[aria-current] .example-selected-icon, +.example-tree-item[aria-selected='true'] .example-selected-icon { + visibility: visible; +} + +.example-dialog { + position: absolute; + left: auto; + right: auto; + top: auto; + bottom: auto; + padding: 0; + border: 1px solid var(--mat-sys-outline); + border-radius: var(--mat-sys-corner-extra-small); +} + +.example-dialog .example-combobox-input-container { + border-radius: 0; +} + +.example-dialog .example-combobox-container, +.example-dialog .example-combobox-input-container { + border: none; +} + +.example-dialog .example-combobox-input { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.example-dialog .example-combobox-container:focus-within .example-combobox-input { + outline: none; + box-shadow: none; +} + +.example-dialog .example-combobox-input-container { + border-bottom: 1px solid var(--mat-sys-outline); +} + +.example-dialog::backdrop { + opacity: 0; +} diff --git a/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.html b/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.html new file mode 100644 index 000000000000..67eae7296522 --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.html @@ -0,0 +1,49 @@ +
        +
        + + arrow_drop_down +
        + + + +
        + +
        + search + +
        + + +
        + @for (option of options(); track option) { +
        + {{option}} + +
        + } +
        +
        +
        +
        +
        +
        diff --git a/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.ts b/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.ts new file mode 100644 index 000000000000..fc0de32bcc93 --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-dialog/combobox-dialog-example.ts @@ -0,0 +1,145 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxDialog, + ComboboxInput, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + computed, + signal, + untracked, + viewChild, +} from '@angular/core'; +import {FormsModule} from '@angular/forms'; + +/** @title Combobox with a dialog popup. */ +@Component({ + selector: 'combobox-dialog-example', + templateUrl: 'combobox-dialog-example.html', + styleUrl: 'combobox-dialog-example.css', + imports: [ + ComboboxDialog, + Combobox, + ComboboxInput, + ComboboxPopupContainer, + Listbox, + Option, + FormsModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ComboboxDialogExample { + dialog = viewChild(ComboboxDialog); + listbox = viewChild>(Listbox); + combobox = viewChild>(Combobox); + + value = signal(''); + searchString = signal(''); + + options = computed(() => + states.filter(state => state.toLowerCase().startsWith(this.searchString().toLowerCase())), + ); + + selectedStates = signal([]); + + constructor() { + afterRenderEffect(() => { + if (this.dialog() && this.combobox()?.expanded()) { + untracked(() => this.listbox()?.gotoFirst()); + this.positionDialog(); + } + }); + + afterRenderEffect(() => { + if (this.selectedStates().length > 0) { + untracked(() => this.dialog()?.close()); + this.value.set(this.selectedStates()[0]); + this.searchString.set(''); + } + }); + + afterRenderEffect(() => this.listbox()?.scrollActiveItemIntoView()); + } + + // TODO(wagnermaciel): Switch to using the CDK for positioning. + + positionDialog() { + const dialog = this.dialog()!; + const combobox = this.combobox()!; + + const comboboxRect = combobox.inputElement()?.getBoundingClientRect(); + + const scrollY = window.scrollY; + + if (comboboxRect) { + dialog.element.style.width = `${comboboxRect.width}px`; + dialog.element.style.top = `${comboboxRect.bottom + scrollY + 4}px`; + dialog.element.style.left = `${comboboxRect.left - 1}px`; + } + } +} + +const states = [ + 'Alabama', + 'Alaska', + 'Arizona', + 'Arkansas', + 'California', + 'Colorado', + 'Connecticut', + 'Delaware', + 'Florida', + 'Georgia', + 'Hawaii', + 'Idaho', + 'Illinois', + 'Indiana', + 'Iowa', + 'Kansas', + 'Kentucky', + 'Louisiana', + 'Maine', + 'Maryland', + 'Massachusetts', + 'Michigan', + 'Minnesota', + 'Mississippi', + 'Missouri', + 'Montana', + 'Nebraska', + 'Nevada', + 'New Hampshire', + 'New Jersey', + 'New Mexico', + 'New York', + 'North Carolina', + 'North Dakota', + 'Ohio', + 'Oklahoma', + 'Oregon', + 'Pennsylvania', + 'Rhode Island', + 'South Carolina', + 'South Dakota', + 'Tennessee', + 'Texas', + 'Utah', + 'Vermont', + 'Virginia', + 'Washington', + 'West Virginia', + 'Wisconsin', + 'Wyoming', +]; diff --git a/src/components-examples/aria/combobox/combobox-disabled/combobox-disabled-example.html b/src/components-examples/aria/combobox/combobox-disabled/combobox-disabled-example.html new file mode 100644 index 000000000000..a791c1d1f5b4 --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-disabled/combobox-disabled-example.html @@ -0,0 +1,33 @@ +
        +
        + search + +
        + +
        + +
        + @for (option of options(); track option) { +
        + {{option}} + +
        + } +
        +
        +
        +
        diff --git a/src/components-examples/aria/combobox/combobox-disabled/combobox-disabled-example.ts b/src/components-examples/aria/combobox/combobox-disabled/combobox-disabled-example.ts new file mode 100644 index 000000000000..bf8e2808fd40 --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-disabled/combobox-disabled-example.ts @@ -0,0 +1,132 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + computed, + ElementRef, + signal, + viewChild, +} from '@angular/core'; +import {FormsModule} from '@angular/forms'; + +/** @title Disabled combobox example. */ +@Component({ + selector: 'combobox-disabled-example', + templateUrl: 'combobox-disabled-example.html', + styleUrl: '../combobox-examples.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + FormsModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ComboboxDisabledExample { + popover = viewChild('popover'); + listbox = viewChild>(Listbox); + combobox = viewChild>(Combobox); + + searchString = signal(''); + + options = computed(() => + states.filter(state => state.toLowerCase().startsWith(this.searchString().toLowerCase())), + ); + + constructor() { + afterRenderEffect(() => { + const popover = this.popover()!; + const combobox = this.combobox()!; + combobox.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); + + this.listbox()?.scrollActiveItemIntoView(); + }); + } + + showPopover() { + const popover = this.popover()!; + const combobox = this.combobox()!; + + const comboboxRect = combobox.inputElement()?.getBoundingClientRect(); + const popoverEl = popover.nativeElement; + + if (comboboxRect) { + popoverEl.style.width = `${comboboxRect.width}px`; + popoverEl.style.top = `${comboboxRect.bottom + 4}px`; + popoverEl.style.left = `${comboboxRect.left - 1}px`; + } + + popover.nativeElement.showPopover(); + } +} + +const states = [ + 'Alabama', + 'Alaska', + 'Arizona', + 'Arkansas', + 'California', + 'Colorado', + 'Connecticut', + 'Delaware', + 'Florida', + 'Georgia', + 'Hawaii', + 'Idaho', + 'Illinois', + 'Indiana', + 'Iowa', + 'Kansas', + 'Kentucky', + 'Louisiana', + 'Maine', + 'Maryland', + 'Massachusetts', + 'Michigan', + 'Minnesota', + 'Mississippi', + 'Missouri', + 'Montana', + 'Nebraska', + 'Nevada', + 'New Hampshire', + 'New Jersey', + 'New Mexico', + 'New York', + 'North Carolina', + 'North Dakota', + 'Ohio', + 'Oklahoma', + 'Oregon', + 'Pennsylvania', + 'Rhode Island', + 'South Carolina', + 'South Dakota', + 'Tennessee', + 'Texas', + 'Utah', + 'Vermont', + 'Virginia', + 'Washington', + 'West Virginia', + 'Wisconsin', + 'Wyoming', +]; diff --git a/src/components-examples/aria/combobox/combobox-examples.css b/src/components-examples/aria/combobox/combobox-examples.css index 54e96b72490d..266f47980eb6 100644 --- a/src/components-examples/aria/combobox/combobox-examples.css +++ b/src/components-examples/aria/combobox/combobox-examples.css @@ -1,23 +1,35 @@ .example-combobox-container { position: relative; - width: 300px; + width: 100%; display: flex; - overflow: hidden; flex-direction: column; border: 1px solid var(--mat-sys-outline); border-radius: var(--mat-sys-corner-extra-small); } -.example-combobox-container:has(.example-combobox-input[aria-expanded='true']) { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; +.example-combobox-container:has([readonly='true']:not([aria-disabled='true'])) { + width: 200px; } .example-combobox-input-container { display: flex; - overflow: hidden; position: relative; align-items: center; + border-radius: var(--mat-sys-corner-extra-small); +} + +.example-combobox-input { + border-radius: var(--mat-sys-corner-extra-small); +} + +.example-combobox-input[readonly='true']:not([aria-disabled='true']) { + cursor: pointer; + padding: 0.7rem 1rem; +} + +.example-combobox-container:focus-within .example-combobox-input { + outline: 1.5px solid var(--mat-sys-primary); + box-shadow: 0 0 0 4px color-mix(in srgb, var(--mat-sys-primary) 25%, transparent); } .example-icon { @@ -35,6 +47,18 @@ opacity: 0.8; } +.example-arrow-icon { + padding: 0 0.5rem; + position: absolute; + right: 0; + opacity: 0.8; + transition: transform 0.2s ease; +} + +.example-combobox-input[aria-expanded='true'] + .example-arrow-icon { + transform: rotate(180deg); +} + .example-combobox-input { width: 100%; border: none; @@ -48,8 +72,7 @@ margin: 0; padding: 0; border: 1px solid var(--mat-sys-outline); - border-bottom-right-radius: var(--mat-sys-corner-extra-small); - border-bottom-left-radius: var(--mat-sys-corner-extra-small); + border-radius: var(--mat-sys-corner-extra-small); background-color: var(--mat-sys-surface); } @@ -59,6 +82,7 @@ overflow: auto; max-height: 10rem; padding: 0.5rem; + gap: 4px; } .example-option { @@ -70,6 +94,26 @@ flex-shrink: 0; align-items: center; justify-content: space-between; + gap: 1rem; +} + +.example-option-text { + flex: 1; +} + +.example-checkbox-blank-icon, +.example-option[aria-selected='true'] .example-checkbox-filled-icon { + display: flex; + align-items: center; +} + +.example-checkbox-filled-icon, +.example-option[aria-selected='true'] .example-checkbox-blank-icon { + display: none; +} + +.example-checkbox-blank-icon { + opacity: 0.6; } .example-selected-icon { @@ -80,26 +124,17 @@ visibility: visible; } -.example-option[inert], -.example-tree-item[inert] { - display: none; +.example-option[aria-selected='true'] { + color: var(--mat-sys-primary); + background-color: color-mix(in srgb, var(--mat-sys-primary) 10%, transparent); +} + +.example-option:hover { + background-color: color-mix(in srgb, var(--mat-sys-on-surface) 10%, transparent); } .example-combobox-container:focus-within [data-active='true'] { - background: color-mix( - in srgb, - var(--mat-sys-on-surface) calc(var(--mat-sys-focus-state-layer-opacity) * 100%), - transparent - ); -} - -.example-combobox-container:focus-within [data-active='true'][aria-selected='true'] { - background: color-mix( - in srgb, - var(--mat-sys-primary) calc(var(--mat-sys-pressed-state-layer-opacity) * 100%), - transparent - ); - color: var(--mat-sys-primary); + outline: 2px solid color-mix(in srgb, var(--mat-sys-primary) 80%, transparent); } .example-tree { @@ -147,3 +182,8 @@ ul[role='group'] { .example-tree-item[aria-selected='true'] .example-selected-icon { visibility: visible; } + +.example-combobox-container:has([aria-disabled='true']) { + opacity: 0.4; + cursor: default; +} diff --git a/src/components-examples/aria/combobox/combobox-highlight/combobox-highlight-example.ts b/src/components-examples/aria/combobox/combobox-highlight/combobox-highlight-example.ts index 074310e88c1f..86f8ef5e07cf 100644 --- a/src/components-examples/aria/combobox/combobox-highlight/combobox-highlight-example.ts +++ b/src/components-examples/aria/combobox/combobox-highlight/combobox-highlight-example.ts @@ -55,10 +55,9 @@ export class ComboboxHighlightExample { afterRenderEffect(() => { const popover = this.popover()!; const combobox = this.combobox()!; - combobox.pattern.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); + combobox.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); - // TODO(wagnermaciel): Make this easier for developers to do. - this.listbox()?.pattern.inputs.activeItem()?.element().scrollIntoView({block: 'nearest'}); + this.listbox()?.scrollActiveItemIntoView(); }); } @@ -66,12 +65,12 @@ export class ComboboxHighlightExample { const popover = this.popover()!; const combobox = this.combobox()!; - const comboboxRect = combobox.pattern.inputs.inputEl()?.getBoundingClientRect(); + const comboboxRect = combobox.inputElement()?.getBoundingClientRect(); const popoverEl = popover.nativeElement; if (comboboxRect) { popoverEl.style.width = `${comboboxRect.width}px`; - popoverEl.style.top = `${comboboxRect.bottom}px`; + popoverEl.style.top = `${comboboxRect.bottom + 4}px`; popoverEl.style.left = `${comboboxRect.left - 1}px`; } diff --git a/src/components-examples/aria/combobox/combobox-manual/combobox-manual-example.ts b/src/components-examples/aria/combobox/combobox-manual/combobox-manual-example.ts index 1493d28eb0b2..4075b3cdae62 100644 --- a/src/components-examples/aria/combobox/combobox-manual/combobox-manual-example.ts +++ b/src/components-examples/aria/combobox/combobox-manual/combobox-manual-example.ts @@ -55,10 +55,9 @@ export class ComboboxManualExample { afterRenderEffect(() => { const popover = this.popover()!; const combobox = this.combobox()!; - combobox.pattern.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); + combobox.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); - // TODO(wagnermaciel): Make this easier for developers to do. - this.listbox()?.pattern.inputs.activeItem()?.element().scrollIntoView({block: 'nearest'}); + this.listbox()?.scrollActiveItemIntoView(); }); } @@ -66,12 +65,12 @@ export class ComboboxManualExample { const popover = this.popover()!; const combobox = this.combobox()!; - const comboboxRect = combobox.pattern.inputs.inputEl()?.getBoundingClientRect(); + const comboboxRect = combobox.inputElement()?.getBoundingClientRect(); const popoverEl = popover.nativeElement; if (comboboxRect) { popoverEl.style.width = `${comboboxRect.width}px`; - popoverEl.style.top = `${comboboxRect.bottom}px`; + popoverEl.style.top = `${comboboxRect.bottom + 4}px`; popoverEl.style.left = `${comboboxRect.left - 1}px`; } diff --git a/src/components-examples/aria/combobox/combobox-readonly-disabled/combobox-readonly-disabled-example.html b/src/components-examples/aria/combobox/combobox-readonly-disabled/combobox-readonly-disabled-example.html new file mode 100644 index 000000000000..0bffcd456559 --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-readonly-disabled/combobox-readonly-disabled-example.html @@ -0,0 +1,26 @@ +
        +
        + {{ displayValue() }} + + arrow_drop_down +
        + + + +
        +
        + @for (label of labels; track label.value) { +
        + {{label.icon}} + {{label.value}} + check +
        + } +
        +
        +
        +
        +
        diff --git a/src/components-examples/aria/combobox/combobox-readonly-disabled/combobox-readonly-disabled-example.ts b/src/components-examples/aria/combobox/combobox-readonly-disabled/combobox-readonly-disabled-example.ts new file mode 100644 index 000000000000..ef1b9a3a4e3d --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-readonly-disabled/combobox-readonly-disabled-example.ts @@ -0,0 +1,94 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + signal, + viewChild, + viewChildren, +} from '@angular/core'; +import {OverlayModule} from '@angular/cdk/overlay'; + +/** @title Disabled readonly combobox. */ +@Component({ + selector: 'combobox-readonly-disabled-example', + templateUrl: 'combobox-readonly-disabled-example.html', + styleUrl: '../select-examples.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + OverlayModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ComboboxReadonlyDisabledExample { + /** The string that is displayed in the combobox. */ + displayValue = signal(''); + + /** The combobox listbox popup. */ + listbox = viewChild>(Listbox); + + /** The options available in the listbox. */ + options = viewChildren>(Option); + + /** A reference to the ng aria combobox. */ + combobox = viewChild>(Combobox); + + /** The labels that are available for selection. */ + labels = [ + {value: 'Important', icon: 'label'}, + {value: 'Starred', icon: 'star'}, + {value: 'Work', icon: 'work'}, + {value: 'Personal', icon: 'person'}, + {value: 'To Do', icon: 'checklist'}, + {value: 'Later', icon: 'schedule'}, + {value: 'Read', icon: 'menu_book'}, + {value: 'Travel', icon: 'flight'}, + ]; + + constructor() { + // Updates the display value when the listbox values change. + afterRenderEffect(() => { + const values = this.listbox()?.values() || []; + if (values.length === 0) { + this.displayValue.set('Select a label'); + } else if (values.length === 1) { + this.displayValue.set(values[0]); + } else { + this.displayValue.set(`${values[0]} + ${values.length - 1} more`); + } + }); + + // Scrolls to the active item when the active option changes. + // The slight delay here is to ensure animations are done before scrolling. + afterRenderEffect(() => { + const option = this.options().find(opt => opt.active()); + setTimeout(() => option?.element.scrollIntoView({block: 'nearest'}), 50); + }); + + // Resets the listbox scroll position when the combobox is closed. + afterRenderEffect(() => { + if (!this.combobox()?.expanded()) { + setTimeout(() => this.listbox()?.element.scrollTo(0, 0), 150); + } + }); + } +} diff --git a/src/components-examples/aria/combobox/combobox-readonly-multiselect/combobox-readonly-multiselect-example.html b/src/components-examples/aria/combobox/combobox-readonly-multiselect/combobox-readonly-multiselect-example.html new file mode 100644 index 000000000000..07a5bc78a105 --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-readonly-multiselect/combobox-readonly-multiselect-example.html @@ -0,0 +1,26 @@ +
        +
        + {{ displayValue() }} + + arrow_drop_down +
        + + + +
        +
        + @for (label of labels; track label.value) { +
        + {{label.icon}} + {{label.value}} + check +
        + } +
        +
        +
        +
        +
        diff --git a/src/components-examples/aria/combobox/combobox-readonly-multiselect/combobox-readonly-multiselect-example.ts b/src/components-examples/aria/combobox/combobox-readonly-multiselect/combobox-readonly-multiselect-example.ts new file mode 100644 index 000000000000..1e6a6eb4c6d1 --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-readonly-multiselect/combobox-readonly-multiselect-example.ts @@ -0,0 +1,94 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import {OverlayModule} from '@angular/cdk/overlay'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + signal, + viewChild, + viewChildren, +} from '@angular/core'; + +/** @title Readonly multiselectable combobox. */ +@Component({ + selector: 'combobox-readonly-multiselect-example', + templateUrl: 'combobox-readonly-multiselect-example.html', + styleUrl: '../select-examples.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + OverlayModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ComboboxReadonlyMultiselectExample { + /** The string that is displayed in the combobox. */ + displayValue = signal(''); + + /** The combobox listbox popup. */ + listbox = viewChild>(Listbox); + + /** The options available in the listbox. */ + options = viewChildren>(Option); + + /** A reference to the ng aria combobox. */ + combobox = viewChild>(Combobox); + + /** The labels that are available for selection. */ + labels = [ + {value: 'Important', icon: 'label'}, + {value: 'Starred', icon: 'star'}, + {value: 'Work', icon: 'work'}, + {value: 'Personal', icon: 'person'}, + {value: 'To Do', icon: 'checklist'}, + {value: 'Later', icon: 'schedule'}, + {value: 'Read', icon: 'menu_book'}, + {value: 'Travel', icon: 'flight'}, + ]; + + constructor() { + // Updates the display value when the listbox values change. + afterRenderEffect(() => { + const values = this.listbox()?.values() || []; + if (values.length === 0) { + this.displayValue.set('Select a label'); + } else if (values.length === 1) { + this.displayValue.set(values[0]); + } else { + this.displayValue.set(`${values[0]} + ${values.length - 1} more`); + } + }); + + // Scrolls to the active item when the active option changes. + // The slight delay here is to ensure animations are done before scrolling. + afterRenderEffect(() => { + const option = this.options().find(opt => opt.active()); + setTimeout(() => option?.element.scrollIntoView({block: 'nearest'}), 50); + }); + + // Resets the listbox scroll position when the combobox is closed. + afterRenderEffect(() => { + if (!this.combobox()?.expanded()) { + setTimeout(() => this.listbox()?.element.scrollTo(0, 0), 150); + } + }); + } +} diff --git a/src/components-examples/aria/combobox/combobox-readonly/combobox-readonly-example.html b/src/components-examples/aria/combobox/combobox-readonly/combobox-readonly-example.html new file mode 100644 index 000000000000..eb10faa22c2b --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-readonly/combobox-readonly-example.html @@ -0,0 +1,26 @@ +
        +
        + {{ displayValue() }} + + arrow_drop_down +
        + + + +
        +
        + @for (label of labels; track label.value) { +
        + {{label.icon}} + {{label.value}} + check +
        + } +
        +
        +
        +
        +
        diff --git a/src/components-examples/aria/combobox/combobox-readonly/combobox-readonly-example.ts b/src/components-examples/aria/combobox/combobox-readonly/combobox-readonly-example.ts new file mode 100644 index 000000000000..264d221920b4 --- /dev/null +++ b/src/components-examples/aria/combobox/combobox-readonly/combobox-readonly-example.ts @@ -0,0 +1,89 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + signal, + viewChild, + viewChildren, +} from '@angular/core'; +import {OverlayModule} from '@angular/cdk/overlay'; + +/** @title Readonly combobox. */ +@Component({ + selector: 'combobox-readonly-example', + templateUrl: 'combobox-readonly-example.html', + styleUrl: '../select-examples.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + OverlayModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ComboboxReadonlyExample { + /** The string that is displayed in the combobox. */ + displayValue = signal(''); + + /** The combobox listbox popup. */ + listbox = viewChild>(Listbox); + + /** The options available in the listbox. */ + options = viewChildren>(Option); + + /** A reference to the ng aria combobox. */ + combobox = viewChild>(Combobox); + + /** The labels that are available for selection. */ + labels = [ + {value: 'Important', icon: 'label'}, + {value: 'Starred', icon: 'star'}, + {value: 'Work', icon: 'work'}, + {value: 'Personal', icon: 'person'}, + {value: 'To Do', icon: 'checklist'}, + {value: 'Later', icon: 'schedule'}, + {value: 'Read', icon: 'menu_book'}, + {value: 'Travel', icon: 'flight'}, + ]; + + constructor() { + // Updates the display value when the listbox values change. + afterRenderEffect(() => { + const values = this.listbox()?.values() || []; + const displayValue = values.length ? values[0] : 'Select a label'; + this.displayValue.set(displayValue); + }); + + // Scrolls to the active item when the active option changes. + // The slight delay here is to ensure animations are done before scrolling. + afterRenderEffect(() => { + const option = this.options().find(opt => opt.active()); + setTimeout(() => option?.element.scrollIntoView({block: 'nearest'}), 50); + }); + + // Resets the listbox scroll position when the combobox is closed. + afterRenderEffect(() => { + if (!this.combobox()?.expanded()) { + setTimeout(() => this.listbox()?.element.scrollTo(0, 0), 150); + } + }); + } +} diff --git a/src/components-examples/aria/combobox/combobox-tree-auto-select/combobox-tree-auto-select-example.html b/src/components-examples/aria/combobox/combobox-tree-auto-select/combobox-tree-auto-select-example.html index 4ef3639366a4..fe7a5fa8af62 100644 --- a/src/components-examples/aria/combobox/combobox-tree-auto-select/combobox-tree-auto-select-example.html +++ b/src/components-examples/aria/combobox/combobox-tree-auto-select/combobox-tree-auto-select-example.html @@ -34,6 +34,7 @@ [parent]="parent" [value]="node.name" [label]="node.name" + [selectable]="!node.children" #treeItem="ngTreeItem" class="example-tree-item example-selectable example-stateful" > diff --git a/src/components-examples/aria/combobox/combobox-tree-auto-select/combobox-tree-auto-select-example.ts b/src/components-examples/aria/combobox/combobox-tree-auto-select/combobox-tree-auto-select-example.ts index 2ccc5c197a82..d35c710b8dfe 100644 --- a/src/components-examples/aria/combobox/combobox-tree-auto-select/combobox-tree-auto-select-example.ts +++ b/src/components-examples/aria/combobox/combobox-tree-auto-select/combobox-tree-auto-select-example.ts @@ -81,10 +81,8 @@ export class ComboboxTreeAutoSelectExample { afterRenderEffect(() => { const popover = this.popover()!; const combobox = this.combobox()!; - combobox.pattern.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); - - // TODO(wagnermaciel): Make this easier for developers to do. - this.tree()?.pattern.inputs.activeItem()?.element().scrollIntoView({block: 'nearest'}); + combobox.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); + this.tree()?.scrollActiveItemIntoView(); }); } @@ -92,12 +90,12 @@ export class ComboboxTreeAutoSelectExample { const popover = this.popover()!; const combobox = this.combobox()!; - const comboboxRect = combobox.pattern.inputs.inputEl()?.getBoundingClientRect(); + const comboboxRect = combobox.inputElement()?.getBoundingClientRect(); const popoverEl = popover.nativeElement; if (comboboxRect) { popoverEl.style.width = `${comboboxRect.width}px`; - popoverEl.style.top = `${comboboxRect.bottom}px`; + popoverEl.style.top = `${comboboxRect.bottom + 4}px`; popoverEl.style.left = `${comboboxRect.left - 1}px`; } diff --git a/src/components-examples/aria/combobox/combobox-tree-highlight/combobox-tree-highlight-example.html b/src/components-examples/aria/combobox/combobox-tree-highlight/combobox-tree-highlight-example.html index 7315770195e8..14f4f5999c41 100644 --- a/src/components-examples/aria/combobox/combobox-tree-highlight/combobox-tree-highlight-example.html +++ b/src/components-examples/aria/combobox/combobox-tree-highlight/combobox-tree-highlight-example.html @@ -34,6 +34,7 @@ [parent]="parent" [value]="node.name" [label]="node.name" + [selectable]="!node.children" #treeItem="ngTreeItem" class="example-tree-item example-selectable example-stateful" > diff --git a/src/components-examples/aria/combobox/combobox-tree-highlight/combobox-tree-highlight-example.ts b/src/components-examples/aria/combobox/combobox-tree-highlight/combobox-tree-highlight-example.ts index 013aaec24480..aefd4830422e 100644 --- a/src/components-examples/aria/combobox/combobox-tree-highlight/combobox-tree-highlight-example.ts +++ b/src/components-examples/aria/combobox/combobox-tree-highlight/combobox-tree-highlight-example.ts @@ -81,10 +81,8 @@ export class ComboboxTreeHighlightExample { afterRenderEffect(() => { const popover = this.popover()!; const combobox = this.combobox()!; - combobox.pattern.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); - - // TODO(wagnermaciel): Make this easier for developers to do. - this.tree()?.pattern.inputs.activeItem()?.element().scrollIntoView({block: 'nearest'}); + combobox.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); + this.tree()?.scrollActiveItemIntoView(); }); } @@ -92,12 +90,12 @@ export class ComboboxTreeHighlightExample { const popover = this.popover()!; const combobox = this.combobox()!; - const comboboxRect = combobox.pattern.inputs.inputEl()?.getBoundingClientRect(); + const comboboxRect = combobox.inputElement()?.getBoundingClientRect(); const popoverEl = popover.nativeElement; if (comboboxRect) { popoverEl.style.width = `${comboboxRect.width}px`; - popoverEl.style.top = `${comboboxRect.bottom}px`; + popoverEl.style.top = `${comboboxRect.bottom + 4}px`; popoverEl.style.left = `${comboboxRect.left - 1}px`; } diff --git a/src/components-examples/aria/combobox/combobox-tree-manual/combobox-tree-manual-example.html b/src/components-examples/aria/combobox/combobox-tree-manual/combobox-tree-manual-example.html index 994e956f3535..41c67e436ab0 100644 --- a/src/components-examples/aria/combobox/combobox-tree-manual/combobox-tree-manual-example.html +++ b/src/components-examples/aria/combobox/combobox-tree-manual/combobox-tree-manual-example.html @@ -34,6 +34,7 @@ [parent]="parent" [value]="node.name" [label]="node.name" + [selectable]="!node.children" #treeItem="ngTreeItem" class="example-tree-item example-selectable example-stateful" > diff --git a/src/components-examples/aria/combobox/combobox-tree-manual/combobox-tree-manual-example.ts b/src/components-examples/aria/combobox/combobox-tree-manual/combobox-tree-manual-example.ts index 3e2d77bda2ae..5a7967f17d9f 100644 --- a/src/components-examples/aria/combobox/combobox-tree-manual/combobox-tree-manual-example.ts +++ b/src/components-examples/aria/combobox/combobox-tree-manual/combobox-tree-manual-example.ts @@ -81,10 +81,8 @@ export class ComboboxTreeManualExample { afterRenderEffect(() => { const popover = this.popover()!; const combobox = this.combobox()!; - combobox.pattern.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); - - // TODO(wagnermaciel): Make this easier for developers to do. - this.tree()?.pattern.inputs.activeItem()?.element().scrollIntoView({block: 'nearest'}); + combobox.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); + this.tree()?.scrollActiveItemIntoView(); }); } @@ -92,12 +90,12 @@ export class ComboboxTreeManualExample { const popover = this.popover()!; const combobox = this.combobox()!; - const comboboxRect = combobox.pattern.inputs.inputEl()?.getBoundingClientRect(); + const comboboxRect = combobox.inputElement()?.getBoundingClientRect(); const popoverEl = popover.nativeElement; if (comboboxRect) { popoverEl.style.width = `${comboboxRect.width}px`; - popoverEl.style.top = `${comboboxRect.bottom}px`; + popoverEl.style.top = `${comboboxRect.bottom + 4}px`; popoverEl.style.left = `${comboboxRect.left - 1}px`; } diff --git a/src/components-examples/aria/combobox/index.ts b/src/components-examples/aria/combobox/index.ts index ca1e1f5c5dde..e19dfd098d76 100644 --- a/src/components-examples/aria/combobox/index.ts +++ b/src/components-examples/aria/combobox/index.ts @@ -1,6 +1,13 @@ +export {ComboboxDialogExample} from './combobox-dialog/combobox-dialog-example'; export {ComboboxManualExample} from './combobox-manual/combobox-manual-example'; export {ComboboxAutoSelectExample} from './combobox-auto-select/combobox-auto-select-example'; export {ComboboxHighlightExample} from './combobox-highlight/combobox-highlight-example'; +export {ComboboxDisabledExample} from './combobox-disabled/combobox-disabled-example'; + +export {ComboboxReadonlyExample} from './combobox-readonly/combobox-readonly-example'; +export {ComboboxReadonlyMultiselectExample} from './combobox-readonly-multiselect/combobox-readonly-multiselect-example'; +export {ComboboxReadonlyDisabledExample} from './combobox-readonly-disabled/combobox-readonly-disabled-example'; + export {ComboboxTreeManualExample} from './combobox-tree-manual/combobox-tree-manual-example'; export {ComboboxTreeAutoSelectExample} from './combobox-tree-auto-select/combobox-tree-auto-select-example'; export {ComboboxTreeHighlightExample} from './combobox-tree-highlight/combobox-tree-highlight-example'; diff --git a/src/components-examples/aria/combobox/select-examples.css b/src/components-examples/aria/combobox/select-examples.css new file mode 100644 index 000000000000..2e4dde0cd4d1 --- /dev/null +++ b/src/components-examples/aria/combobox/select-examples.css @@ -0,0 +1,120 @@ +.example-select { + display: flex; + position: relative; + align-items: center; + color: var(--mat-sys-on-primary); + font-size: var(--mat-sys-label-large); + background-color: var(--mat-sys-primary); + border-radius: var(--mat-sys-corner-extra-large); +} + +.example-select:has([ngComboboxInput][aria-disabled='true']) { + opacity: 0.6; + cursor: default; +} + +.example-select:hover { + background-color: color-mix(in srgb, var(--mat-sys-primary) 90%, transparent); +} + +[ngComboboxInput] { + opacity: 0; + cursor: pointer; + padding: 0 3rem; + height: 3rem; + border: none; +} + +[ngCombobox]:focus-within .example-select { + outline-offset: 2px; + outline: 2px solid var(--mat-sys-primary); +} + +.example-combobox-text { + left: 2rem; + position: absolute; +} + +.example-arrow { + right: 1rem; + position: absolute; + pointer-events: none; + transition: transform 150ms ease-in-out; +} + +[ngComboboxInput][aria-expanded='true'] ~ .example-arrow { + transform: rotate(180deg); +} + +.example-popup-container { + width: 100%; + padding: 0.5rem; + margin-top: 8px; + border-radius: var(--mat-sys-corner-large); + background-color: var(--mat-sys-surface-container); + + max-height: 13rem; + opacity: 1; + visibility: visible; + transition: max-height 150ms ease-out, visibility 0s, opacity 25ms ease-out; +} + +[ngListbox] { + gap: 4px; + height: 100%; + display: flex; + overflow: auto; + flex-direction: column; +} + +[ngCombobox]:has([ngComboboxInput][aria-expanded='false']) .example-popup-container { + max-height: 0; + opacity: 0; + visibility: hidden; + transition: max-height 150ms ease-in, visibility 0s 150ms, opacity 150ms ease-in; +} + +[ngCombobox]:has([ngComboboxInput][aria-expanded='true']) [ngListbox] { + display: flex; +} + +[ngOption] { + display: flex; + cursor: pointer; + align-items: center; + padding: 0 1rem; + min-height: 3rem; + color: var(--mat-sys-on-surface); + font-size: var(--mat-sys-label-large); + border-radius: var(--mat-sys-corner-extra-large); +} + +[ngOption]:hover { + background-color: color-mix(in srgb, var(--mat-sys-on-surface) 5%, transparent); +} + +[ngOption][data-active='true'] { + background-color: color-mix(in srgb, var(--mat-sys-on-surface) 10%, transparent); +} + +[ngOption][aria-selected='true'] { + color: var(--mat-sys-primary); + background-color: color-mix(in srgb, var(--mat-sys-primary) 10%, transparent); +} + +.example-option-icon { + padding-right: 1rem; +} + +.example-option-check, +.example-option-icon { + font-size: var(--mat-sys-label-large); +} + +[ngOption]:not([aria-selected='true']) .example-option-check { + display: none; +} + +.example-option-text { + flex: 1; +} diff --git a/src/components-examples/aria/grid/BUILD.bazel b/src/components-examples/aria/grid/BUILD.bazel index 2f11f723254e..b16742afd8b4 100644 --- a/src/components-examples/aria/grid/BUILD.bazel +++ b/src/components-examples/aria/grid/BUILD.bazel @@ -17,6 +17,7 @@ ng_project( "//src/material/checkbox", "//src/material/form-field", "//src/material/icon", + "//src/material/input", "//src/material/select", ], ) diff --git a/src/components-examples/aria/grid/grid-calendar/grid-calendar-example.css b/src/components-examples/aria/grid/grid-calendar/grid-calendar-example.css new file mode 100644 index 000000000000..9499799e4509 --- /dev/null +++ b/src/components-examples/aria/grid/grid-calendar/grid-calendar-example.css @@ -0,0 +1,75 @@ +.example-grid-container { + max-width: fit-content; +} + +.example-grid-calendar-debug { + padding-bottom: 12px; +} + +.example-grid-calendar-control { + display: flex; + justify-content: space-around; + align-items: center; +} + +.example-grid-calendar-control-button { + background-color: transparent; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + width: 80px; + border: 2px solid color-mix(in srgb, var(--mat-sys-outline) 40%, transparent); + cursor: pointer; +} + +.example-grid-calendar-control-button:hover, +.example-grid-calendar-control-button:focus { + background: color-mix( + in srgb, + var(--mat-sys-on-surface) calc(var(--mat-sys-hover-state-layer-opacity) * 100%), + transparent + ); +} + +.example-calendar-cell { + width: 50px; + height: 50px; + text-align: center; + vertical-align: middle; +} + +.example-calendar-cell[aria-disabled='true'] { + color: color-mix(in srgb, var(--mat-sys-on-surface) 38%, transparent); +} + +.example-calendar-day-button { + width: 90%; + height: 90%; + border-radius: 50%; + border: 0; + background-color: transparent; +} + +.example-calendar-day-button:hover { + background: color-mix( + in srgb, + var(--mat-sys-on-surface) calc(var(--mat-sys-hover-state-layer-opacity) * 100%), + transparent + ); +} + +[data-active='true'] .example-calendar-day-button { + outline: 3px dashed var(--mat-sys-outline); + outline-offset: 3px; +} + +[data-active='true']:focus-within .example-calendar-day-button { + outline: 3px dashed var(--mat-sys-tertiary); + outline-offset: 3px; +} + +[aria-selected='true'] .example-calendar-day-button { + color: var(--mat-sys-on-primary); + background: color-mix(in srgb, var(--mat-sys-primary) 80%, transparent); +} diff --git a/src/components-examples/aria/grid/grid-calendar/grid-calendar-example.html b/src/components-examples/aria/grid/grid-calendar/grid-calendar-example.html new file mode 100644 index 000000000000..63d85bd843f0 --- /dev/null +++ b/src/components-examples/aria/grid/grid-calendar/grid-calendar-example.html @@ -0,0 +1,61 @@ +
        +
        Selected Date: {{displayActiveDate()}}
        +
        + +
        {{monthYearLabel()}}
        + +
        + + + + + @for (day of weekdays(); track day.long) { + + } + + + + @for (week of weeks(); track week) { + + @if ($first) { + @for (day of daysFromPrevMonth(); track day) { + + } + } + + @for (day of week; track day) { + + } + + @if ($last && week.length < 7) { + @for (day of [].constructor(7 - week.length); track $index) { + + } + } + + } +
        + {{day.long}} + +
        {{day}} + + {{$index + 1}}
        +
        diff --git a/src/components-examples/aria/grid/grid-calendar/grid-calendar-example.ts b/src/components-examples/aria/grid/grid-calendar/grid-calendar-example.ts new file mode 100644 index 000000000000..7f1e844e48b6 --- /dev/null +++ b/src/components-examples/aria/grid/grid-calendar/grid-calendar-example.ts @@ -0,0 +1,143 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ +import { + inject, + Component, + WritableSignal, + signal, + Signal, + computed, + untracked, + afterRenderEffect, +} from '@angular/core'; +import {DateAdapter, MAT_DATE_FORMATS, MatDateFormats} from '@angular/material/core'; +import {Grid, GridRow, GridCell, GridCellWidget} from '@angular/aria/grid'; + +const DAYS_PER_WEEK = 7; + +interface CalendarCell { + displayName: string; + ariaLabel: string; + date: D; + selected: WritableSignal; +} + +/** @title Grid Calendar. */ +@Component({ + selector: 'grid-calendar-example', + templateUrl: 'grid-calendar-example.html', + styleUrls: ['../grid-common.css', 'grid-calendar-example.css'], + imports: [Grid, GridRow, GridCell, GridCellWidget], +}) +export class GridCalendarExample { + private readonly _dateAdapter = inject>(DateAdapter, {optional: true})!; + private readonly _dateFormats = inject(MAT_DATE_FORMATS, {optional: true})!; + private readonly _firstWeekOffset: Signal = computed(() => { + const firstOfMonth = this._dateAdapter.createDate( + this._dateAdapter.getYear(this.viewMonth()), + this._dateAdapter.getMonth(this.viewMonth()), + 1, + ); + + return ( + (DAYS_PER_WEEK + + this._dateAdapter.getDayOfWeek(firstOfMonth) - + this._dateAdapter.getFirstDayOfWeek()) % + DAYS_PER_WEEK + ); + }); + + private readonly _activeDate: WritableSignal = signal(this._dateAdapter.today()); + readonly displayActiveDate: Signal = computed(() => + this._dateAdapter.format(this._activeDate(), this._dateFormats.display), + ); + + readonly monthYearLabel: Signal = computed(() => + this._dateAdapter + .format(this.viewMonth(), this._dateFormats.display.monthYearLabel) + .toLocaleUpperCase(), + ); + readonly prevMonthNumDays: Signal = computed(() => + this._dateAdapter.getNumDaysInMonth(this._dateAdapter.addCalendarMonths(this.viewMonth(), -1)), + ); + readonly daysFromPrevMonth: Signal = computed(() => { + const days: number[] = []; + for (let i = this._firstWeekOffset() - 1; i >= 0; i--) { + days.push(this.prevMonthNumDays() - i); + } + return days; + }); + readonly viewMonth: WritableSignal = signal(this._dateAdapter.today()); + readonly weekdays: Signal<{long: string; narrow: string}[]> = computed(() => { + const firstDayOfWeek = this._dateAdapter.getFirstDayOfWeek(); + const narrowWeekdays = this._dateAdapter.getDayOfWeekNames('narrow'); + const longWeekdays = this._dateAdapter.getDayOfWeekNames('long'); + + // Rotate the labels for days of the week based on the configured first day of the week. + const weekdays = longWeekdays.map((long, i) => { + return {long, narrow: narrowWeekdays[i]}; + }); + return weekdays.slice(firstDayOfWeek).concat(weekdays.slice(0, firstDayOfWeek)); + }); + readonly weeks: Signal[][]> = computed(() => + this._createWeekCells(this.viewMonth()), + ); + + readonly scrolledUp = signal(false); + readonly scrolledDown = signal(false); + + constructor() { + afterRenderEffect(() => { + for (const day of this.weeks().flat()) { + if (day.selected()) { + this._activeDate.set(day.date); + return; + } + } + }); + } + + nextMonth(): void { + this.viewMonth.set(this._dateAdapter.addCalendarMonths(this.viewMonth(), 1)); + } + + prevMonth(): void { + this.viewMonth.set(this._dateAdapter.addCalendarMonths(this.viewMonth(), -1)); + } + + private _createWeekCells(viewMonth: D): CalendarCell[][] { + const daysInMonth = this._dateAdapter.getNumDaysInMonth(viewMonth); + const dateNames = this._dateAdapter.getDateNames(); + const weeks: CalendarCell[][] = [[]]; + for (let i = 0, cell = this._firstWeekOffset(); i < daysInMonth; i++, cell++) { + if (cell == DAYS_PER_WEEK) { + weeks.push([]); + cell = 0; + } + const date = this._dateAdapter.createDate( + this._dateAdapter.getYear(viewMonth), + this._dateAdapter.getMonth(viewMonth), + i + 1, + ); + const ariaLabel = this._dateAdapter.format(date, this._dateFormats.display.dateA11yLabel); + + weeks[weeks.length - 1].push({ + displayName: dateNames[i], + ariaLabel, + date, + selected: signal( + this._dateAdapter.compareDate( + date, + untracked(() => this._activeDate()), + ) === 0, + ), + }); + } + return weeks; + } +} diff --git a/src/components-examples/aria/grid/grid-common.css b/src/components-examples/aria/grid/grid-common.css index 90b84b899be3..67c1e65f27f6 100644 --- a/src/components-examples/aria/grid/grid-common.css +++ b/src/components-examples/aria/grid/grid-common.css @@ -1,23 +1,53 @@ -.example-grid-controls { +.example-controls { + display: flex; + flex-wrap: wrap; align-items: center; + gap: 16px; margin-bottom: 16px; } -.example-grid-controls-select { +.example-controls-select { padding: 8px; } -.example-grid-cell[data-active='true'] { +.example-cell[data-active='true'] { outline: 3px dashed var(--mat-sys-outline); outline-offset: 4px; } -.example-grid-cell[data-active='true']:focus-within, -[aria-activedescendant]:focus-within .example-grid-cell[data-active='true'] { +.example-grid:focus-within .example-cell[data-anchor='true'][data-active='false'] { + outline: 3px dashed var(--mat-sys-outline); + outline-offset: 3px; +} + +.example-cell[data-active='true']:focus-within, +[aria-activedescendant]:focus-within .example-cell[data-active='true'] { outline: 3px dashed var(--mat-sys-tertiary); outline-offset: 3px; } -.example-grid-cell[aria-disabled='true'] { +.example-cell.example-cell.example-cell:has([data-active-control='widget']) { + outline: 3px dashed var(--mat-sys-on-error-container); + outline-offset: 3px; +} + +.example-cell[aria-disabled='true'] { border: 1px dashed var(--mat-sys-outline-variant); } + +.example-cell:hover { + background: color-mix( + in srgb, + var(--mat-sys-on-surface) calc(var(--mat-sys-hover-state-layer-opacity) * 100%), + transparent + ); +} + +.example-cell[aria-selected='true'] { + background: color-mix( + in srgb, + var(--mat-sys-primary) calc(var(--mat-sys-pressed-state-layer-opacity) * 100%), + transparent + ); + color: var(--mat-sys-primary); +} diff --git a/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.css b/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.css index 9d620e264ec7..0db7bab4cffb 100644 --- a/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.css +++ b/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.css @@ -1,5 +1,6 @@ .example-grid-container { display: flex; + align-items: flex-start; } .example-grid { @@ -14,8 +15,12 @@ ); } -.example-grid-cell { +.example-cell { height: 50px; width: 50px; border: 1px solid; } + +.example-grid-shortcuts { + margin-left: 12px; +} diff --git a/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.html b/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.html index ae284cf0d6a6..c56e1e022c87 100644 --- a/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.html +++ b/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.html @@ -1,93 +1,57 @@ - - - - - - +
        + Disabled + Soft Disabled + Enable Selection + Multi + Range Selection -
        - - - - -
        - Disabled - - Skip Disabled - - Enable Selection -
        - - Row Wrap - - No Wrap - Loop - Continuous - - - - - Col Wrap - - No Wrap - Loop - Continuous - - - - - Focus Strategy - - Roving - Active Descendant - - -
        + + Row Wrap + + No Wrap + Loop + Continuous + + + + Col Wrap + + No Wrap + Loop + Continuous + + + + Focus Strategy + + Roving + Active Descendant + + + + Selection Strategy + + Explicit + Follow Focus + + +
        @for (row of gridData; track row) { @for (cell of row; track cell) {
        -
          -
        • - -
        • -
        • Home: first cell in the row
        • -
        • End: last cell in the row
        • -
        • Crtl + Home: very first cell
        • -
        • Ctrl + End: very last cell
        • -
        • Shift + Space: select a row
        • -
        • Ctrl + Space: select a col
        • -
        • Shift + Arrow: expand selection
        • -
        • Ctrl + A: select all
        • -
        • - Internal coords: ({{grid.pattern.gridBehavior.focusBehavior.activeCoords().row - - - - - +
          +
          + + Example Options + + Row Span + Col Span + Disabled + + +
          +
          + Navigation Keys +
            +
          • Arrow keys navigation
          • +
          • Home: first cell in the row
          • +
          • End: last cell in the row
          • +
          • Crtl + Home: very first cell
          • +
          • Ctrl + End: very last cell
          • +
          + @if (enableSelection.value) { + Selection Keys +
            + @if (this.selectionMode === 'explicit') { +
          • Enter/Space: select/deselect cell (explicit)
          • + } + @if (this.selectionMode === 'follow') { +
          • Selection change on navigation (follow focus)
          • + } + @if (multi.value && enableRangeSelection.value) { +
          • Shift + Arrow: expand selection
          • +
          • Ctrl + A: select all or deselect all (if all selected)
          • +
          • Shift + Space: select a row
          • +
          • Ctrl + Space: select a col
          • +
          • Shift + Home: range select from first cell in the row
          • +
          • Shift + End: range select to last cell in the row
          • +
          • Shift + Ctrl + Home: range select from very first cell
          • +
          • Shift + Ctrl + End: range select to very last cell
          • + } +
          - }}, {{grid.pattern.gridBehavior.focusBehavior.activeCoords().col}}) -
        • -
        + Mouse Selection +
          + @if (this.selectionMode === 'explicit') { +
        • Click: select/deselect cell (explicit)
        • + } + @if (this.selectionMode === 'follow') { +
        • Click: select cell (follow focus)
        • + @if (multi.value) { +
        • Ctrl + Click: add/remove a cell
        • + } + } + @if (multi.value && enableRangeSelection.value) { + @if (this.selectionMode === 'explicit') { +
        • Drag: add a new range selection (explicit)
        • + } + @if (this.selectionMode === 'follow') { +
        • Drag: start a new range selection (follow focus)
        • + } +
        • Shift + Drag: update the current range selection
        • +
        • Ctrl + Drag: add a new range selection
        • + } +
        + } + diff --git a/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.ts b/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.ts index 882acb789ea2..59611bda697c 100644 --- a/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.ts +++ b/src/components-examples/aria/grid/grid-configurable/grid-configurable-example.ts @@ -5,12 +5,12 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ -import {Component} from '@angular/core'; +import {Component, model, afterRenderEffect, computed} from '@angular/core'; import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; import {MatCheckboxModule} from '@angular/material/checkbox'; import {MatFormFieldModule} from '@angular/material/form-field'; import {MatSelectModule} from '@angular/material/select'; -import {Grid, GridRow, GridCell, GridCellWidget} from '@angular/aria/grid'; +import {Grid, GridRow, GridCell} from '@angular/aria/grid'; interface Cell { rowSpan?: number; @@ -30,7 +30,13 @@ function randomDisabled(): boolean { return disabledChanceTable[randomIndex]; } -function generateValidGrid(rowCount: number, colCount: number): Cell[][] { +function generateValidGrid( + rowCount: number, + colCount: number, + randomRowSpan: boolean = true, + randomColSpan: boolean = true, + randomDisable: boolean = true, +): Cell[][] { const grid: Cell[][] = []; const visitedCoords = new Set(); for (let r = 0; r < rowCount; r++) { @@ -40,14 +46,14 @@ function generateValidGrid(rowCount: number, colCount: number): Cell[][] { continue; } - const rowSpan = Math.min(randomSpan(), rowCount - r); - const maxColSpan = Math.min(randomSpan(), colCount - c); + const rowSpan = randomRowSpan ? Math.min(randomSpan(), rowCount - r) : 1; + const maxColSpan = randomColSpan ? Math.min(randomSpan(), colCount - c) : 1; let colSpan = 1; while (colSpan < maxColSpan) { if (visitedCoords.has(`${r},${c + colSpan}`)) break; colSpan += 1; } - const disabled = randomDisabled(); + const disabled = randomDisable ? randomDisabled() : false; row.push({ rowSpan, @@ -69,10 +75,8 @@ function generateValidGrid(rowCount: number, colCount: number): Cell[][] { /** @title Configurable Grid. */ @Component({ selector: 'grid-configurable-example', - exportAs: 'GridConfigurableExample', templateUrl: 'grid-configurable-example.html', styleUrls: ['../grid-common.css', 'grid-configurable-example.css'], - standalone: true, imports: [ FormsModule, ReactiveFormsModule, @@ -82,21 +86,42 @@ function generateValidGrid(rowCount: number, colCount: number): Cell[][] { Grid, GridRow, GridCell, - GridCellWidget, ], }) export class GridConfigurableExample { rowWrap: 'continuous' | 'loop' | 'nowrap' = 'loop'; colWrap: 'continuous' | 'loop' | 'nowrap' = 'continuous'; focusMode: 'roving' | 'activedescendant' = 'roving'; + selectionMode: 'explicit' | 'follow' = 'follow'; + exampleOptions = model(['rowSpan', 'colSpan', 'disable']); + + randomRowSpan = computed(() => this.exampleOptions().includes('rowSpan')); + randomColSpan = computed(() => this.exampleOptions().includes('colSpan')); + randomDisable = computed(() => this.exampleOptions().includes('disable')); disabled = new FormControl(false, {nonNullable: true}); - skipDisabled = new FormControl(true, {nonNullable: true}); + softDisabled = new FormControl(false, {nonNullable: true}); enableSelection = new FormControl(false, {nonNullable: true}); + multi = new FormControl(false, {nonNullable: true}); + enableRangeSelection = new FormControl(false, {nonNullable: true}); - gridData: Cell[][] = generateValidGrid(10, 10); + gridData: Cell[][] = generateValidGrid( + 10, + 10, + this.randomRowSpan(), + this.randomColSpan(), + this.randomDisable(), + ); - regenerateGrid() { - this.gridData = generateValidGrid(10, 10); + constructor() { + afterRenderEffect(() => { + this.gridData = generateValidGrid( + 10, + 10, + this.randomRowSpan(), + this.randomColSpan(), + this.randomDisable(), + ); + }); } } diff --git a/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.css b/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.css index 1501c190d051..fd4360b0882d 100644 --- a/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.css +++ b/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.css @@ -1,6 +1,5 @@ .example-pill-list-container { padding: 10px; - border: 1px solid; max-width: 800px; } @@ -21,7 +20,7 @@ .example-pill-label { border: 1px solid; border-right-width: 0; - border-radius: 1rem 0 0 1rem; + border-radius: 2rem 0 0 2rem; padding: 4px 4px 4px 12px; display: flex; align-items: center; @@ -32,7 +31,7 @@ .example-pill-action { border: 1px solid; - border-radius: 0 1rem 1rem 0; + border-radius: 0 2rem 2rem 0; padding: 4px 12px 4px 8px; display: flex; align-items: center; diff --git a/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.html b/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.html index 87cf65f0f218..798c623fba5e 100644 --- a/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.html +++ b/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.html @@ -6,10 +6,10 @@
        @for (item of sortedItems(); track item; let i = $index) {
        -
        +
        {{item.label}}
        -
        +
        diff --git a/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.ts b/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.ts index 0559ff99605f..5e7c45b336f0 100644 --- a/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.ts +++ b/src/components-examples/aria/grid/grid-pill-list/grid-pill-list-example.ts @@ -16,10 +16,8 @@ import {toSignal} from '@angular/core/rxjs-interop'; /** @title Grid Pill List. */ @Component({ selector: 'grid-pill-list-example', - exportAs: 'GridPillListExample', templateUrl: 'grid-pill-list-example.html', styleUrls: ['../grid-common.css', 'grid-pill-list-example.css'], - standalone: true, imports: [ Grid, GridRow, diff --git a/src/components-examples/aria/grid/grid-table/grid-chips.css b/src/components-examples/aria/grid/grid-table/grid-chips.css new file mode 100644 index 000000000000..46770ac72001 --- /dev/null +++ b/src/components-examples/aria/grid/grid-table/grid-chips.css @@ -0,0 +1,45 @@ +.example-grid-chips { + display: flex; + align-items: center; + gap: 4px; + flex-wrap: wrap; +} + +.example-grid-chips, +.example-chip-icon { + font-size: 0.825rem; +} + +.example-grid-chip { + border-radius: 8px; + display: flex; + align-items: center; + border: 1px solid; + padding: 4px; +} + +.example-grid-chip:hover, +.example-grid-chip:focus-within { + background: color-mix(in srgb, var(--mat-sys-secondary) 10%, transparent); +} + +.example-chip-label { + padding: 0 8px; +} + +.example-chip-remove-button { + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 50%; + border: none; + background: color-mix(in srgb, var(--mat-sys-secondary) 80%, transparent); + color: var(--mat-sys-on-secondary); + height: 1rem; + width: 1rem; +} + +.example-chip-empty { + color: color-mix(in srgb, var(--mat-sys-on-background) 60%, transparent); +} diff --git a/src/components-examples/aria/grid/grid-table/grid-chips.html b/src/components-examples/aria/grid/grid-table/grid-chips.html new file mode 100644 index 000000000000..c3bd582a1d2f --- /dev/null +++ b/src/components-examples/aria/grid/grid-table/grid-chips.html @@ -0,0 +1,25 @@ +
        + @for (value of values(); track $index) { +
        +
        + {{value}} +
        +
        + +
        +
        + } + @if (values().length === 0) { +
        +
        No Tag
        +
        + } +
        diff --git a/src/components-examples/aria/grid/grid-table/grid-chips.ts b/src/components-examples/aria/grid/grid-table/grid-chips.ts new file mode 100644 index 000000000000..e0e421ba5d58 --- /dev/null +++ b/src/components-examples/aria/grid/grid-table/grid-chips.ts @@ -0,0 +1,32 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ +import {Component, model, viewChild, input} from '@angular/core'; +import {Grid, GridRow, GridCell, GridCellWidget} from '@angular/aria/grid'; + +/** @title Grid Chips. */ +@Component({ + selector: 'grid-chips', + exportAs: 'gridChips', + templateUrl: 'grid-chips.html', + styleUrls: ['grid-chips.css'], + imports: [Grid, GridRow, GridCell, GridCellWidget], +}) +export class GridChips { + readonly firstCell = viewChild(GridCell); + readonly values = model([]); + + readonly tabindex = input(); + + removeItem(index: number) { + this.values.update(items => [...items.slice(0, index), ...items.slice(index + 1)]); + } + + focus(): void { + this.firstCell()?.element.focus(); + } +} diff --git a/src/components-examples/aria/grid/grid-table/grid-table-example.css b/src/components-examples/aria/grid/grid-table/grid-table-example.css new file mode 100644 index 000000000000..6ab620cd0b4a --- /dev/null +++ b/src/components-examples/aria/grid/grid-table/grid-table-example.css @@ -0,0 +1,73 @@ +.example-table { + border-spacing: 12px; +} + +.example-table td, +.example-table th { + height: 40px; +} + +.example-header-row th:not(:first-of-type) { + background: color-mix(in srgb, var(--mat-sys-secondary) 80%, transparent); + color: var(--mat-sys-on-secondary); +} + +.example-edit-icon { + color: color-mix(in srgb, var(--mat-sys-on-background) 60%, transparent); +} + +.example-row .example-edit-icon { + opacity: 0; + padding: 0 8px; +} + +.example-row:hover .example-edit-icon, +.example-row:focus-within .example-edit-icon { + opacity: 1; +} + +.example-cell-summary [role='button'] { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + outline: none; +} + +.example-cell-summary mat-form-field { + width: 100%; + height: 100%; +} + +.example-cell-checkbox { + width: 40px; +} + +.example-cell-assignee [role='button'] { + outline: none; +} + +.example-cell-tags { + display: flex; + gap: 10px; + align-items: baseline; + height: 100%; + max-width: 500px; +} + +.example-cell-tag-input { + border: none; + border-bottom: 1px dotted; + font-size: 0.825rem; + background-color: transparent; + max-width: 100px; + height: 24px; + padding: 0; + margin: 0; +} + +.example-hidden { + display: none; +} diff --git a/src/components-examples/aria/grid/grid-table/grid-table-example.html b/src/components-examples/aria/grid/grid-table/grid-table-example.html new file mode 100644 index 000000000000..83c38145fab8 --- /dev/null +++ b/src/components-examples/aria/grid/grid-table/grid-table-example.html @@ -0,0 +1,100 @@ + + + + + + + + + + + @for (task of tasks(); track task) { + + + + + + + } + +
        + + SummaryAssigneeTags
        + + +
        + {{task.summary()}} + + + + +
        +
        +
        + + + @for (e of employees; track e) { + {{e}} + } + + +
        +
        +
        +
        + +
        + +
        +
        diff --git a/src/components-examples/aria/grid/grid-table/grid-table-example.ts b/src/components-examples/aria/grid/grid-table/grid-table-example.ts new file mode 100644 index 000000000000..35337e74688f --- /dev/null +++ b/src/components-examples/aria/grid/grid-table/grid-table-example.ts @@ -0,0 +1,138 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ +import {Component, computed, Signal, signal, WritableSignal} from '@angular/core'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {MatCheckboxModule} from '@angular/material/checkbox'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {MatInputModule} from '@angular/material/input'; +import {MatSelectModule} from '@angular/material/select'; +import {Grid, GridRow, GridCell, GridCellWidget} from '@angular/aria/grid'; +import {GridChips} from './grid-chips'; + +interface TaskRow { + selected: WritableSignal; + summary: WritableSignal; + assignee: WritableSignal; + tags: WritableSignal; +} + +/** @title Table Grid. */ +@Component({ + selector: 'grid-table-example', + templateUrl: 'grid-table-example.html', + styleUrls: ['../grid-common.css', 'grid-table-example.css'], + imports: [ + FormsModule, + ReactiveFormsModule, + MatCheckboxModule, + MatFormFieldModule, + MatSelectModule, + MatInputModule, + Grid, + GridRow, + GridCell, + GridCellWidget, + GridChips, + ], +}) +export class GridTableExample { + readonly employees = [ + 'Sudo Sloth', + 'Copy-Pasta Capybara', + 'Rubber Duck', + 'Caffeinated Owl', + 'Patch Monkey', + ]; + + readonly allSelected: Signal = computed(() => this.tasks().every(t => t.selected())); + + readonly partiallySelected: Signal = computed( + () => this.tasks().some(t => t.selected()) && !this.allSelected(), + ); + + readonly tempInput: WritableSignal = signal(''); + + readonly tasks: WritableSignal = signal(this._createRows()); + + constructor() {} + + startEdit( + event: KeyboardEvent | FocusEvent | undefined, + task: TaskRow, + inputEl: HTMLInputElement, + ): void { + this.tempInput.set(task.summary()); + inputEl.focus(); + + if (!(event instanceof KeyboardEvent)) return; + + // Start editing with a alphanumeric character. + if (event.key.length === 1) { + this.tempInput.set(event.key); + } + } + + onClickEdit(widget: GridCellWidget, task: TaskRow, inputEl: HTMLInputElement) { + if (widget.isActivated()) return; + + widget.activate(); + setTimeout(() => this.startEdit(undefined, task, inputEl)); + } + + completeEdit(event: KeyboardEvent | FocusEvent | undefined, task: TaskRow): void { + if (!(event instanceof KeyboardEvent)) { + return; + } + if (event.key === 'Enter') { + task.summary.set(this.tempInput()); + } + } + + updateSelection(checked: boolean): void { + this.tasks().forEach(t => t.selected.set(checked)); + } + + addTag(event: KeyboardEvent | FocusEvent | undefined, task: TaskRow, inputEl: HTMLInputElement) { + if (event instanceof KeyboardEvent && event.key === 'Enter') { + const value = inputEl.value; + if (value.length > 0) { + task.tags.set([...task.tags(), value]); + } + } + inputEl.value = ''; + } + + private _createRows(): TaskRow[] { + return [ + { + selected: signal(false), + summary: signal('Repairing the coffee machine'), + assignee: signal('Caffeinated Owl'), + tags: signal(['P0']), + }, + { + selected: signal(false), + summary: signal('Burying technical debt in the backyard so no one finds it'), + assignee: signal(''), + tags: signal(['tech-debt', 'P3']), + }, + { + selected: signal(false), + summary: signal('Hibernating under the standing desk until the outage is resolved'), + assignee: signal(''), + tags: signal([]), + }, + { + selected: signal(false), + summary: signal('Hunting down the Uber Eats driver who got lost in the lobby'), + assignee: signal('Sudo Sloth'), + tags: signal(['lunch']), + }, + ]; + } +} diff --git a/src/components-examples/aria/grid/index.ts b/src/components-examples/aria/grid/index.ts index 713726afa907..d9fb3bd38aae 100644 --- a/src/components-examples/aria/grid/index.ts +++ b/src/components-examples/aria/grid/index.ts @@ -1,2 +1,4 @@ export {GridConfigurableExample} from './grid-configurable/grid-configurable-example'; export {GridPillListExample} from './grid-pill-list/grid-pill-list-example'; +export {GridCalendarExample} from './grid-calendar/grid-calendar-example'; +export {GridTableExample} from './grid-table/grid-table-example'; diff --git a/src/components-examples/aria/listbox/listbox-active-descendant/listbox-active-descendant-example.html b/src/components-examples/aria/listbox/listbox-active-descendant/listbox-active-descendant-example.html index 3380d0d60568..407824fa79b1 100644 --- a/src/components-examples/aria/listbox/listbox-active-descendant/listbox-active-descendant-example.html +++ b/src/components-examples/aria/listbox/listbox-active-descendant/listbox-active-descendant-example.html @@ -15,7 +15,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.html b/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.html index 8d467ca37354..e979b8fb8fd3 100644 --- a/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.html +++ b/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.html @@ -3,7 +3,7 @@ Multi Disabled Readonly - Skip Disabled + Soft Disabled Selection @@ -52,12 +52,12 @@
          {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.ts b/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.ts index 167f579884f6..23dcf34e6c4b 100644 --- a/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.ts +++ b/src/components-examples/aria/listbox/listbox-configurable/listbox-configurable-example.ts @@ -33,7 +33,7 @@ export class ListboxConfigurableExample { multi = new FormControl(true, {nonNullable: true}); disabled = new FormControl(false, {nonNullable: true}); readonly = new FormControl(false, {nonNullable: true}); - skipDisabled = new FormControl(true, {nonNullable: true}); + softDisabled = new FormControl(false, {nonNullable: true}); fruits = [ 'Apple', diff --git a/src/components-examples/aria/listbox/listbox-disabled-focusable/listbox-disabled-focusable-example.html b/src/components-examples/aria/listbox/listbox-disabled-focusable/listbox-disabled-focusable-example.html index 9fa9e9e4fe8c..a8a4dcf9a179 100644 --- a/src/components-examples/aria/listbox/listbox-disabled-focusable/listbox-disabled-focusable-example.html +++ b/src/components-examples/aria/listbox/listbox-disabled-focusable/listbox-disabled-focusable-example.html @@ -2,7 +2,7 @@
            @@ -16,7 +16,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-disabled-skipped/listbox-disabled-skipped-example.html b/src/components-examples/aria/listbox/listbox-disabled-skipped/listbox-disabled-skipped-example.html index cc3c97192a77..3976e66360cd 100644 --- a/src/components-examples/aria/listbox/listbox-disabled-skipped/listbox-disabled-skipped-example.html +++ b/src/components-examples/aria/listbox/listbox-disabled-skipped/listbox-disabled-skipped-example.html @@ -2,7 +2,7 @@
              @@ -16,7 +16,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-disabled/listbox-disabled-example.html b/src/components-examples/aria/listbox/listbox-disabled/listbox-disabled-example.html index d7b24b44f1a7..cf5f32184b0a 100644 --- a/src/components-examples/aria/listbox/listbox-disabled/listbox-disabled-example.html +++ b/src/components-examples/aria/listbox/listbox-disabled/listbox-disabled-example.html @@ -14,7 +14,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-horizontal/listbox-horizontal-example.html b/src/components-examples/aria/listbox/listbox-horizontal/listbox-horizontal-example.html index f67f0e5669d0..b58b0f4f1024 100644 --- a/src/components-examples/aria/listbox/listbox-horizontal/listbox-horizontal-example.html +++ b/src/components-examples/aria/listbox/listbox-horizontal/listbox-horizontal-example.html @@ -15,7 +15,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-multi-select-follow-focus/listbox-multi-select-follow-focus-example.html b/src/components-examples/aria/listbox/listbox-multi-select-follow-focus/listbox-multi-select-follow-focus-example.html index 5ee2efc48739..6d6d9ca6e133 100644 --- a/src/components-examples/aria/listbox/listbox-multi-select-follow-focus/listbox-multi-select-follow-focus-example.html +++ b/src/components-examples/aria/listbox/listbox-multi-select-follow-focus/listbox-multi-select-follow-focus-example.html @@ -16,7 +16,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-multi-select/listbox-multi-select-example.html b/src/components-examples/aria/listbox/listbox-multi-select/listbox-multi-select-example.html index 2268a7e97a10..7fba7b051aae 100644 --- a/src/components-examples/aria/listbox/listbox-multi-select/listbox-multi-select-example.html +++ b/src/components-examples/aria/listbox/listbox-multi-select/listbox-multi-select-example.html @@ -16,7 +16,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-readonly/listbox-readonly-example.html b/src/components-examples/aria/listbox/listbox-readonly/listbox-readonly-example.html index 13a76475f7e2..4a412f4fa767 100644 --- a/src/components-examples/aria/listbox/listbox-readonly/listbox-readonly-example.html +++ b/src/components-examples/aria/listbox/listbox-readonly/listbox-readonly-example.html @@ -15,7 +15,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-rtl-horizontal/listbox-rtl-horizontal-example.html b/src/components-examples/aria/listbox/listbox-rtl-horizontal/listbox-rtl-horizontal-example.html index 1fd90d8f30e7..1377a5e9aa8b 100644 --- a/src/components-examples/aria/listbox/listbox-rtl-horizontal/listbox-rtl-horizontal-example.html +++ b/src/components-examples/aria/listbox/listbox-rtl-horizontal/listbox-rtl-horizontal-example.html @@ -15,7 +15,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-single-select-follow-focus/listbox-single-select-follow-focus-example.html b/src/components-examples/aria/listbox/listbox-single-select-follow-focus/listbox-single-select-follow-focus-example.html index 69fcccf66db6..4d2d93d5ffd7 100644 --- a/src/components-examples/aria/listbox/listbox-single-select-follow-focus/listbox-single-select-follow-focus-example.html +++ b/src/components-examples/aria/listbox/listbox-single-select-follow-focus/listbox-single-select-follow-focus-example.html @@ -16,7 +16,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/listbox/listbox-single-select/listbox-single-select-example.html b/src/components-examples/aria/listbox/listbox-single-select/listbox-single-select-example.html index b26b3bad68fb..41694d4a096a 100644 --- a/src/components-examples/aria/listbox/listbox-single-select/listbox-single-select-example.html +++ b/src/components-examples/aria/listbox/listbox-single-select/listbox-single-select-example.html @@ -16,7 +16,7 @@ #option="ngOption" > {{ fruit }} diff --git a/src/components-examples/aria/menu/BUILD.bazel b/src/components-examples/aria/menu/BUILD.bazel index 3b006c241567..548211a6572c 100644 --- a/src/components-examples/aria/menu/BUILD.bazel +++ b/src/components-examples/aria/menu/BUILD.bazel @@ -12,6 +12,8 @@ ng_project( deps = [ "//:node_modules/@angular/core", "//src/aria/menu", + "//src/cdk/a11y", + "//src/cdk/overlay", ], ) diff --git a/src/components-examples/aria/menu/index.ts b/src/components-examples/aria/menu/index.ts index fd502b060d90..e5afd68153a5 100644 --- a/src/components-examples/aria/menu/index.ts +++ b/src/components-examples/aria/menu/index.ts @@ -1,4 +1,5 @@ -export {MenuBarExample} from './menu-bar/menu-bar-example'; export {MenuContextExample} from './menu-context/menu-context-example'; export {MenuTriggerExample} from './menu-trigger/menu-trigger-example'; +export {MenuTriggerDisabledExample} from './menu-trigger-disabled/menu-trigger-disabled-example'; export {MenuStandaloneExample} from './menu-standalone/menu-standalone-example'; +export {MenuStandaloneDisabledExample} from './menu-standalone-disabled/menu-standalone-disabled-example'; diff --git a/src/components-examples/aria/menu/menu-bar/menu-bar-example.html b/src/components-examples/aria/menu/menu-bar/menu-bar-example.html deleted file mode 100644 index 5b772ddf3e91..000000000000 --- a/src/components-examples/aria/menu/menu-bar/menu-bar-example.html +++ /dev/null @@ -1,300 +0,0 @@ -
              -
              File
              - -
              -
              - article - New - ⌘N -
              - -
              - folder - Open - ⌘O -
              - -
              - file_copy - Make a copy -
              - - - -
              - person_add - Share - arrow_right -
              - -
              -
              - person_add - Share with others -
              - -
              - public - Publish to web -
              -
              - -
              - download - Download -
              - -
              - print - Print -
              - - - -
              - edit - Rename -
              - -
              - delete - Move to trash -
              -
              - -
              Edit
              - -
              -
              - undo - Undo - ⌘Z -
              - -
              - redo - Redo - ⌘Y -
              - - - -
              - content_cut - Cut - ⌘X -
              - -
              - content_copy - Copy - ⌘C -
              - -
              - content_paste - Paste - ⌘V -
              - - - -
              - find_replace - Find and replace - ⇧⌘H -
              -
              - -
              View
              - -
              -
              - check - Show print layout -
              - -
              - check - Show ruler -
              - - - -
              - Zoom in - ⌘+ -
              - -
              - Zoom out - ⌘- -
              - - - -
              - Full screen -
              -
              - -
              Insert
              - -
              -
              - image - Image - arrow_right -
              - -
              -
              - upload - Upload from computer -
              - -
              - search - Search the web -
              - -
              - link - By URL -
              -
              - -
              - table_chart - Table -
              - -
              - insert_chart - Chart - arrow_right -
              - -
              -
              - bar_chart - Bar -
              - -
              - insert_chart - Column -
              - -
              - show_chart - Line -
              - -
              - pie_chart - Pie -
              -
              - -
              - horizontal_rule - Horizontal line -
              -
              - -
              Format
              - -
              -
              - format_bold - Text - arrow_right -
              - -
              -
              - format_bold - Bold - ⌘B -
              - -
              - format_italic - Italic - ⌘I -
              - -
              - format_underlined - Underline - ⌘U -
              - -
              - strikethrough_s - Strikethrough - ⇧⌘X -
              - - - -
              - Size - arrow_right -
              - -
              -
              - Increase font size - ⇧⌘. -
              - -
              - Decrease font size - ⇧⌘, -
              -
              -
              - -
              - format_align_justify - Paragraph styles - arrow_right -
              - -
              -
              Normal text
              -
              Heading 1
              -
              Heading 2
              -
              - -
              - format_indent_increase - Align & indent - arrow_right -
              - -
              -
              - format_align_left - Align left -
              - -
              - format_align_center - Align center -
              - -
              - format_align_right - Align right -
              - -
              - format_align_justify - Justify -
              -
              -
              -
              diff --git a/src/components-examples/aria/menu/menu-bar/menu-bar-example.ts b/src/components-examples/aria/menu/menu-bar/menu-bar-example.ts deleted file mode 100644 index fd3aa5768f7d..000000000000 --- a/src/components-examples/aria/menu/menu-bar/menu-bar-example.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {Component} from '@angular/core'; -import { - SimpleMenu, - SimpleMenuBar, - SimpleMenuBarItem, - SimpleMenuItem, - SimpleMenuItemIcon, - SimpleMenuItemShortcut, - SimpleMenuItemText, -} from '../simple-menu'; - -/** @title Menu bar example. */ -@Component({ - selector: 'menu-bar-example', - exportAs: 'MenuBarExample', - templateUrl: 'menu-bar-example.html', - styleUrl: '../menu-example.css', - standalone: true, - imports: [ - SimpleMenu, - SimpleMenuBar, - SimpleMenuBarItem, - SimpleMenuItem, - SimpleMenuItemIcon, - SimpleMenuItemText, - SimpleMenuItemShortcut, - ], -}) -export class MenuBarExample {} diff --git a/src/components-examples/aria/menu/menu-context/menu-context-example.html b/src/components-examples/aria/menu/menu-context/menu-context-example.html index 7505025ffd42..cf2ee2fea501 100644 --- a/src/components-examples/aria/menu/menu-context/menu-context-example.html +++ b/src/components-examples/aria/menu/menu-context/menu-context-example.html @@ -3,39 +3,43 @@
            -
            - content_cut - Cut - ⌘X -
            - -
            - content_copy - Copy - ⌘C -
            + +
            + content_cut + Cut + ⌘X +
            -
            - content_paste - Paste - arrow_right -
            +
            + content_copy + Copy + ⌘C +
            -
            -
            - Paste as plain text - ⌘⇧V +
            + content_paste + Paste + arrow_right
            -
            - Paste without formatting - ⌘⇧V +
            + +
            + Paste as plain text + ⌘⇧V +
            + +
            + Paste without formatting + ⌘⇧V +
            +
            -
            +
            diff --git a/src/components-examples/aria/menu/menu-context/menu-context-example.ts b/src/components-examples/aria/menu/menu-context/menu-context-example.ts index e265c393cf05..a484b5f3f5da 100644 --- a/src/components-examples/aria/menu/menu-context/menu-context-example.ts +++ b/src/components-examples/aria/menu/menu-context/menu-context-example.ts @@ -1,5 +1,5 @@ import {Component, viewChild} from '@angular/core'; -import {Menu} from '@angular/aria/menu'; +import {Menu, MenuContent} from '@angular/aria/menu'; import { SimpleMenu, SimpleMenuItem, @@ -11,16 +11,15 @@ import { /** @title Context menu example. */ @Component({ selector: 'menu-context-example', - exportAs: 'MenuContextExample', templateUrl: 'menu-context-example.html', styleUrl: '../menu-example.css', - standalone: true, imports: [ SimpleMenu, SimpleMenuItem, SimpleMenuItemText, SimpleMenuItemIcon, SimpleMenuItemShortcut, + MenuContent, ], }) export class MenuContextExample { @@ -38,7 +37,7 @@ export class MenuContextExample { open(event: MouseEvent) { const menu = this.menu(); - menu?.closeAll(); + menu?._pattern.closeAll(); if (menu) { event.preventDefault(); @@ -47,7 +46,7 @@ export class MenuContextExample { menu.element.style.top = `${event.clientY}px`; menu.element.style.left = `${event.clientX}px`; - setTimeout(() => menu.uiPattern.first()); + setTimeout(() => menu._pattern.first()); } } } diff --git a/src/components-examples/aria/menu/menu-example.css b/src/components-examples/aria/menu/menu-example.css index f5fb288f91ec..6aaf76c9d91a 100644 --- a/src/components-examples/aria/menu/menu-example.css +++ b/src/components-examples/aria/menu/menu-example.css @@ -22,6 +22,7 @@ } .example-menu[popover] { + left: auto; position: absolute; } @@ -42,6 +43,13 @@ border-radius: var(--mat-sys-corner-extra-small); } +.example-menu-item[aria-disabled='true'], +.example-menu-trigger[aria-disabled='true'], +.example-menu-bar-item[aria-disabled='true'] { + cursor: default; + opacity: 0.38; +} + .example-menu-heading { display: block; font-weight: bold; @@ -83,11 +91,6 @@ outline: 2px solid var(--mat-sys-primary); } -.example-menu-item[aria-disabled='true'] { - cursor: default; - opacity: 0.38; -} - .example-icon { opacity: 0.875; font-size: 1.25rem; diff --git a/src/components-examples/aria/menu/menu-standalone-disabled/menu-standalone-disabled-example.html b/src/components-examples/aria/menu/menu-standalone-disabled/menu-standalone-disabled-example.html new file mode 100644 index 000000000000..9f835ce855c4 --- /dev/null +++ b/src/components-examples/aria/menu/menu-standalone-disabled/menu-standalone-disabled-example.html @@ -0,0 +1,65 @@ +
            + + SECURITY + +
            +
            + lock_open + Change password +
            + +
            + security_key + Two-factor authentication +
            + +
            + refresh + Reset + arrow_right +
            + +
            + +
            + email + Email address +
            + +
            + phone + Phone number +
            + +
            + vpn_key + Password +
            +
            +
            +
            + + + + HELP + +
            +
            + help + Support +
            + +
            + feedback + Feedback +
            +
            + + + +
            + logout + Logout +
            +
            +
            diff --git a/src/components-examples/aria/menu/menu-standalone-disabled/menu-standalone-disabled-example.ts b/src/components-examples/aria/menu/menu-standalone-disabled/menu-standalone-disabled-example.ts new file mode 100644 index 000000000000..8de16e276329 --- /dev/null +++ b/src/components-examples/aria/menu/menu-standalone-disabled/menu-standalone-disabled-example.ts @@ -0,0 +1,14 @@ +import {Component} from '@angular/core'; +import {Menu, MenuContent} from '@angular/aria/menu'; +import {SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText} from '../simple-menu'; + +/** + * @title Disabled standalone menu example. + */ +@Component({ + selector: 'menu-standalone-disabled-example', + templateUrl: 'menu-standalone-disabled-example.html', + styleUrl: '../menu-example.css', + imports: [Menu, MenuContent, SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText], +}) +export class MenuStandaloneDisabledExample {} diff --git a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html index 6a3419830193..ad7fd866e21b 100644 --- a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html +++ b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html @@ -1,61 +1,65 @@
            - SECURITY + + SECURITY -
            -
            - lock_open - Change password -
            - -
            - security_key - Two-factor authentication -
            - -
            - refresh - Reset - arrow_right -
            +
            +
            + lock_open + Change password +
            -
            -
            - email - Email address +
            + security_key + Two-factor authentication
            -
            - phone - Phone number +
            + refresh + Reset + arrow_right
            -
            - vpn_key - Password +
            + +
            + email + Email address +
            + +
            + phone + Phone number +
            + +
            + vpn_key + Password +
            +
            -
            - + - HELP + HELP -
            -
            - help - Support -
            +
            +
            + help + Support +
            -
            - feedback - Feedback +
            + feedback + Feedback +
            -
            - + -
            - logout - Logout -
            +
            + logout + Logout +
            +
            diff --git a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.ts b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.ts index e2c12304b18a..e3cc7486db41 100644 --- a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.ts +++ b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.ts @@ -1,5 +1,5 @@ import {Component} from '@angular/core'; -import {Menu} from '@angular/aria/menu'; +import {Menu, MenuContent} from '@angular/aria/menu'; import {SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText} from '../simple-menu'; /** @@ -7,10 +7,8 @@ import {SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText} from */ @Component({ selector: 'menu-standalone-example', - exportAs: 'MenuStandaloneExample', templateUrl: 'menu-standalone-example.html', styleUrl: '../menu-example.css', - standalone: true, - imports: [Menu, SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText], + imports: [Menu, MenuContent, SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText], }) export class MenuStandaloneExample {} diff --git a/src/components-examples/aria/menu/menu-trigger-disabled/menu-trigger-disabled-example.html b/src/components-examples/aria/menu/menu-trigger-disabled/menu-trigger-disabled-example.html new file mode 100644 index 000000000000..571e8cf0dfad --- /dev/null +++ b/src/components-examples/aria/menu/menu-trigger-disabled/menu-trigger-disabled-example.html @@ -0,0 +1,67 @@ + + +
            + +
            + mark_email_read + Mark as read +
            + +
            + snooze + Snooze +
            + + + +
            + category + Categorize + arrow_right +
            + +
            + +
            + label_important + Mark as important +
            + +
            + star + Star +
            + +
            + label + Label +
            +
            +
            + + + +
            + archive + Archive +
            + +
            + report + Report spam +
            + +
            + delete + Delete +
            +
            +
            diff --git a/src/components-examples/aria/menu/menu-trigger-disabled/menu-trigger-disabled-example.ts b/src/components-examples/aria/menu/menu-trigger-disabled/menu-trigger-disabled-example.ts new file mode 100644 index 000000000000..e8eb4322e67b --- /dev/null +++ b/src/components-examples/aria/menu/menu-trigger-disabled/menu-trigger-disabled-example.ts @@ -0,0 +1,19 @@ +import {Component} from '@angular/core'; +import {MenuTrigger, MenuContent} from '@angular/aria/menu'; +import {SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText} from '../simple-menu'; + +/** @title Menu trigger example. */ +@Component({ + selector: 'menu-trigger-disabled-example', + templateUrl: 'menu-trigger-disabled-example.html', + styleUrl: '../menu-example.css', + imports: [ + MenuContent, + MenuTrigger, + SimpleMenu, + SimpleMenuItem, + SimpleMenuItemIcon, + SimpleMenuItemText, + ], +}) +export class MenuTriggerDisabledExample {} diff --git a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html index 4c857c37e6ca..686b5d81b85e 100644 --- a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html +++ b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html @@ -1,63 +1,66 @@ -
            -
            - mark_email_read - Mark as read -
            - -
            - snooze - Snooze -
            - - - -
            - category - Categorize - arrow_right -
            - -
            -
            - label_important - Mark as important +
            + +
            + mark_email_read + Mark as read
            -
            - star - Star +
            + snooze + Snooze
            -
            - label - Label + + +
            + category + Categorize + arrow_right +
            + +
            + +
            + label_important + Mark as important +
            + +
            + star + Star +
            + +
            + label + Label +
            +
            -
            - + -
            - archive - Archive -
            +
            + archive + Archive +
            -
            - report - Report spam -
            +
            + report + Report spam +
            -
            - delete - Delete -
            +
            + delete + Delete +
            +
            diff --git a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.ts b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.ts index 0cf84e867441..49cf9aa69145 100644 --- a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.ts +++ b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.ts @@ -1,14 +1,19 @@ import {Component} from '@angular/core'; -import {MenuTrigger} from '@angular/aria/menu'; +import {MenuTrigger, MenuContent} from '@angular/aria/menu'; import {SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText} from '../simple-menu'; /** @title Menu trigger example. */ @Component({ selector: 'menu-trigger-example', - exportAs: 'MenuTriggerExample', templateUrl: 'menu-trigger-example.html', styleUrl: '../menu-example.css', - standalone: true, - imports: [SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText, MenuTrigger], + imports: [ + MenuContent, + MenuTrigger, + SimpleMenu, + SimpleMenuItem, + SimpleMenuItemIcon, + SimpleMenuItemText, + ], }) export class MenuTriggerExample {} diff --git a/src/components-examples/aria/menu/simple-menu.ts b/src/components-examples/aria/menu/simple-menu.ts index 17af13190dfc..87a71501ff71 100644 --- a/src/components-examples/aria/menu/simple-menu.ts +++ b/src/components-examples/aria/menu/simple-menu.ts @@ -2,8 +2,8 @@ import {Menu, MenuBar, MenuItem, MenuTrigger} from '@angular/aria/menu'; import {afterRenderEffect, Directive, effect, inject} from '@angular/core'; @Directive({ - selector: '[menu]', - hostDirectives: [{directive: Menu, inputs: ['parent']}], + selector: '[ng-menu]', + hostDirectives: [{directive: Menu}], host: { class: 'example-menu', popover: 'manual', @@ -15,7 +15,7 @@ export class SimpleMenu { constructor() { afterRenderEffect(() => { - this.menu.isVisible() ? this.menu.element.showPopover() : this.menu.element.hidePopover(); + this.menu.visible() ? this.menu.element.showPopover() : this.menu.element.hidePopover(); }); } @@ -28,6 +28,7 @@ export class SimpleMenu { const parentEl = parent.element; const parentRect = parentEl.getBoundingClientRect(); + const menuRect = this.menu.element.getBoundingClientRect(); const scrollX = window.scrollX; const scrollY = window.scrollY; @@ -36,28 +37,31 @@ export class SimpleMenu { const bottom = parentRect.y + scrollY + parentRect.height + 6; if (parent.parent instanceof MenuBar) { - this.menu.element.style.left = `${parentRect.left + scrollX}px`; + const rtlOffset = this.menu.textDirection() === 'rtl' ? menuRect.width - parentRect.width : 0; + this.menu.element.style.left = `${parentRect.left + scrollX - rtlOffset}px`; this.menu.element.style.top = `${bottom}px`; } else if (parent instanceof MenuTrigger) { this.menu.element.style.left = `${parentRect.left + scrollX}px`; this.menu.element.style.top = `${parentRect.bottom + scrollY + 2}px`; } else { - this.menu.element.style.left = `${parentRect.right + scrollX + 6}px`; + const rtlOffset = + this.menu.textDirection() === 'rtl' ? menuRect.width + parentRect.width + 12 : 0; + this.menu.element.style.left = `${parentRect.right + scrollX + 6 - rtlOffset}px`; this.menu.element.style.top = `${top}px`; } } } @Directive({ - selector: '[menu-bar]', - hostDirectives: [{directive: MenuBar}], + selector: '[ng-menu-bar]', + hostDirectives: [{directive: MenuBar, inputs: ['disabled']}], host: {class: 'example-menu-bar'}, }) export class SimpleMenuBar {} @Directive({ - selector: '[menu-bar-item]', - hostDirectives: [{directive: MenuItem, inputs: ['value', 'submenu']}], + selector: '[ng-menu-bar-item]', + hostDirectives: [{directive: MenuItem, inputs: ['value', 'submenu', 'disabled']}], host: {class: 'example-menu-bar-item'}, }) export class SimpleMenuBarItem { @@ -69,7 +73,7 @@ export class SimpleMenuBarItem { } @Directive({ - selector: '[menu-item]', + selector: '[ng-menu-item]', hostDirectives: [{directive: MenuItem, inputs: ['value', 'disabled', 'submenu']}], host: {class: 'example-menu-item'}, }) @@ -82,7 +86,7 @@ export class SimpleMenuItem { } @Directive({ - selector: '[menu-item-icon]', + selector: '[ng-menu-item-icon]', host: { 'aria-hidden': 'true', class: 'example-icon material-symbols-outlined', @@ -91,13 +95,13 @@ export class SimpleMenuItem { export class SimpleMenuItemIcon {} @Directive({ - selector: '[menu-item-text]', + selector: '[ng-menu-item-text]', host: {class: 'example-menu-item-text'}, }) export class SimpleMenuItemText {} @Directive({ - selector: '[menu-item-shortcut]', + selector: '[ng-menu-item-shortcut]', host: { 'aria-hidden': 'true', class: 'example-menu-item-shortcut', diff --git a/src/components-examples/aria/menubar/BUILD.bazel b/src/components-examples/aria/menubar/BUILD.bazel new file mode 100644 index 000000000000..0bf9ca6cfb55 --- /dev/null +++ b/src/components-examples/aria/menubar/BUILD.bazel @@ -0,0 +1,27 @@ +load("//tools:defaults.bzl", "ng_project") + +package(default_visibility = ["//visibility:public"]) + +ng_project( + name = "menubar", + srcs = glob(["**/*.ts"]), + assets = glob([ + "**/*.html", + "**/*.css", + ]), + deps = [ + "//:node_modules/@angular/core", + "//src/aria/menu", + "//src/cdk/a11y", + "//src/cdk/overlay", + ], +) + +filegroup( + name = "source-files", + srcs = glob([ + "**/*.html", + "**/*.css", + "**/*.ts", + ]), +) diff --git a/src/components-examples/aria/menubar/index.ts b/src/components-examples/aria/menubar/index.ts new file mode 100644 index 000000000000..bc22b6308940 --- /dev/null +++ b/src/components-examples/aria/menubar/index.ts @@ -0,0 +1,3 @@ +export {MenuBarExample} from './menubar/menubar-example'; +export {MenuBarRTLExample} from './menubar-rtl/menubar-rtl-example'; +export {MenuBarDisabledExample} from './menubar-disabled/menubar-disabled-example'; diff --git a/src/components-examples/aria/menubar/menubar-disabled/menubar-disabled-example.html b/src/components-examples/aria/menubar/menubar-disabled/menubar-disabled-example.html new file mode 100644 index 000000000000..f12ccbaa7379 --- /dev/null +++ b/src/components-examples/aria/menubar/menubar-disabled/menubar-disabled-example.html @@ -0,0 +1,459 @@ +
            + + + +
            + +
            + article + New + ⌘N +
            + +
            + folder + Open + ⌘O +
            + +
            + file_copy + Make a copy +
            + + + +
            + person_add + Share + arrow_right +
            + + +
            + +
            + person_add + Share with others +
            + +
            + public + Publish to web +
            +
            +
            +
            + +
            + download + Download +
            + +
            + print + Print +
            + + + +
            + edit + Rename +
            + +
            + delete + Move to trash +
            +
            +
            +
            + + + + +
            + +
            + undo + Undo + ⌘Z +
            + +
            + redo + Redo + ⌘Y +
            + + + +
            + content_cut + Cut + ⌘X +
            + +
            + content_copy + Copy + ⌘C +
            + +
            + content_paste + Paste + ⌘V +
            + + + +
            + find_replace + Find and replace + ⇧⌘H +
            +
            +
            +
            + + + + +
            + +
            + check + Show print layout +
            + +
            + check + Show ruler +
            + + + +
            + Zoom in + ⌘+ +
            + +
            + Zoom out + ⌘- +
            + + + +
            + Full screen +
            +
            +
            +
            + + + + +
            + +
            + image + Image + arrow_right +
            + + +
            + +
            + upload + Upload from computer +
            + +
            + search + Search the web +
            + +
            + link + By URL +
            +
            +
            +
            + +
            + table_chart + Table +
            + +
            + insert_chart + Chart + arrow_right +
            + + +
            + +
            + bar_chart + Bar +
            + +
            + insert_chart + Column +
            + +
            + show_chart + Line +
            + +
            + pie_chart + Pie +
            +
            +
            +
            + +
            + horizontal_rule + Horizontal line +
            +
            +
            +
            + + + + +
            + +
            + format_bold + Text + arrow_right +
            + + +
            + +
            + format_bold + Bold + ⌘B +
            + +
            + format_italic + Italic + ⌘I +
            + +
            + format_underlined + Underline + ⌘U +
            + +
            + strikethrough_s + Strikethrough + ⇧⌘X +
            + + + +
            + Size + arrow_right +
            + + +
            + +
            + Increase font size + ⇧⌘. +
            + +
            + Decrease font size + ⇧⌘, +
            +
            +
            +
            +
            +
            +
            + +
            + format_align_justify + Paragraph styles + arrow_right +
            + + +
            + +
            Normal text
            +
            Heading 1
            +
            Heading 2
            +
            +
            +
            + +
            + format_indent_increase + Align & indent + arrow_right +
            + + +
            + +
            + format_align_left + Align left +
            + +
            + format_align_center + Align center +
            + +
            + format_align_right + Align right +
            + +
            + format_align_justify + Justify +
            +
            +
            +
            +
            +
            +
            +
            diff --git a/src/components-examples/aria/menubar/menubar-disabled/menubar-disabled-example.ts b/src/components-examples/aria/menubar/menubar-disabled/menubar-disabled-example.ts new file mode 100644 index 000000000000..ac86d74ba45f --- /dev/null +++ b/src/components-examples/aria/menubar/menubar-disabled/menubar-disabled-example.ts @@ -0,0 +1,25 @@ +import {Component, viewChild} from '@angular/core'; +import {Menu, MenuBar, MenuContent, MenuItem} from '@angular/aria/menu'; +import {OverlayModule} from '@angular/cdk/overlay'; + +/** @title Menu bar disabled example. */ +@Component({ + selector: 'menubar-disabled-example', + templateUrl: 'menubar-disabled-example.html', + styleUrl: '../menubar.css', + imports: [Menu, MenuBar, MenuItem, MenuContent, OverlayModule], +}) +export class MenuBarDisabledExample { + fileMenu = viewChild>('fileMenu'); + shareMenu = viewChild>('shareMenu'); + editMenu = viewChild>('editMenu'); + viewMenu = viewChild>('viewMenu'); + insertMenu = viewChild>('insertMenu'); + imageMenu = viewChild>('imageMenu'); + chartMenu = viewChild>('chartMenu'); + formatMenu = viewChild>('formatMenu'); + textMenu = viewChild>('textMenu'); + sizeMenu = viewChild>('sizeMenu'); + paragraphMenu = viewChild>('paragraphMenu'); + alignMenu = viewChild>('alignMenu'); +} diff --git a/src/components-examples/aria/menubar/menubar-rtl/menubar-rtl-example.html b/src/components-examples/aria/menubar/menubar-rtl/menubar-rtl-example.html new file mode 100644 index 000000000000..1c8a8a3c2868 --- /dev/null +++ b/src/components-examples/aria/menubar/menubar-rtl/menubar-rtl-example.html @@ -0,0 +1,459 @@ +
            + + + +
            + +
            + article + New + ⌘N +
            + +
            + folder + Open + ⌘O +
            + +
            + file_copy + Make a copy +
            + + + +
            + person_add + Share + arrow_left +
            + + +
            + +
            + person_add + Share with others +
            + +
            + public + Publish to web +
            +
            +
            +
            + +
            + download + Download +
            + +
            + print + Print +
            + + + +
            + edit + Rename +
            + +
            + delete + Move to trash +
            +
            +
            +
            + + + + +
            + +
            + undo + Undo + ⌘Z +
            + +
            + redo + Redo + ⌘Y +
            + + + +
            + content_cut + Cut + ⌘X +
            + +
            + content_copy + Copy + ⌘C +
            + +
            + content_paste + Paste + ⌘V +
            + + + +
            + find_replace + Find and replace + ⇧⌘H +
            +
            +
            +
            + + + + +
            + +
            + check + Show print layout +
            + +
            + check + Show ruler +
            + + + +
            + Zoom in + ⌘+ +
            + +
            + Zoom out + ⌘- +
            + + + +
            + Full screen +
            +
            +
            +
            + + + + +
            + +
            + image + Image + arrow_left +
            + + +
            + +
            + upload + Upload from computer +
            + +
            + search + Search the web +
            + +
            + link + By URL +
            +
            +
            +
            + +
            + table_chart + Table +
            + +
            + insert_chart + Chart + arrow_left +
            + + +
            + +
            + bar_chart + Bar +
            + +
            + insert_chart + Column +
            + +
            + show_chart + Line +
            + +
            + pie_chart + Pie +
            +
            +
            +
            + +
            + horizontal_rule + Horizontal line +
            +
            +
            +
            + + + + +
            + +
            + format_bold + Text + arrow_left +
            + + +
            + +
            + format_bold + Bold + ⌘B +
            + +
            + format_italic + Italic + ⌘I +
            + +
            + format_underlined + Underline + ⌘U +
            + +
            + strikethrough_s + Strikethrough + ⇧⌘X +
            + + + +
            + Size + arrow_left +
            + + +
            + +
            + Increase font size + ⇧⌘. +
            + +
            + Decrease font size + ⇧⌘, +
            +
            +
            +
            +
            +
            +
            + +
            + format_align_justify + Paragraph styles + arrow_left +
            + + +
            + +
            Normal text
            +
            Heading 1
            +
            Heading 2
            +
            +
            +
            + +
            + format_indent_increase + Align & indent + arrow_left +
            + + +
            + +
            + format_align_left + Align left +
            + +
            + format_align_center + Align center +
            + +
            + format_align_right + Align right +
            + +
            + format_align_justify + Justify +
            +
            +
            +
            +
            +
            +
            +
            diff --git a/src/components-examples/aria/menubar/menubar-rtl/menubar-rtl-example.ts b/src/components-examples/aria/menubar/menubar-rtl/menubar-rtl-example.ts new file mode 100644 index 000000000000..368eaf8d7ea2 --- /dev/null +++ b/src/components-examples/aria/menubar/menubar-rtl/menubar-rtl-example.ts @@ -0,0 +1,26 @@ +import {Dir} from '@angular/cdk/bidi'; +import {Component, viewChild} from '@angular/core'; +import {Menu, MenuBar, MenuContent, MenuItem} from '@angular/aria/menu'; +import {OverlayModule} from '@angular/cdk/overlay'; + +/** @title Menu bar RTL example. */ +@Component({ + selector: 'menubar-rtl-example', + templateUrl: 'menubar-rtl-example.html', + styleUrl: '../menubar.css', + imports: [Dir, Menu, MenuBar, MenuItem, MenuContent, OverlayModule], +}) +export class MenuBarRTLExample { + fileMenu = viewChild>('fileMenu'); + shareMenu = viewChild>('shareMenu'); + editMenu = viewChild>('editMenu'); + viewMenu = viewChild>('viewMenu'); + insertMenu = viewChild>('insertMenu'); + imageMenu = viewChild>('imageMenu'); + chartMenu = viewChild>('chartMenu'); + formatMenu = viewChild>('formatMenu'); + textMenu = viewChild>('textMenu'); + sizeMenu = viewChild>('sizeMenu'); + paragraphMenu = viewChild>('paragraphMenu'); + alignMenu = viewChild>('alignMenu'); +} diff --git a/src/components-examples/aria/menubar/menubar.css b/src/components-examples/aria/menubar/menubar.css new file mode 100644 index 000000000000..59050cb8a0de --- /dev/null +++ b/src/components-examples/aria/menubar/menubar.css @@ -0,0 +1,80 @@ +:host { + --border-color: color-mix(in srgb, var(--mat-sys-outline) 40%, transparent); +} + +[ngMenuBar] { + display: flex; + gap: 0.25rem; + padding: 0.25rem; + border-radius: var(--mat-sys-corner-extra-small); + border: 1px solid var(--border-color); + background-color: var(--mat-sys-surface); + + /* stylelint-disable-next-line material/no-prefixes -- Valid in all remotely recent browsers. */ + width: fit-content; +} + +[ngMenuBar] > [ngMenuItem] { + padding: 0.25rem 0.5rem; +} + +[ngMenu] { + margin: 0; + width: 15rem; + padding: 0.25rem; + border-radius: var(--mat-sys-corner-extra-small); + border: 1px solid var(--border-color); + background-color: var(--mat-sys-surface); +} + +[ngMenu][data-visible='false'] { + display: none; +} + +[ngMenuItem] { + outline: none; + display: flex; + cursor: pointer; + align-items: center; + gap: 0.5rem; + padding: 0.5rem; + font-size: 0.875rem; + border-radius: var(--mat-sys-corner-extra-small); +} + +[ngMenuItem][aria-disabled='true'] { + cursor: default; + opacity: 0.5; +} + +[ngMenuItem][data-active='true'] { + background: color-mix(in srgb, var(--mat-sys-outline) 20%, transparent); +} + +[ngMenuItem]:focus { + outline: 2px solid var(--mat-sys-primary); +} + +[ngMenuItem] .example-icon { + opacity: 0.875; + font-size: 1.25rem; +} + +[ngMenuItem] .example-label { + flex: 1; + opacity: 0.875; + font-size: 0.875rem; +} + +[ngMenuItem]:not([aria-expanded='true']) .example-arrow { + opacity: 0.5; +} + +[ngMenu] .example-separator { + border-top: 1px solid var(--border-color); + margin: 0.25rem 0; +} + +[ngMenu] .example-shortcut { + opacity: 0.65; +} diff --git a/src/components-examples/aria/menubar/menubar/menubar-example.html b/src/components-examples/aria/menubar/menubar/menubar-example.html new file mode 100644 index 000000000000..0648bb77890b --- /dev/null +++ b/src/components-examples/aria/menubar/menubar/menubar-example.html @@ -0,0 +1,459 @@ +
            + + + +
            + +
            + article + New + ⌘N +
            + +
            + folder + Open + ⌘O +
            + +
            + file_copy + Make a copy +
            + + + +
            + person_add + Share + arrow_right +
            + + +
            + +
            + person_add + Share with others +
            + +
            + public + Publish to web +
            +
            +
            +
            + +
            + download + Download +
            + +
            + print + Print +
            + + + +
            + edit + Rename +
            + +
            + delete + Move to trash +
            +
            +
            +
            + + + + +
            + +
            + undo + Undo + ⌘Z +
            + +
            + redo + Redo + ⌘Y +
            + + + +
            + content_cut + Cut + ⌘X +
            + +
            + content_copy + Copy + ⌘C +
            + +
            + content_paste + Paste + ⌘V +
            + + + +
            + find_replace + Find and replace + ⇧⌘H +
            +
            +
            +
            + + + + +
            + +
            + check + Show print layout +
            + +
            + check + Show ruler +
            + + + +
            + Zoom in + ⌘+ +
            + +
            + Zoom out + ⌘- +
            + + + +
            + Full screen +
            +
            +
            +
            + + + + +
            + +
            + image + Image + arrow_right +
            + + +
            + +
            + upload + Upload from computer +
            + +
            + search + Search the web +
            + +
            + link + By URL +
            +
            +
            +
            + +
            + table_chart + Table +
            + +
            + insert_chart + Chart + arrow_right +
            + + +
            + +
            + bar_chart + Bar +
            + +
            + insert_chart + Column +
            + +
            + show_chart + Line +
            + +
            + pie_chart + Pie +
            +
            +
            +
            + +
            + horizontal_rule + Horizontal line +
            +
            +
            +
            + + + + +
            + +
            + format_bold + Text + arrow_right +
            + + +
            + +
            + format_bold + Bold + ⌘B +
            + +
            + format_italic + Italic + ⌘I +
            + +
            + format_underlined + Underline + ⌘U +
            + +
            + strikethrough_s + Strikethrough + ⇧⌘X +
            + + + +
            + Size + arrow_right +
            + + +
            + +
            + Increase font size + ⇧⌘. +
            + +
            + Decrease font size + ⇧⌘, +
            +
            +
            +
            +
            +
            +
            + +
            + format_align_justify + Paragraph styles + arrow_right +
            + + +
            + +
            Normal text
            +
            Heading 1
            +
            Heading 2
            +
            +
            +
            + +
            + format_indent_increase + Align & indent + arrow_right +
            + + +
            + +
            + format_align_left + Align left +
            + +
            + format_align_center + Align center +
            + +
            + format_align_right + Align right +
            + +
            + format_align_justify + Justify +
            +
            +
            +
            +
            +
            +
            +
            diff --git a/src/components-examples/aria/menubar/menubar/menubar-example.ts b/src/components-examples/aria/menubar/menubar/menubar-example.ts new file mode 100644 index 000000000000..52fc61df6be5 --- /dev/null +++ b/src/components-examples/aria/menubar/menubar/menubar-example.ts @@ -0,0 +1,25 @@ +import {Component, viewChild} from '@angular/core'; +import {Menu, MenuBar, MenuContent, MenuItem} from '@angular/aria/menu'; +import {OverlayModule} from '@angular/cdk/overlay'; + +/** @title Menu bar example. */ +@Component({ + selector: 'menubar-example', + templateUrl: 'menubar-example.html', + styleUrl: '../menubar.css', + imports: [Menu, MenuBar, MenuItem, MenuContent, OverlayModule], +}) +export class MenuBarExample { + fileMenu = viewChild>('fileMenu'); + shareMenu = viewChild>('shareMenu'); + editMenu = viewChild>('editMenu'); + viewMenu = viewChild>('viewMenu'); + insertMenu = viewChild>('insertMenu'); + imageMenu = viewChild>('imageMenu'); + chartMenu = viewChild>('chartMenu'); + formatMenu = viewChild>('formatMenu'); + textMenu = viewChild>('textMenu'); + sizeMenu = viewChild>('sizeMenu'); + paragraphMenu = viewChild>('paragraphMenu'); + alignMenu = viewChild>('alignMenu'); +} diff --git a/src/components-examples/aria/radio-group/index.ts b/src/components-examples/aria/radio-group/index.ts deleted file mode 100644 index 1eac914e3216..000000000000 --- a/src/components-examples/aria/radio-group/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export {RadioGroupStandardExample} from './radio-group-standard/radio-group-standard-example'; -export {RadioGroupHorizontalExample} from './radio-group-horizontal/radio-group-horizontal-example'; -export {RadioGroupRtlHorizontalExample} from './radio-group-rtl-horizontal/radio-group-rtl-horizontal-example'; -export {RadioGroupActiveDescendantExample} from './radio-group-active-descendant/radio-group-active-descendant-example'; -export {RadioGroupDisabledFocusableExample} from './radio-group-disabled-focusable/radio-group-disabled-focusable-example'; -export {RadioGroupDisabledSkippedExample} from './radio-group-disabled-skipped/radio-group-disabled-skipped-example'; -export {RadioGroupReadonlyExample} from './radio-group-readonly/radio-group-readonly-example'; -export {RadioGroupDisabledExample} from './radio-group-disabled/radio-group-disabled-example'; -export {RadioGroupConfigurableExample} from './radio-group-configurable/radio-group-configurable-example'; diff --git a/src/components-examples/aria/radio-group/radio-common.css b/src/components-examples/aria/radio-group/radio-common.css deleted file mode 100644 index 35d90bdb095e..000000000000 --- a/src/components-examples/aria/radio-group/radio-common.css +++ /dev/null @@ -1,90 +0,0 @@ -.example-radio-controls { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 16px; - padding-bottom: 16px; -} - -.example-radio-group { - gap: 4px; - margin: 0; - padding: 8px; - max-height: 300px; - border: 1px solid var(--mat-sys-outline); - border-radius: var(--mat-sys-corner-extra-small); - display: flex; - list-style: none; - flex-direction: column; - overflow: scroll; -} - -.example-radio-group[aria-orientation='horizontal'] { - flex-direction: row; -} - -.example-radio-group[aria-disabled='true'] { - pointer-events: none; -} - -.example-radio-group label { - padding: 16px; - flex-shrink: 0; -} - -.example-radio-button { - gap: 16px; - padding: 16px; - display: flex; - cursor: pointer; - position: relative; - align-items: center; - border-radius: var(--mat-sys-corner-extra-small); -} - -/* Basic visual indicator for the radio button */ -.example-radio-indicator { - width: 16px; - height: 16px; - border-radius: 50%; - border: 2px solid var(--mat-sys-outline); - display: inline-block; - position: relative; -} - -.example-radio-button[aria-checked='true'] .example-radio-indicator { - border-color: var(--mat-sys-primary); -} - -.example-radio-button[aria-checked='true'] .example-radio-indicator::after { - content: ''; - display: block; - width: 8px; - height: 8px; - border-radius: 50%; - background-color: var(--mat-sys-primary); - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); -} - -.example-radio-button[aria-disabled='true'][aria-checked='true'] .example-radio-indicator::after { - background-color: var(--mat-sys-outline); -} - -.example-radio-button[aria-disabled='true'] { - cursor: default; -} - -.example-radio-button[aria-disabled='true']::before { - content: ''; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - border-radius: var(--mat-sys-corner-extra-small); - background-color: var(--mat-sys-on-surface); - opacity: var(--mat-sys-focus-state-layer-opacity); -} diff --git a/src/components-examples/aria/radio-group/radio-group-active-descendant/radio-group-active-descendant-example.html b/src/components-examples/aria/radio-group/radio-group-active-descendant/radio-group-active-descendant-example.html deleted file mode 100644 index eb5bc78e5cbf..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-active-descendant/radio-group-active-descendant-example.html +++ /dev/null @@ -1,26 +0,0 @@ -
            -
              - - @for (fruit of fruits; track fruit) { -
            • - - {{ fruit }} -
            • - } -
            -
            diff --git a/src/components-examples/aria/radio-group/radio-group-active-descendant/radio-group-active-descendant-example.ts b/src/components-examples/aria/radio-group/radio-group-active-descendant/radio-group-active-descendant-example.ts deleted file mode 100644 index d111affcfe74..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-active-descendant/radio-group-active-descendant-example.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {Component} from '@angular/core'; -import {FormsModule} from '@angular/forms'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; - -/** @title Active descendant radio group. */ -@Component({ - selector: 'radio-group-active-descendant-example', - templateUrl: 'radio-group-active-descendant-example.html', - styleUrl: '../radio-common.css', - imports: [RadioGroup, RadioButton, FormsModule], -}) -export class RadioGroupActiveDescendantExample { - fruits = [ - 'Apple', - 'Apricot', - 'Banana', - 'Blackberry', - 'Blueberry', - 'Cantaloupe', - 'Cherry', - 'Clementine', - 'Cranberry', - 'Dates', - 'Figs', - 'Grapes', - 'Grapefruit', - 'Guava', - 'Kiwi', - 'Kumquat', - 'Lemon', - 'Lime', - 'Mandarin', - 'Mango', - 'Nectarine', - 'Orange', - 'Papaya', - 'Passion', - 'Peach', - 'Pear', - 'Pineapple', - 'Plum', - 'Pomegranate', - 'Raspberries', - 'Strawberry', - 'Tangerine', - 'Watermelon', - ]; -} diff --git a/src/components-examples/aria/radio-group/radio-group-configurable/radio-group-configurable-example.html b/src/components-examples/aria/radio-group/radio-group-configurable/radio-group-configurable-example.html deleted file mode 100644 index cda2bef0de4a..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-configurable/radio-group-configurable-example.html +++ /dev/null @@ -1,56 +0,0 @@ -
            - Disabled - Readonly - Skip Disabled - - - Disabled Radio Options - - @for (fruit of fruits; track fruit) { - {{fruit}} - } - - - - - Orientation - - Vertical - Horizontal - - - - - Focus strategy - - Roving Tabindex - Active Descendant - - -
            - - -
              - @for (fruit of fruits; track fruit) { - @let optionDisabled = disabledOptions.includes(fruit); -
            • - - {{ fruit }} -
            • - } -
            - diff --git a/src/components-examples/aria/radio-group/radio-group-configurable/radio-group-configurable-example.ts b/src/components-examples/aria/radio-group/radio-group-configurable/radio-group-configurable-example.ts deleted file mode 100644 index 8c9db2e14332..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-configurable/radio-group-configurable-example.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {Component} from '@angular/core'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; -import {MatCheckboxModule} from '@angular/material/checkbox'; -import {MatFormFieldModule} from '@angular/material/form-field'; -import {MatSelectModule} from '@angular/material/select'; -import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; - -/** @title Configurable CDK Radio Group */ -@Component({ - selector: 'radio-group-configurable-example', - templateUrl: 'radio-group-configurable-example.html', - styleUrl: '../radio-common.css', - imports: [ - RadioGroup, - RadioButton, - MatCheckboxModule, - MatFormFieldModule, - MatSelectModule, - FormsModule, - ReactiveFormsModule, - ], -}) -export class RadioGroupConfigurableExample { - orientation: 'vertical' | 'horizontal' = 'vertical'; - disabled = new FormControl(false, {nonNullable: true}); - - fruits = [ - 'Apple', - 'Apricot', - 'Banana', - 'Blackberry', - 'Blueberry', - 'Cantaloupe', - 'Cherry', - 'Clementine', - 'Cranberry', - 'Dates', - 'Figs', - 'Grapes', - 'Grapefruit', - 'Guava', - 'Kiwi', - 'Kumquat', - 'Lemon', - 'Lime', - 'Mandarin', - 'Mango', - 'Nectarine', - 'Orange', - 'Papaya', - 'Passion', - 'Peach', - 'Pear', - 'Pineapple', - 'Plum', - 'Pomegranate', - 'Raspberries', - 'Strawberry', - 'Tangerine', - 'Watermelon', - ]; - - // New controls - readonly = new FormControl(false, {nonNullable: true}); - skipDisabled = new FormControl(true, {nonNullable: true}); - focusMode: 'roving' | 'activedescendant' = 'roving'; - - // Control for which radio options are individually disabled - disabledOptions: string[] = ['Banana']; -} diff --git a/src/components-examples/aria/radio-group/radio-group-disabled-focusable/radio-group-disabled-focusable-example.html b/src/components-examples/aria/radio-group/radio-group-disabled-focusable/radio-group-disabled-focusable-example.html deleted file mode 100644 index f6764a413edf..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-disabled-focusable/radio-group-disabled-focusable-example.html +++ /dev/null @@ -1,27 +0,0 @@ -
            -
              - - @for (fruit of fruits; track fruit) { -
            • - - {{ fruit }} {{ disabledFruits.includes(fruit) ? '(Disabled)' : '' }} -
            • - } -
            -
            diff --git a/src/components-examples/aria/radio-group/radio-group-disabled-focusable/radio-group-disabled-focusable-example.ts b/src/components-examples/aria/radio-group/radio-group-disabled-focusable/radio-group-disabled-focusable-example.ts deleted file mode 100644 index d85354a2199c..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-disabled-focusable/radio-group-disabled-focusable-example.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {Component} from '@angular/core'; -import {FormsModule} from '@angular/forms'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; - -/** @title Radio group with disabled options that are focusable. */ -@Component({ - selector: 'radio-group-disabled-focusable-example', - templateUrl: 'radio-group-disabled-focusable-example.html', - styleUrl: '../radio-common.css', - imports: [RadioGroup, RadioButton, FormsModule], -}) -export class RadioGroupDisabledFocusableExample { - fruits = [ - 'Apple', - 'Apricot', - 'Banana', - 'Blackberry', - 'Blueberry', - 'Cantaloupe', - 'Cherry', - 'Clementine', - 'Cranberry', - 'Dates', - 'Figs', - 'Grapes', - 'Grapefruit', - 'Guava', - 'Kiwi', - 'Kumquat', - 'Lemon', - 'Lime', - 'Mandarin', - 'Mango', - 'Nectarine', - 'Orange', - 'Papaya', - 'Passion', - 'Peach', - 'Pear', - 'Pineapple', - 'Plum', - 'Pomegranate', - 'Raspberries', - 'Strawberry', - 'Tangerine', - 'Watermelon', - ]; - disabledFruits = ['Banana', 'Kiwi']; -} diff --git a/src/components-examples/aria/radio-group/radio-group-disabled-skipped/radio-group-disabled-skipped-example.html b/src/components-examples/aria/radio-group/radio-group-disabled-skipped/radio-group-disabled-skipped-example.html deleted file mode 100644 index e0d01e2a092e..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-disabled-skipped/radio-group-disabled-skipped-example.html +++ /dev/null @@ -1,26 +0,0 @@ -
            -
              - - @for (fruit of fruits; track fruit) { -
            • - - {{ fruit }} {{ disabledFruits.includes(fruit) ? '(Disabled)' : '' }} -
            • - } -
            -
            diff --git a/src/components-examples/aria/radio-group/radio-group-disabled-skipped/radio-group-disabled-skipped-example.ts b/src/components-examples/aria/radio-group/radio-group-disabled-skipped/radio-group-disabled-skipped-example.ts deleted file mode 100644 index 9e74081d5788..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-disabled-skipped/radio-group-disabled-skipped-example.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {Component} from '@angular/core'; -import {FormsModule} from '@angular/forms'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; - -/** @title Radio group with disabled options that are skipped. */ -@Component({ - selector: 'radio-group-disabled-skipped-example', - templateUrl: 'radio-group-disabled-skipped-example.html', - styleUrl: '../radio-common.css', - imports: [RadioGroup, RadioButton, FormsModule], -}) -export class RadioGroupDisabledSkippedExample { - fruits = [ - 'Apple', - 'Apricot', - 'Banana', - 'Blackberry', - 'Blueberry', - 'Cantaloupe', - 'Cherry', - 'Clementine', - 'Cranberry', - 'Dates', - 'Figs', - 'Grapes', - 'Grapefruit', - 'Guava', - 'Kiwi', - 'Kumquat', - 'Lemon', - 'Lime', - 'Mandarin', - 'Mango', - 'Nectarine', - 'Orange', - 'Papaya', - 'Passion', - 'Peach', - 'Pear', - 'Pineapple', - 'Plum', - 'Pomegranate', - 'Raspberries', - 'Strawberry', - 'Tangerine', - 'Watermelon', - ]; - disabledFruits = ['Banana', 'Kiwi']; -} diff --git a/src/components-examples/aria/radio-group/radio-group-disabled/radio-group-disabled-example.html b/src/components-examples/aria/radio-group/radio-group-disabled/radio-group-disabled-example.html deleted file mode 100644 index 767af665a645..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-disabled/radio-group-disabled-example.html +++ /dev/null @@ -1,25 +0,0 @@ -
            -
              - - @for (fruit of fruits; track fruit) { -
            • - - {{ fruit }} -
            • - } -
            -

            The entire radio group is disabled. Focus should not enter the group.

            -
            diff --git a/src/components-examples/aria/radio-group/radio-group-disabled/radio-group-disabled-example.ts b/src/components-examples/aria/radio-group/radio-group-disabled/radio-group-disabled-example.ts deleted file mode 100644 index 932769eb06a4..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-disabled/radio-group-disabled-example.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {Component} from '@angular/core'; -import {FormsModule} from '@angular/forms'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; - -/** @title Disabled radio group. */ -@Component({ - selector: 'radio-group-disabled-example', - templateUrl: 'radio-group-disabled-example.html', - styleUrl: '../radio-common.css', - imports: [RadioGroup, RadioButton, FormsModule], -}) -export class RadioGroupDisabledExample { - fruits = [ - 'Apple', - 'Apricot', - 'Banana', - 'Blackberry', - 'Blueberry', - 'Cantaloupe', - 'Cherry', - 'Clementine', - 'Cranberry', - 'Dates', - 'Figs', - 'Grapes', - 'Grapefruit', - 'Guava', - 'Kiwi', - 'Kumquat', - 'Lemon', - 'Lime', - 'Mandarin', - 'Mango', - 'Nectarine', - 'Orange', - 'Papaya', - 'Passion', - 'Peach', - 'Pear', - 'Pineapple', - 'Plum', - 'Pomegranate', - 'Raspberries', - 'Strawberry', - 'Tangerine', - 'Watermelon', - ]; -} diff --git a/src/components-examples/aria/radio-group/radio-group-horizontal/radio-group-horizontal-example.html b/src/components-examples/aria/radio-group/radio-group-horizontal/radio-group-horizontal-example.html deleted file mode 100644 index 9ccf81a55f02..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-horizontal/radio-group-horizontal-example.html +++ /dev/null @@ -1,24 +0,0 @@ -
            -
              - - @for (fruit of fruits; track fruit) { -
            • - - {{ fruit }} -
            • - } -
            -
            diff --git a/src/components-examples/aria/radio-group/radio-group-horizontal/radio-group-horizontal-example.ts b/src/components-examples/aria/radio-group/radio-group-horizontal/radio-group-horizontal-example.ts deleted file mode 100644 index 081b62def973..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-horizontal/radio-group-horizontal-example.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {Component} from '@angular/core'; -import {FormsModule} from '@angular/forms'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; - -/** @title Horizontal radio group. */ -@Component({ - selector: 'radio-group-horizontal-example', - templateUrl: 'radio-group-horizontal-example.html', - styleUrl: '../radio-common.css', - imports: [RadioGroup, RadioButton, FormsModule], -}) -export class RadioGroupHorizontalExample { - fruits = [ - 'Apple', - 'Apricot', - 'Banana', - 'Blackberry', - 'Blueberry', - 'Cantaloupe', - 'Cherry', - 'Clementine', - 'Cranberry', - 'Dates', - 'Figs', - 'Grapes', - 'Grapefruit', - 'Guava', - 'Kiwi', - 'Kumquat', - 'Lemon', - 'Lime', - 'Mandarin', - 'Mango', - 'Nectarine', - 'Orange', - 'Papaya', - 'Passion', - 'Peach', - 'Pear', - 'Pineapple', - 'Plum', - 'Pomegranate', - 'Raspberries', - 'Strawberry', - 'Tangerine', - 'Watermelon', - ]; -} diff --git a/src/components-examples/aria/radio-group/radio-group-readonly/radio-group-readonly-example.html b/src/components-examples/aria/radio-group/radio-group-readonly/radio-group-readonly-example.html deleted file mode 100644 index 8d6892260338..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-readonly/radio-group-readonly-example.html +++ /dev/null @@ -1,25 +0,0 @@ -
            -
              - - @for (fruit of fruits; track fruit) { -
            • - - {{ fruit }} -
            • - } -
            -

            The radio group is navigable, but selection cannot be changed.

            -
            diff --git a/src/components-examples/aria/radio-group/radio-group-readonly/radio-group-readonly-example.ts b/src/components-examples/aria/radio-group/radio-group-readonly/radio-group-readonly-example.ts deleted file mode 100644 index 3bb4d5cbad03..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-readonly/radio-group-readonly-example.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {Component} from '@angular/core'; -import {FormsModule} from '@angular/forms'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; - -/** @title Readonly radio group. */ -@Component({ - selector: 'radio-group-readonly-example', - templateUrl: 'radio-group-readonly-example.html', - styleUrl: '../radio-common.css', - imports: [RadioGroup, RadioButton, FormsModule], -}) -export class RadioGroupReadonlyExample { - fruits = [ - 'Apple', - 'Apricot', - 'Banana', - 'Blackberry', - 'Blueberry', - 'Cantaloupe', - 'Cherry', - 'Clementine', - 'Cranberry', - 'Dates', - 'Figs', - 'Grapes', - 'Grapefruit', - 'Guava', - 'Kiwi', - 'Kumquat', - 'Lemon', - 'Lime', - 'Mandarin', - 'Mango', - 'Nectarine', - 'Orange', - 'Papaya', - 'Passion', - 'Peach', - 'Pear', - 'Pineapple', - 'Plum', - 'Pomegranate', - 'Raspberries', - 'Strawberry', - 'Tangerine', - 'Watermelon', - ]; -} diff --git a/src/components-examples/aria/radio-group/radio-group-rtl-horizontal/radio-group-rtl-horizontal-example.html b/src/components-examples/aria/radio-group/radio-group-rtl-horizontal/radio-group-rtl-horizontal-example.html deleted file mode 100644 index a6e8763958cb..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-rtl-horizontal/radio-group-rtl-horizontal-example.html +++ /dev/null @@ -1,21 +0,0 @@ -
            -
              - - @for (fruit of fruits; track fruit) { -
            • - - {{ fruit }} -
            • - } -
            -
            diff --git a/src/components-examples/aria/radio-group/radio-group-rtl-horizontal/radio-group-rtl-horizontal-example.ts b/src/components-examples/aria/radio-group/radio-group-rtl-horizontal/radio-group-rtl-horizontal-example.ts deleted file mode 100644 index 46a3bcc6fab1..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-rtl-horizontal/radio-group-rtl-horizontal-example.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {Component} from '@angular/core'; -import {Dir} from '@angular/cdk/bidi'; -import {FormsModule} from '@angular/forms'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; - -/** @title RTL horizontal radio group. */ -@Component({ - selector: 'radio-group-rtl-horizontal-example', - templateUrl: 'radio-group-rtl-horizontal-example.html', - styleUrl: '../radio-common.css', - imports: [RadioGroup, RadioButton, Dir, FormsModule], -}) -export class RadioGroupRtlHorizontalExample { - fruits = [ - 'Apple', - 'Apricot', - 'Banana', - 'Blackberry', - 'Blueberry', - 'Cantaloupe', - 'Cherry', - 'Clementine', - 'Cranberry', - 'Dates', - 'Figs', - 'Grapes', - 'Grapefruit', - 'Guava', - 'Kiwi', - 'Kumquat', - 'Lemon', - 'Lime', - 'Mandarin', - 'Mango', - 'Nectarine', - 'Orange', - 'Papaya', - 'Passion', - 'Peach', - 'Pear', - 'Pineapple', - 'Plum', - 'Pomegranate', - 'Raspberries', - 'Strawberry', - 'Tangerine', - 'Watermelon', - ]; -} diff --git a/src/components-examples/aria/radio-group/radio-group-standard/radio-group-standard-example.html b/src/components-examples/aria/radio-group/radio-group-standard/radio-group-standard-example.html deleted file mode 100644 index ce6b57bde1ab..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-standard/radio-group-standard-example.html +++ /dev/null @@ -1,23 +0,0 @@ -
            -
              - - @for (fruit of fruits; track fruit) { -
            • - - {{ fruit }} -
            • - } -
            -
            diff --git a/src/components-examples/aria/radio-group/radio-group-standard/radio-group-standard-example.ts b/src/components-examples/aria/radio-group/radio-group-standard/radio-group-standard-example.ts deleted file mode 100644 index aa3f9564f31e..000000000000 --- a/src/components-examples/aria/radio-group/radio-group-standard/radio-group-standard-example.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {Component} from '@angular/core'; -import {FormsModule} from '@angular/forms'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; - -/** @title Basic radio group. */ -@Component({ - selector: 'radio-group-standard-example', - templateUrl: 'radio-group-standard-example.html', - styleUrl: '../radio-common.css', - imports: [RadioGroup, RadioButton, FormsModule], -}) -export class RadioGroupStandardExample { - fruits = [ - 'Apple', - 'Apricot', - 'Banana', - 'Blackberry', - 'Blueberry', - 'Cantaloupe', - 'Cherry', - 'Clementine', - 'Cranberry', - 'Dates', - 'Figs', - 'Grapes', - 'Grapefruit', - 'Guava', - 'Kiwi', - 'Kumquat', - 'Lemon', - 'Lime', - 'Mandarin', - 'Mango', - 'Nectarine', - 'Orange', - 'Papaya', - 'Passion', - 'Peach', - 'Pear', - 'Pineapple', - 'Plum', - 'Pomegranate', - 'Raspberries', - 'Strawberry', - 'Tangerine', - 'Watermelon', - ]; -} diff --git a/src/components-examples/aria/select/BUILD.bazel b/src/components-examples/aria/select/BUILD.bazel new file mode 100644 index 000000000000..cf82f9bf6ef9 --- /dev/null +++ b/src/components-examples/aria/select/BUILD.bazel @@ -0,0 +1,27 @@ +load("//tools:defaults.bzl", "ng_project") + +package(default_visibility = ["//visibility:public"]) + +ng_project( + name = "select", + srcs = glob(["**/*.ts"]), + assets = glob([ + "**/*.html", + "**/*.css", + ]), + deps = [ + "//:node_modules/@angular/core", + "//src/aria/combobox", + "//src/aria/listbox", + "//src/cdk/overlay", + ], +) + +filegroup( + name = "source-files", + srcs = glob([ + "**/*.html", + "**/*.css", + "**/*.ts", + ]), +) diff --git a/src/components-examples/aria/select/index.ts b/src/components-examples/aria/select/index.ts new file mode 100644 index 000000000000..2ceef481d338 --- /dev/null +++ b/src/components-examples/aria/select/index.ts @@ -0,0 +1,3 @@ +export {SelectDisabledExample} from './select-disabled/select-disabled-example'; +export {SelectMultiExample} from './select-multi/select-multi-example'; +export {SelectExample} from './select/select-example'; diff --git a/src/components-examples/aria/select/select-disabled/select-disabled-example.html b/src/components-examples/aria/select/select-disabled/select-disabled-example.html new file mode 100644 index 000000000000..a64296a5d06d --- /dev/null +++ b/src/components-examples/aria/select/select-disabled/select-disabled-example.html @@ -0,0 +1,28 @@ +
            +
            +
            + Select an option +
            + + arrow_drop_down +
            + + + +
            +
            + @for (item of items; track item) { +
            + + {{item}} + +
            + } +
            +
            +
            +
            +
            diff --git a/src/components-examples/aria/select/select-disabled/select-disabled-example.ts b/src/components-examples/aria/select/select-disabled/select-disabled-example.ts new file mode 100644 index 000000000000..aacc40f17b4d --- /dev/null +++ b/src/components-examples/aria/select/select-disabled/select-disabled-example.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; +import {OverlayModule} from '@angular/cdk/overlay'; + +/** @title Aria select disabled example. */ +@Component({ + selector: 'select-disabled-example', + templateUrl: 'select-disabled-example.html', + styleUrl: '../select.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + OverlayModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SelectDisabledExample { + /** The items available for selection. */ + items = ['Option 1', 'Option 2', 'Option 3']; +} diff --git a/src/components-examples/aria/select/select-multi/select-multi-example.html b/src/components-examples/aria/select/select-multi/select-multi-example.html new file mode 100644 index 000000000000..29e40ca53586 --- /dev/null +++ b/src/components-examples/aria/select/select-multi/select-multi-example.html @@ -0,0 +1,27 @@ +
            +
            +
            + {{ displayValue() }} +
            + + arrow_drop_down +
            + + + +
            +
            + @for (item of items; track item) { +
            + {{item}} + +
            + } +
            +
            +
            +
            +
            diff --git a/src/components-examples/aria/select/select-multi/select-multi-example.ts b/src/components-examples/aria/select/select-multi/select-multi-example.ts new file mode 100644 index 000000000000..8d553c4a84ac --- /dev/null +++ b/src/components-examples/aria/select/select-multi/select-multi-example.ts @@ -0,0 +1,74 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + computed, + viewChild, + viewChildren, +} from '@angular/core'; +import {OverlayModule} from '@angular/cdk/overlay'; + +/** @title Aria multiselect example. */ +@Component({ + selector: 'select-multi-example', + templateUrl: 'select-multi-example.html', + styleUrl: '../select.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + OverlayModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SelectMultiExample { + /** The options available in the listbox. */ + options = viewChildren>(Option); + + /** The combobox listbox popup. */ + listbox = viewChild>(Listbox); + + /** The visible label displayed to the user. */ + displayValue = computed(() => { + const values = this.listbox()?.values(); + + if (!values?.length) { + return 'Select a day'; + } + + if (values.length <= 2) { + return values.join(', '); + } + + return `${values[0]} + ${values.length - 1} more`; + }); + + /** The items available for selection. */ + items = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + + constructor() { + // Scrolls to the active item when the active option changes. + afterRenderEffect(() => { + const option = this.options().find(opt => opt.active()); + option?.element.scrollIntoView({block: 'nearest'}); + }); + } +} diff --git a/src/components-examples/aria/select/select.css b/src/components-examples/aria/select/select.css new file mode 100644 index 000000000000..282b043531f1 --- /dev/null +++ b/src/components-examples/aria/select/select.css @@ -0,0 +1,137 @@ +.example-select { + position: relative; + display: flex; + align-items: center; + border: 1px solid var(--mat-sys-outline); + border-radius: var(--mat-sys-corner-extra-small); + + /* stylelint-disable-next-line material/no-prefixes -- Valid in all remotely recent browsers. */ + width: fit-content; +} + +.example-select:has([ngComboboxInput][aria-disabled='true']) { + opacity: 0.7; + background-color: var(--mat-sys-surface-dim); +} + +.example-select:focus-within { + outline-offset: -2px; + outline: 2px solid var(--mat-sys-primary); +} + +.example-arrow, +.example-select-value { + position: absolute; + pointer-events: none; +} + +.example-select-value { + display: flex; + gap: 1rem; + left: 1rem; + width: calc(100% - 4rem); +} + +.example-select-label { + text-overflow: ellipsis; + text-wrap-mode: nowrap; + overflow: hidden; +} + +.example-arrow, +.example-select-icon { + font-size: 1.25rem; + opacity: 0.875; +} + +.example-arrow { + right: 1rem; + transition: transform 0.2s ease-in-out; +} + +[ngComboboxInput] { + cursor: pointer; + padding: 0.7rem 3rem; + opacity: 0; +} + +[ngComboboxInput][aria-disabled='true'] { + cursor: default; +} + +[ngComboboxInput][aria-expanded='true'] + .example-arrow { + transform: rotate(180deg); +} + +[ngCombobox]:has([aria-expanded='false']) .example-popup { + display: none; +} + +.example-popup { + width: 100%; + margin-top: 2px; + padding: 0.1rem; + max-height: 11rem; + border-radius: var(--mat-sys-corner-extra-small); + background-color: var(--mat-sys-surface); + border: 1px solid var(--mat-sys-outline); +} + +.example-no-results { + padding: 1rem; +} + +[ngListbox] { + gap: 2px; + width: 100%; + height: 100%; + display: flex; + overflow: auto; + flex-direction: column; +} + +[ngOption] { + display: flex; + cursor: pointer; + align-items: center; + margin: 1px; + gap: 1rem; + padding: 0.7rem 1rem; + border-radius: var(--mat-sys-corner-extra-small); +} + +[ngOption][aria-disabled='true'] { + cursor: default; + opacity: 0.5; + background-color: var(--mat-sys-surface-dim); +} + +[ngOption]:hover { + background-color: color-mix(in srgb, var(--mat-sys-outline) 15%, transparent); +} + +[ngOption][data-active='true'] { + outline-offset: -2px; + outline: 2px solid var(--mat-sys-primary); +} + +[ngOption][aria-selected='true'] { + color: var(--mat-sys-primary); + background-color: color-mix(in srgb, var(--mat-sys-primary) 10%, transparent); +} + +[ngOption]:not([aria-selected='true']) .example-option-check { + display: none; +} + +.example-option-text { + flex: 1; +} + +.example-option-icon { + font-size: 1.25rem; +} + +.example-option-check { + font-size: 1rem; +} diff --git a/src/components-examples/aria/select/select/select-example.html b/src/components-examples/aria/select/select/select-example.html new file mode 100644 index 000000000000..9dfd34de9b9f --- /dev/null +++ b/src/components-examples/aria/select/select/select-example.html @@ -0,0 +1,35 @@ +
            +
            +
            + {{ value().icon }} + {{ value().label }} +
            + + arrow_drop_down +
            + + + +
            +
            + @for (item of items; track item.label) { +
            + + {{item.label}} + +
            + } +
            +
            +
            +
            +
            diff --git a/src/components-examples/aria/select/select/select-example.ts b/src/components-examples/aria/select/select/select-example.ts new file mode 100644 index 000000000000..9a57cc865e74 --- /dev/null +++ b/src/components-examples/aria/select/select/select-example.ts @@ -0,0 +1,66 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import { + afterRenderEffect, + ChangeDetectionStrategy, + Component, + computed, + viewChild, + viewChildren, +} from '@angular/core'; +import {OverlayModule} from '@angular/cdk/overlay'; + +/** @title Aria select example. */ +@Component({ + selector: 'select-example', + templateUrl: 'select-example.html', + styleUrl: '../select.css', + imports: [ + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + OverlayModule, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SelectExample { + /** The options available in the listbox. */ + options = viewChildren>(Option); + + /** The combobox listbox popup. */ + listbox = viewChild>(Listbox); + + /** The current value of the select. */ + value = computed(() => this.listbox()?.values()[0] ?? this.items[1]); + + /** The items available for selection. */ + items = [ + {label: 'Light Mode', icon: 'light_mode'}, + {label: 'Dark Mode', icon: 'dark_mode'}, + {label: 'System Default', icon: 'settings'}, + ]; + + constructor() { + // Scrolls to the active item when the active option changes. + afterRenderEffect(() => { + const option = this.options().find(opt => opt.active()); + option?.element.scrollIntoView({block: 'nearest'}); + }); + } +} diff --git a/src/components-examples/aria/tabs/active-descendant/tabs-active-descendant-example.html b/src/components-examples/aria/tabs/active-descendant/tabs-active-descendant-example.html index a4e61401ada4..320cb123ad4c 100644 --- a/src/components-examples/aria/tabs/active-descendant/tabs-active-descendant-example.html +++ b/src/components-examples/aria/tabs/active-descendant/tabs-active-descendant-example.html @@ -1,29 +1,29 @@ -
            -
              -
            • tab 1
            • -
            • tab 2
            • -
            • tab 3
            • -
            • tab 4
            • -
            • tab 5
            • -
            +
            +
            +
            Tab 1
            +
            Tab 2
            +
            Tab 3
            +
            Tab 4
            +
            Tab 5
            +
            -
            - Tabpanel 1 +
            + Panel 1
            -
            - Tabpanel 2 +
            + Panel 2
            -
            - Tabpanel 3 +
            + Panel 3
            -
            - Tabpanel 4 +
            + Panel 4
            -
            - Tabpanel 5 +
            + Panel 5
            diff --git a/src/components-examples/aria/tabs/active-descendant/tabs-active-descendant-example.ts b/src/components-examples/aria/tabs/active-descendant/tabs-active-descendant-example.ts index 2af0ae60ab71..9edf19de666c 100644 --- a/src/components-examples/aria/tabs/active-descendant/tabs-active-descendant-example.ts +++ b/src/components-examples/aria/tabs/active-descendant/tabs-active-descendant-example.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {afterRenderEffect, Component, viewChildren} from '@angular/core'; import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; /** @title Active Descendant */ @@ -8,4 +8,13 @@ import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; styleUrls: ['../tabs-common.css'], imports: [TabList, Tab, Tabs, TabPanel, TabContent], }) -export class TabsActiveDescendantExample {} +export class TabsActiveDescendantExample { + tabs = viewChildren(Tab); + + constructor() { + afterRenderEffect(() => { + const tab = this.tabs().find(t => t.active()); + tab?.element.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'nearest'}); + }); + } +} diff --git a/src/components-examples/aria/tabs/disabled-focusable/tabs-disabled-focusable-example.html b/src/components-examples/aria/tabs/disabled-focusable/tabs-disabled-focusable-example.html index 97d542078fa8..cd2192fcf3cd 100644 --- a/src/components-examples/aria/tabs/disabled-focusable/tabs-disabled-focusable-example.html +++ b/src/components-examples/aria/tabs/disabled-focusable/tabs-disabled-focusable-example.html @@ -1,29 +1,29 @@ -
            -
              -
            • tab 1
            • -
            • tab 2
            • -
            • tab 3
            • -
            • tab 4
            • -
            • tab 5
            • -
            +
            +
            +
            Tab 1
            +
            Tab 2
            +
            Tab 3
            +
            Tab 4
            +
            Tab 5
            +
            -
            - Tabpanel 1 +
            + Panel 1
            -
            - Tabpanel 2 +
            + Panel 2
            -
            - Tabpanel 3 +
            + Panel 3
            -
            - Tabpanel 4 +
            + Panel 4
            -
            - Tabpanel 5 +
            + Panel 5
            diff --git a/src/components-examples/aria/tabs/disabled-focusable/tabs-disabled-focusable-example.ts b/src/components-examples/aria/tabs/disabled-focusable/tabs-disabled-focusable-example.ts index 7a90ee0d55f6..7cc4e6007c84 100644 --- a/src/components-examples/aria/tabs/disabled-focusable/tabs-disabled-focusable-example.ts +++ b/src/components-examples/aria/tabs/disabled-focusable/tabs-disabled-focusable-example.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {afterRenderEffect, Component, viewChildren} from '@angular/core'; import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; /** @title Disabled Tabs are Focusable */ @@ -8,4 +8,13 @@ import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; styleUrls: ['../tabs-common.css'], imports: [TabList, Tab, Tabs, TabPanel, TabContent], }) -export class TabsDisabledFocusableExample {} +export class TabsDisabledFocusableExample { + tabs = viewChildren(Tab); + + constructor() { + afterRenderEffect(() => { + const tab = this.tabs().find(t => t.active()); + tab?.element.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'nearest'}); + }); + } +} diff --git a/src/components-examples/aria/tabs/disabled-skipped/tabs-disabled-skipped-example.html b/src/components-examples/aria/tabs/disabled-skipped/tabs-disabled-skipped-example.html index 02900da93462..e74ad12ae53b 100644 --- a/src/components-examples/aria/tabs/disabled-skipped/tabs-disabled-skipped-example.html +++ b/src/components-examples/aria/tabs/disabled-skipped/tabs-disabled-skipped-example.html @@ -1,29 +1,29 @@ -
            -
              -
            • tab 1
            • -
            • tab 2
            • -
            • tab 3
            • -
            • tab 4
            • -
            • tab 5
            • -
            +
            +
            +
            Tab 1
            +
            Tab 2
            +
            Tab 3
            +
            Tab 4
            +
            Tab 5
            +
            -
            - Tabpanel 1 +
            + Panel 1
            -
            - Tabpanel 2 +
            + Panel 2
            -
            - Tabpanel 3 +
            + Panel 3
            -
            - Tabpanel 4 +
            + Panel 4
            -
            - Tabpanel 5 +
            + Panel 5
            diff --git a/src/components-examples/aria/tabs/disabled-skipped/tabs-disabled-skipped-example.ts b/src/components-examples/aria/tabs/disabled-skipped/tabs-disabled-skipped-example.ts index 37a4319aa5a1..6ffcef883c33 100644 --- a/src/components-examples/aria/tabs/disabled-skipped/tabs-disabled-skipped-example.ts +++ b/src/components-examples/aria/tabs/disabled-skipped/tabs-disabled-skipped-example.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {afterRenderEffect, Component, viewChildren} from '@angular/core'; import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; /** @title Disabled Tabs are Skipped */ @@ -8,4 +8,13 @@ import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; styleUrls: ['../tabs-common.css'], imports: [TabList, Tab, Tabs, TabPanel, TabContent], }) -export class TabsDisabledSkippedExample {} +export class TabsDisabledSkippedExample { + tabs = viewChildren(Tab); + + constructor() { + afterRenderEffect(() => { + const tab = this.tabs().find(t => t.active()); + tab?.element.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'nearest'}); + }); + } +} diff --git a/src/components-examples/aria/tabs/disabled/tabs-disabled-example.html b/src/components-examples/aria/tabs/disabled/tabs-disabled-example.html index b3df716aceaf..d356a4f7f564 100644 --- a/src/components-examples/aria/tabs/disabled/tabs-disabled-example.html +++ b/src/components-examples/aria/tabs/disabled/tabs-disabled-example.html @@ -1,29 +1,29 @@ -
            -
              -
            • tab 1
            • -
            • tab 2
            • -
            • tab 3
            • -
            • tab 4
            • -
            • tab 5
            • -
            +
            +
            +
            Tab 1
            +
            Tab 2
            +
            Tab 3
            +
            Tab 4
            +
            Tab 5
            +
            -
            - Tabpanel 1 +
            + Panel 1
            -
            - Tabpanel 2 +
            + Panel 2
            -
            - Tabpanel 3 +
            + Panel 3
            -
            - Tabpanel 4 +
            + Panel 4
            -
            - Tabpanel 5 +
            + Panel 5
            diff --git a/src/components-examples/aria/tabs/disabled/tabs-disabled-example.ts b/src/components-examples/aria/tabs/disabled/tabs-disabled-example.ts index df5b647f3f49..5391f71df936 100644 --- a/src/components-examples/aria/tabs/disabled/tabs-disabled-example.ts +++ b/src/components-examples/aria/tabs/disabled/tabs-disabled-example.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {afterRenderEffect, Component, viewChildren} from '@angular/core'; import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; /** @title Disabled */ @@ -8,4 +8,13 @@ import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; styleUrls: ['../tabs-common.css'], imports: [TabList, Tab, Tabs, TabPanel, TabContent], }) -export class TabsDisabledExample {} +export class TabsDisabledExample { + tabs = viewChildren(Tab); + + constructor() { + afterRenderEffect(() => { + const tab = this.tabs().find(t => t.active()); + tab?.element.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'nearest'}); + }); + } +} diff --git a/src/components-examples/aria/tabs/explicit-selection/tabs-explicit-selection-example.html b/src/components-examples/aria/tabs/explicit-selection/tabs-explicit-selection-example.html index 2ecd56444fcb..6ee281a4f16a 100644 --- a/src/components-examples/aria/tabs/explicit-selection/tabs-explicit-selection-example.html +++ b/src/components-examples/aria/tabs/explicit-selection/tabs-explicit-selection-example.html @@ -1,29 +1,29 @@ -
            -
              -
            • tab 1
            • -
            • tab 2
            • -
            • tab 3
            • -
            • tab 4
            • -
            • tab 5
            • -
            +
            +
            +
            Tab 1
            +
            Tab 2
            +
            Tab 3
            +
            Tab 4
            +
            Tab 5
            +
            -
            - Tabpanel 1 +
            + Panel 1
            -
            - Tabpanel 2 +
            + Panel 2
            -
            - Tabpanel 3 +
            + Panel 3
            -
            - Tabpanel 4 +
            + Panel 4
            -
            - Tabpanel 5 +
            + Panel 5
            diff --git a/src/components-examples/aria/tabs/explicit-selection/tabs-explicit-selection-example.ts b/src/components-examples/aria/tabs/explicit-selection/tabs-explicit-selection-example.ts index 1a1aa9ba2897..bd91d20cdc84 100644 --- a/src/components-examples/aria/tabs/explicit-selection/tabs-explicit-selection-example.ts +++ b/src/components-examples/aria/tabs/explicit-selection/tabs-explicit-selection-example.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {afterRenderEffect, Component, viewChildren} from '@angular/core'; import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; /** @title Explicit selection */ @@ -8,4 +8,13 @@ import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; styleUrls: ['../tabs-common.css'], imports: [TabList, Tab, Tabs, TabPanel, TabContent], }) -export class TabsExplicitSelectionExample {} +export class TabsExplicitSelectionExample { + tabs = viewChildren(Tab); + + constructor() { + afterRenderEffect(() => { + const tab = this.tabs().find(t => t.active()); + tab?.element.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'nearest'}); + }); + } +} diff --git a/src/components-examples/aria/tabs/rtl/tabs-rtl-example.html b/src/components-examples/aria/tabs/rtl/tabs-rtl-example.html index 2f83927ecf01..2c0f2cad2ee4 100644 --- a/src/components-examples/aria/tabs/rtl/tabs-rtl-example.html +++ b/src/components-examples/aria/tabs/rtl/tabs-rtl-example.html @@ -1,31 +1,29 @@ -
            -
            -
              -
            • tab 1
            • -
            • tab 2
            • -
            • tab 3
            • -
            • tab 4
            • -
            • tab 5
            • -
            +
            +
            +
            Tab 1
            +
            Tab 2
            +
            Tab 3
            +
            Tab 4
            +
            Tab 5
            +
            -
            - Tabpanel 1 -
            +
            + Panel 1 +
            -
            - Tabpanel 2 -
            +
            + Panel 2 +
            -
            - Tabpanel 3 -
            +
            + Panel 3 +
            -
            - Tabpanel 4 -
            +
            + Panel 4 +
            -
            - Tabpanel 5 -
            +
            + Panel 5
            diff --git a/src/components-examples/aria/tabs/rtl/tabs-rtl-example.ts b/src/components-examples/aria/tabs/rtl/tabs-rtl-example.ts index 0189620732a8..af28e8ec9c42 100644 --- a/src/components-examples/aria/tabs/rtl/tabs-rtl-example.ts +++ b/src/components-examples/aria/tabs/rtl/tabs-rtl-example.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {afterRenderEffect, Component, viewChildren} from '@angular/core'; import {Dir} from '@angular/cdk/bidi'; import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; @@ -10,5 +10,12 @@ import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; imports: [TabList, Tab, Tabs, TabPanel, TabContent, Dir], }) export class TabsRtlExample { - selectedIndex = 0; + tabs = viewChildren(Tab); + + constructor() { + afterRenderEffect(() => { + const tab = this.tabs().find(t => t.active()); + tab?.element.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'nearest'}); + }); + } } diff --git a/src/components-examples/aria/tabs/selection-follows-focus/tabs-selection-follows-focus-example.html b/src/components-examples/aria/tabs/selection-follows-focus/tabs-selection-follows-focus-example.html index 0c7d5d88f473..b92774de566b 100644 --- a/src/components-examples/aria/tabs/selection-follows-focus/tabs-selection-follows-focus-example.html +++ b/src/components-examples/aria/tabs/selection-follows-focus/tabs-selection-follows-focus-example.html @@ -1,29 +1,29 @@ -
            -
              -
            • tab 1
            • -
            • tab 2
            • -
            • tab 3
            • -
            • tab 4
            • -
            • tab 5
            • -
            +
            +
            +
            Tab 1
            +
            Tab 2
            +
            Tab 3
            +
            Tab 4
            +
            Tab 5
            +
            -
            - Tabpanel 1 +
            + Panel 1
            -
            - Tabpanel 2 +
            + Panel 2
            -
            - Tabpanel 3 +
            + Panel 3
            -
            - Tabpanel 4 +
            + Panel 4
            -
            - Tabpanel 5 +
            + Panel 5
            diff --git a/src/components-examples/aria/tabs/selection-follows-focus/tabs-selection-follows-focus-example.ts b/src/components-examples/aria/tabs/selection-follows-focus/tabs-selection-follows-focus-example.ts index 5433a87a70cb..7e2d4cb079d6 100644 --- a/src/components-examples/aria/tabs/selection-follows-focus/tabs-selection-follows-focus-example.ts +++ b/src/components-examples/aria/tabs/selection-follows-focus/tabs-selection-follows-focus-example.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {afterRenderEffect, Component, viewChildren} from '@angular/core'; import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; /** @title Selection Follows Focus */ @@ -8,4 +8,13 @@ import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; styleUrls: ['../tabs-common.css'], imports: [TabList, Tab, Tabs, TabPanel, TabContent], }) -export class TabsSelectionFollowsFocusExample {} +export class TabsSelectionFollowsFocusExample { + tabs = viewChildren(Tab); + + constructor() { + afterRenderEffect(() => { + const tab = this.tabs().find(t => t.active()); + tab?.element.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'nearest'}); + }); + } +} diff --git a/src/components-examples/aria/tabs/tabs-common.css b/src/components-examples/aria/tabs/tabs-common.css index 9b29f96dff03..f6568449e861 100644 --- a/src/components-examples/aria/tabs/tabs-common.css +++ b/src/components-examples/aria/tabs/tabs-common.css @@ -1,80 +1,120 @@ -.example-tablist-controls { +[ngTabs] { + overflow: hidden; + border: 1px solid var(--mat-sys-outline-variant); + background-color: var(--mat-sys-surface-container-low); + border-radius: var(--mat-sys-corner-medium); +} + +[ngTabList] { display: flex; - flex-wrap: wrap; - align-items: center; - gap: 16px; - padding-bottom: 16px; + outline: none; + overflow-x: scroll; + border-bottom: 1px solid var(--mat-sys-outline-variant); } -.example-tabs { - border: 1px solid var(--mat-sys-outline); - min-height: 30vh; +[ngTabList][aria-disabled='true'] [ngTab]:not([aria-selected='true']) { + cursor: default; + color: color-mix(in srgb, var(--mat-sys-on-surface) 38%, transparent); + background-color: color-mix(in srgb, var(--mat-sys-on-surface) 12%, transparent); } -.example-tabs:has(ul[aria-orientation='vertical']) { - display: flex; +[ngTab] { + flex: 1; + outline: none; + padding: 1rem; + cursor: pointer; + text-align: center; + position: relative; + white-space: nowrap; + color: var(--mat-sys-secondary); } -.example-tablist { - gap: 8px; - margin: 0; - padding: 8px; - max-height: 50vh; - border-bottom: 1px solid var(--mat-sys-outline); - border-radius: var(--mat-sys-corner-extra-small); - display: flex; - list-style: none; - flex-direction: row; - justify-content: center; +[ngTab][aria-disabled='true'] { + cursor: default; + color: color-mix(in srgb, var(--mat-sys-on-surface) 38%, transparent); + background-color: color-mix(in srgb, var(--mat-sys-on-surface) 12%, transparent); } -.example-tablist[aria-orientation='vertical'] { - flex-direction: column; - border-bottom: initial; - border-right: 1px solid var(--mat-sys-outline); - justify-content: start; +[ngTabList]:focus-within [ngTab][aria-disabled='true'][data-active='true']::before { + outline-color: var(--mat-sys-outline); } -.example-tablist[aria-orientation='horizontal'] li::before { - display: none; +[ngTabList]:focus-within [ngTab][data-active='true']::before { + top: 3px; + left: 3px; + right: 3px; + bottom: 6px; + content: ''; + position: absolute; + outline: 2px solid var(--mat-sys-primary); + border-radius: var(--mat-sys-corner-small); } -.example-tablist[aria-orientation='horizontal'] li[aria-selected='true']::before { - display: block; +[ngTab]:not([aria-disabled='true']):hover { + background-color: color-mix(in srgb, var(--mat-sys-outline) 10%, transparent); } -.example-tablist[aria-disabled='true'] { - background-color: var(--mat-sys-surface-dim); +[ngTab]:not([aria-disabled='true'])[aria-selected='true'] { + color: var(--mat-sys-primary); + background-color: color-mix(in srgb, var(--mat-sys-primary) 5%, transparent); } -.example-tab { - gap: 16px; - padding: 16px; - display: flex; - cursor: pointer; - align-items: center; - border-radius: var(--mat-sys-corner-extra-small); +[ngTab][aria-selected='true']::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 2px; + background-color: var(--mat-sys-primary); + border-top-left-radius: var(--mat-sys-corner-small); + border-top-right-radius: var(--mat-sys-corner-small); } -.example-tablist:focus-within .example-tab:hover, -.example-tablist:focus-within .example-tab[data-active='true'] { - outline: 1px solid var(--mat-sys-outline); - background: var(--mat-sys-surface-container); +[ngTabPanel] { + flex: 1; + display: grid; + place-items: center; + min-height: 100px; } -.example-tab:focus-within { +[ngTabPanel][inert='true'] { + display: none; +} + +[ngTabPanel]:focus { + outline-offset: -4px; outline: 2px solid var(--mat-sys-primary); - background: var(--mat-sys-surface-container); + border-radius: var(--mat-sys-corner-medium); +} + +/** Vertical Orientation Styles */ + +[ngTabs]:has([ngTabList][aria-orientation='vertical']) { + display: flex; +} + +[ngTabList][aria-orientation='vertical'] { + flex-direction: column; + border-bottom: none; + border-right: 1px solid var(--mat-sys-outline-variant); } -.example-tablist:focus-within .example-tab[data-active='true'] { - background-color: var(--mat-sys-secondary-container); +[ngTabList][aria-orientation='vertical']:focus-within [ngTab][data-active='true']::before { + right: 6px; + bottom: 3px; } -.example-tab[aria-disabled='true'] { - background-color: var(--mat-sys-surface-dim); +[ngTabList][aria-orientation='vertical'] [ngTab][aria-selected='true']::after { + top: 0; + left: auto; + width: 2px; + height: 100%; + border-radius: 0; + border-top-left-radius: var(--mat-sys-corner-small); + border-bottom-left-radius: var(--mat-sys-corner-small); } -.example-tabpanel { - margin: 8px; +[ngTabList][aria-orientation='vertical'] [ngTab] { + padding: 1rem 2rem; } diff --git a/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.css b/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.css new file mode 100644 index 000000000000..245fffb718f4 --- /dev/null +++ b/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.css @@ -0,0 +1,6 @@ +.example-tablist-controls { + gap: 1rem; + display: flex; + flex-wrap: wrap; + padding: 2rem 0; +} diff --git a/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.html b/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.html index c33f5e9481f0..74effd360596 100644 --- a/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.html +++ b/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.html @@ -1,7 +1,7 @@
            Wrap Disabled - Skip Disabled + Soft Disabled Orientation @@ -33,36 +33,47 @@ Tab 1 Tab 2 Tab 3 + Tab 4 + Tab 5
            - -
            -
              +
              -
            • tab 1
            • -
            • tab 2
            • -
            • tab 3
            • -
            +
            Tab 1
            +
            Tab 2
            +
            Tab 3
            +
            Tab 4
            +
            Tab 5
            +
            + +
            + Panel 1 +
            -
            - Tabpanel 1 +
            + Panel 2
            -
            - Tabpanel 2 + +
            + Panel 3
            -
            - Tabpanel 3 + +
            + Panel 4 +
            + +
            + Panel 5
            - diff --git a/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.ts b/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.ts index 44e274738a37..bf80136ee106 100644 --- a/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.ts +++ b/src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {afterRenderEffect, Component, viewChildren} from '@angular/core'; import {MatCheckboxModule} from '@angular/material/checkbox'; import {Tabs, TabList, Tab, TabPanel, TabContent} from '@angular/aria/tabs'; import {MatFormFieldModule} from '@angular/material/form-field'; @@ -9,7 +9,7 @@ import {FormControl, ReactiveFormsModule} from '@angular/forms'; @Component({ selector: 'tabs-configurable-example', templateUrl: 'tabs-configurable-example.html', - styleUrls: ['../tabs-common.css'], + styleUrls: ['../tabs-common.css', 'tabs-configurable-example.css'], imports: [ Tabs, TabList, @@ -30,5 +30,14 @@ export class TabsConfigurableExample { wrap = new FormControl(true, {nonNullable: true}); disabled = new FormControl(false, {nonNullable: true}); - skipDisabled = new FormControl(true, {nonNullable: true}); + softDisabled = new FormControl(true, {nonNullable: true}); + + tabs = viewChildren(Tab); + + constructor() { + afterRenderEffect(() => { + const tab = this.tabs().find(tab => tab.active()); + tab?.element.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'nearest'}); + }); + } } diff --git a/src/components-examples/aria/tabs/vertical-orientation/tabs-vertical-example.html b/src/components-examples/aria/tabs/vertical-orientation/tabs-vertical-example.html index fdafd1577515..132f776c106c 100644 --- a/src/components-examples/aria/tabs/vertical-orientation/tabs-vertical-example.html +++ b/src/components-examples/aria/tabs/vertical-orientation/tabs-vertical-example.html @@ -1,29 +1,29 @@ -
            -
              -
            • tab 1
            • -
            • tab 2
            • -
            • tab 3
            • -
            • tab 4
            • -
            • tab 5
            • -
            +
            +
            +
            Tab 1
            +
            Tab 2
            +
            Tab 3
            +
            Tab 4
            +
            Tab 5
            +
            -
            - Tabpanel 1 +
            + Panel 1
            -
            - Tabpanel 2 +
            + Panel 2
            -
            - Tabpanel 3 +
            + Panel 3
            -
            - Tabpanel 4 +
            + Panel 4
            -
            - Tabpanel 5 +
            + Panel 5
            diff --git a/src/components-examples/aria/tabs/vertical-orientation/tabs-vertical-example.ts b/src/components-examples/aria/tabs/vertical-orientation/tabs-vertical-example.ts index ceb529996151..626a1b9bee3d 100644 --- a/src/components-examples/aria/tabs/vertical-orientation/tabs-vertical-example.ts +++ b/src/components-examples/aria/tabs/vertical-orientation/tabs-vertical-example.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {afterRenderEffect, Component, viewChildren} from '@angular/core'; import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; /** @title Vertical */ @@ -8,4 +8,13 @@ import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs'; styleUrls: ['../tabs-common.css'], imports: [TabList, Tab, Tabs, TabPanel, TabContent], }) -export class TabsVerticalExample {} +export class TabsVerticalExample { + tabs = viewChildren(Tab); + + constructor() { + afterRenderEffect(() => { + const tab = this.tabs().find(t => t.active()); + tab?.element.scrollIntoView({behavior: 'smooth', block: 'nearest', inline: 'nearest'}); + }); + } +} diff --git a/src/components-examples/aria/toolbar/BUILD.bazel b/src/components-examples/aria/toolbar/BUILD.bazel index aac5f1eb7eed..a6dcbf508488 100644 --- a/src/components-examples/aria/toolbar/BUILD.bazel +++ b/src/components-examples/aria/toolbar/BUILD.bazel @@ -12,7 +12,8 @@ ng_project( deps = [ "//:node_modules/@angular/core", "//:node_modules/@angular/forms", - "//src/aria/radio-group", + "//src/aria/combobox", + "//src/aria/listbox", "//src/aria/toolbar", "//src/cdk/a11y", "//src/material/checkbox", diff --git a/src/components-examples/aria/toolbar/index.ts b/src/components-examples/aria/toolbar/index.ts index 42e92a97467b..89582a318a90 100644 --- a/src/components-examples/aria/toolbar/index.ts +++ b/src/components-examples/aria/toolbar/index.ts @@ -1,4 +1,5 @@ export {ToolbarBasicHorizontalExample} from './toolbar-basic-horizontal/toolbar-basic-horizontal-example'; export {ToolbarBasicVerticalExample} from './toolbar-basic-vertical/toolbar-basic-vertical-example'; export {ToolbarConfigurableExample} from './toolbar-configurable/toolbar-configurable-example'; -export {ToolbarSkipDisabledExample} from './toolbar-skip-disabled/toolbar-skip-disabled-example'; +export {ToolbarRtlExample} from './toolbar-rtl/toolbar-rtl-example'; +export {ToolbarHardDisabledExample} from './toolbar-hard-disabled/toolbar-hard-disabled-example'; diff --git a/src/components-examples/aria/toolbar/simple-toolbar.ts b/src/components-examples/aria/toolbar/simple-toolbar.ts new file mode 100644 index 000000000000..56ed29dbd183 --- /dev/null +++ b/src/components-examples/aria/toolbar/simple-toolbar.ts @@ -0,0 +1,142 @@ +import { + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, +} from '@angular/aria/combobox'; +import {Listbox, Option} from '@angular/aria/listbox'; +import {ToolbarWidget} from '@angular/aria/toolbar'; +import {Dir, Directionality} from '@angular/cdk/bidi'; +import { + afterRenderEffect, + Component, + Directive, + ElementRef, + inject, + signal, + viewChild, +} from '@angular/core'; + +@Directive({ + selector: 'button[toolbar-button]', + hostDirectives: [{directive: ToolbarWidget, inputs: ['value', 'disabled']}], + host: { + type: 'button', + class: 'example-button material-symbols-outlined', + '[aria-label]': 'widget.value()', + }, +}) +export class SimpleToolbarButton { + widget = inject(ToolbarWidget); +} + +@Directive({ + selector: 'button[toolbar-toggle-button]', + hostDirectives: [{directive: ToolbarWidget, inputs: ['value']}], + host: { + type: 'button', + class: 'example-button material-symbols-outlined', + '[aria-pressed]': 'widget.selected()', + '[aria-label]': 'widget.value()', + }, +}) +export class SimpleToolbarToggleButton { + widget = inject(ToolbarWidget); +} + +@Directive({ + selector: 'button[toolbar-radio-button]', + hostDirectives: [{directive: ToolbarWidget, inputs: ['value', 'disabled']}], + host: { + role: 'radio', + type: 'button', + class: 'example-button material-symbols-outlined', + '[aria-checked]': 'widget.selected()', + '[aria-label]': 'widget.value()', + }, +}) +export class SimpleToolbarRadioButton { + widget = inject(ToolbarWidget); +} + +@Component({ + selector: 'combobox', + imports: [ + Dir, + Combobox, + ComboboxInput, + ComboboxPopup, + ComboboxPopupContainer, + Listbox, + Option, + ToolbarWidget, + ], + styleUrl: 'toolbar-common.css', + host: {class: 'example-combobox-container'}, + template: ` +
            +
            + + arrow_drop_down +
            + +
            + +
            + @for (option of options; track option) { +
            + {{option}} + +
            + } +
            +
            +
            +
            + `, +}) +export class SimpleCombobox { + dir = inject(Directionality).valueSignal; + popover = viewChild('popover'); + listbox = viewChild>(Listbox); + combobox = viewChild>(Combobox); + + value = signal('Normal text'); + options = ['Normal text', 'Title', 'Subtitle', 'Heading 1', 'Heading 2', 'Heading 3']; + + constructor() { + afterRenderEffect(() => { + const popover = this.popover()!; + const combobox = this.combobox()!; + combobox.expanded() ? this.showPopover() : popover.nativeElement.hidePopover(); + + this.listbox()?.scrollActiveItemIntoView(); + }); + } + + showPopover() { + const popover = this.popover()!; + const combobox = this.combobox()!; + + const comboboxRect = combobox.inputElement()?.getBoundingClientRect(); + const popoverEl = popover.nativeElement; + + if (comboboxRect) { + popoverEl.style.width = `${comboboxRect.width}px`; + popoverEl.style.top = `${comboboxRect.bottom + 4}px`; + popoverEl.style.left = `${comboboxRect.left - 1}px`; + } + + popover.nativeElement.showPopover(); + } +} diff --git a/src/components-examples/aria/toolbar/toolbar-basic-horizontal/toolbar-basic-horizontal-example.html b/src/components-examples/aria/toolbar/toolbar-basic-horizontal/toolbar-basic-horizontal-example.html index caa014e61494..94908c0c3209 100644 --- a/src/components-examples/aria/toolbar/toolbar-basic-horizontal/toolbar-basic-horizontal-example.html +++ b/src/components-examples/aria/toolbar/toolbar-basic-horizontal/toolbar-basic-horizontal-example.html @@ -1,43 +1,41 @@ -
            -
            - - - -
              - @for (alignment of alignments; track alignment) { -
            • - - {{ alignment.label }} -
            • - } -
            - +
            +
            +
            + +
            + + + +
            + + + +
            + + + + + + + +
            + + + +
            + + + +
            + + + +
            +
            diff --git a/src/components-examples/aria/toolbar/toolbar-basic-horizontal/toolbar-basic-horizontal-example.ts b/src/components-examples/aria/toolbar/toolbar-basic-horizontal/toolbar-basic-horizontal-example.ts index 45af7aac691d..8ec2ff47c8c7 100644 --- a/src/components-examples/aria/toolbar/toolbar-basic-horizontal/toolbar-basic-horizontal-example.ts +++ b/src/components-examples/aria/toolbar/toolbar-basic-horizontal/toolbar-basic-horizontal-example.ts @@ -1,28 +1,25 @@ import {Component} from '@angular/core'; -import {Toolbar, ToolbarWidget} from '@angular/aria/toolbar'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; -import {LiveAnnouncer} from '@angular/cdk/a11y'; +import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar'; +import { + SimpleCombobox, + SimpleToolbarButton, + SimpleToolbarRadioButton, + SimpleToolbarToggleButton, +} from '../simple-toolbar'; /** @title Basic Horizontal Toolbar Example */ @Component({ selector: 'toolbar-basic-horizontal-example', templateUrl: 'toolbar-basic-horizontal-example.html', styleUrl: '../toolbar-common.css', - imports: [RadioButton, RadioGroup, Toolbar, ToolbarWidget], + imports: [ + Toolbar, + ToolbarWidget, + ToolbarWidgetGroup, + SimpleCombobox, + SimpleToolbarButton, + SimpleToolbarRadioButton, + SimpleToolbarToggleButton, + ], }) -export class ToolbarBasicHorizontalExample { - constructor(private _liveAnnouncer: LiveAnnouncer) {} - alignments = [ - {value: 'left', label: 'Left'}, - {value: 'center', label: 'Center'}, - {value: 'right', label: 'Right'}, - ]; - format(tool: string) { - console.log(`Tool activated: ${tool}`); - this._liveAnnouncer.announce(`${tool} applied`, 'polite'); - } - test(action: string) { - console.log(`Action triggered: ${action}`); - this._liveAnnouncer.announce(`${action} button activated`, 'polite'); - } -} +export class ToolbarBasicHorizontalExample {} diff --git a/src/components-examples/aria/toolbar/toolbar-basic-vertical/toolbar-basic-vertical-example.html b/src/components-examples/aria/toolbar/toolbar-basic-vertical/toolbar-basic-vertical-example.html index eec277e9de26..72d7096f48f6 100644 --- a/src/components-examples/aria/toolbar/toolbar-basic-vertical/toolbar-basic-vertical-example.html +++ b/src/components-examples/aria/toolbar/toolbar-basic-vertical/toolbar-basic-vertical-example.html @@ -1,43 +1,34 @@ -
            -
            - - - -
              - @for (alignment of alignments; track alignment) { -
            • - - {{ alignment.label }} -
            • - } -
            - +
            +
            +
            + +
            + + + +
            + + + +
            + + + +
            + + + +
            +
            diff --git a/src/components-examples/aria/toolbar/toolbar-basic-vertical/toolbar-basic-vertical-example.ts b/src/components-examples/aria/toolbar/toolbar-basic-vertical/toolbar-basic-vertical-example.ts index fec7482882d1..62afddef2fc4 100644 --- a/src/components-examples/aria/toolbar/toolbar-basic-vertical/toolbar-basic-vertical-example.ts +++ b/src/components-examples/aria/toolbar/toolbar-basic-vertical/toolbar-basic-vertical-example.ts @@ -1,28 +1,23 @@ import {Component} from '@angular/core'; -import {Toolbar, ToolbarWidget} from '@angular/aria/toolbar'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; -import {LiveAnnouncer} from '@angular/cdk/a11y'; +import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar'; +import { + SimpleToolbarButton, + SimpleToolbarRadioButton, + SimpleToolbarToggleButton, +} from '../simple-toolbar'; /** @title Basic Vertical Toolbar Example */ @Component({ selector: 'toolbar-basic-vertical-example', templateUrl: 'toolbar-basic-vertical-example.html', styleUrl: '../toolbar-common.css', - imports: [RadioButton, RadioGroup, Toolbar, ToolbarWidget], + imports: [ + Toolbar, + ToolbarWidget, + ToolbarWidgetGroup, + SimpleToolbarButton, + SimpleToolbarRadioButton, + SimpleToolbarToggleButton, + ], }) -export class ToolbarBasicVerticalExample { - constructor(private _liveAnnouncer: LiveAnnouncer) {} - alignments = [ - {value: 'left', label: 'Left'}, - {value: 'center', label: 'Center'}, - {value: 'right', label: 'Right'}, - ]; - format(tool: string) { - console.log(`Tool activated: ${tool}`); - this._liveAnnouncer.announce(`${tool} applied`, 'polite'); - } - test(action: string) { - console.log(`Action triggered: ${action}`); - this._liveAnnouncer.announce(`${action} button activated`, 'polite'); - } -} +export class ToolbarBasicVerticalExample {} diff --git a/src/components-examples/aria/toolbar/toolbar-common.css b/src/components-examples/aria/toolbar/toolbar-common.css index 1e347bf97904..4be1ff833de1 100644 --- a/src/components-examples/aria/toolbar/toolbar-common.css +++ b/src/components-examples/aria/toolbar/toolbar-common.css @@ -1,7 +1,3 @@ -.example-container { - padding-bottom: 32px; -} - .example-heading { margin: 16px 0 4px; } @@ -15,120 +11,177 @@ } .example-toolbar { - display: flex; - flex-direction: column; - padding: 8px; - width: 50%; - border: 1px solid var(--mat-sys-outline); - border-radius: var(--mat-sys-corner-extra-small); gap: 16px; -} -.example-toolbar[aria-orientation='horizontal'] { + padding: 8px; + display: flex; + width: -webkit-fit-content; + width: -moz-fit-content; flex-direction: row; - width: 100%; + border-radius: var(--mat-sys-corner-small); + background-color: var(--mat-sys-surface); + border: 1px solid color-mix(in srgb, var(--mat-sys-outline) 50%, transparent); } -.example-radio-group { +.example-toolbar[aria-orientation='vertical'], +.example-toolbar[aria-orientation='vertical'] .example-group { + flex-direction: column; +} + +.example-group { gap: 4px; - margin: 0; - padding: 8px; - max-height: 300px; - border: 1px solid var(--mat-sys-outline); - border-radius: var(--mat-sys-corner-extra-small); display: flex; - list-style: none; - flex-direction: column; - overflow: scroll; } -.example-radio-group[aria-orientation='horizontal'] { - flex-direction: row; - width: 100%; +.example-button { + cursor: pointer; + opacity: 0.875; + font-size: 1.25rem; + padding: 6px 8px; + background-color: transparent; + border: 1px solid transparent; + border-radius: var(--mat-sys-corner-extra-small); } -.example-radio-group[aria-disabled='true'] { - background-color: var(--mat-sys-surface-dim); - pointer-events: none; +.example-button:focus, +.example-button:hover { + background: color-mix(in srgb, var(--mat-sys-outline) 10%, transparent); } -.example-radio-group label { - padding: 16px; - flex-shrink: 0; +.example-button:active { + background: color-mix(in srgb, var(--mat-sys-outline) 20%, transparent); } -.example-radio-button { - gap: 16px; - padding: 16px; +.example-button[aria-pressed='true'], +.example-button[aria-checked='true'] { + color: color-mix(in srgb, var(--mat-sys-primary) 90%, black); + background: color-mix(in srgb, var(--mat-sys-primary) 15%, transparent); +} + +.example-button:focus { + border-color: var(--mat-sys-primary); + outline: 2px solid color-mix(in srgb, var(--mat-sys-primary) 50%, transparent); +} + +.example-button[aria-disabled='true'] { + cursor: default; + opacity: 0.45; +} + +.example-separator { + width: 1px; + background: color-mix(in srgb, var(--mat-sys-outline) 50%, transparent); +} + +.example-toolbar[aria-orientation='vertical'] .example-separator { + height: 1px; + width: auto; +} + +.example-combobox-container { + border-radius: var(--mat-sys-corner-extra-small); + border: 1px solid color-mix(in srgb, var(--mat-sys-outline) 50%, transparent); +} + +.example-combobox-container:focus-within { + border-color: var(--mat-sys-primary); + outline: 2px solid color-mix(in srgb, var(--mat-sys-primary) 50%, transparent); +} + +.example-combobox { + height: 100%; + width: 10rem; + display: flex; + position: relative; + flex-direction: column; +} + +.example-combobox-input-container { display: flex; - cursor: pointer; position: relative; align-items: center; border-radius: var(--mat-sys-corner-extra-small); + height: 100%; } -/* Basic visual indicator for the radio button */ -.example-radio-indicator { - width: 16px; - height: 16px; - border-radius: 50%; - border: 2px solid var(--mat-sys-outline); - display: inline-block; - position: relative; +.example-combobox-input { + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + height: 100%; + width: 100%; + border: none; + outline: none; + font-size: 0.8rem; + padding: 0 0.5rem; + border-radius: var(--mat-sys-corner-extra-small); + background-color: transparent; } -.example-radio-button[aria-checked='true'] .example-radio-indicator { - border-color: var(--mat-sys-primary); +.example-combobox-input::-moz-selection { + background: transparent; } -.example-radio-button[aria-checked='true'] .example-radio-indicator::after { - content: ''; - display: block; - width: 8px; - height: 8px; - border-radius: 50%; - background-color: var(--mat-sys-primary); - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); +.example-combobox-input::-webkit-selection { + background: transparent; } -.example-radio-button[aria-disabled='true'][aria-checked='true'] .example-radio-indicator::after { - background-color: var(--mat-sys-outline); +.example-arrow-icon { + padding: 0 0.2rem; + position: absolute; + right: 0; + opacity: 0.7; + transition: transform 0.2s ease; + pointer-events: none; } -.example-radio-button[data-active='true'], -.example-radio-button[aria-disabled='false']:hover { - outline: 2px solid var(--mat-sys-outline); - background: var(--mat-sys-surface-container); +.example-combobox[dir='rtl'] .example-arrow-icon { + right: auto; + left: 0; } -.example-radio-button[aria-disabled='false']:focus-within { - outline: 2px solid var(--mat-sys-primary); - background: var(--mat-sys-surface-container); +.example-combobox-input[aria-expanded='true'] + .example-arrow-icon { + transform: rotate(180deg); } -.example-radio-button[data-active='true'][aria-disabled='true'], -.example-radio-button[aria-disabled='true']:focus-within { - outline: 2px solid var(--mat-sys-outline); +.example-popover { + margin: 0; + padding: 0; + border: 1px solid color-mix(in srgb, var(--mat-sys-outline) 50%, transparent); + border-radius: var(--mat-sys-corner-extra-small); + background-color: var(--mat-sys-surface); } -.example-radio-button[aria-disabled='true'] { - cursor: default; +.example-option { + cursor: pointer; + font-size: 0.8rem; + padding: 0.5rem; + display: flex; + overflow: hidden; + flex-shrink: 0; + align-items: center; + justify-content: space-between; } -.example-radio-button[aria-disabled='true'] span:not(.example-radio-indicator) { - opacity: 0.3; +.example-option:hover { + background: color-mix(in srgb, var(--mat-sys-outline) 10%, transparent); } -.example-radio-button[aria-disabled='true']::before { - content: ''; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; +.example-option[data-active='true'] { border-radius: var(--mat-sys-corner-extra-small); - background-color: var(--mat-sys-on-surface); - opacity: var(--mat-sys-focus-state-layer-opacity); + outline: 1px solid var(--mat-sys-primary); + outline-offset: -1px; +} + +.example-option[aria-selected='true'] { + color: var(--mat-sys-primary); + background: color-mix(in srgb, var(--mat-sys-primary) 10%, transparent); +} + +.example-option-icon { + font-size: 1rem; +} + +.example-option[aria-selected='false'] .example-option-icon { + visibility: hidden; } diff --git a/src/components-examples/aria/toolbar/toolbar-configurable/toolbar-configurable-example.html b/src/components-examples/aria/toolbar/toolbar-configurable/toolbar-configurable-example.html index 1506f1b93a4a..813a2b5ea388 100644 --- a/src/components-examples/aria/toolbar/toolbar-configurable/toolbar-configurable-example.html +++ b/src/components-examples/aria/toolbar/toolbar-configurable/toolbar-configurable-example.html @@ -1,9 +1,9 @@

            Toolbar Controls

            - Skip Disabled - Wrap - Disabled + Soft Disabled + Wrap + Disabled Orientation @@ -12,26 +12,23 @@

            Toolbar Controls

            -

            Radio Group Controls

            + +

            Button

            - Disabled - Readonly - Disabled Radio Options - - @for (fruit of fruits; track fruit) { - {{fruit}} + Disabled Buttons + + @for (widget of widgets; track widget) { + {{widget}} } -
            -

            Button

            -
            + - Disabled Buttons - - @for (fruit of buttonFruits; track fruit) { - {{fruit}} + Disabled Groups + + @for (group of groups; track group) { + {{group}} } @@ -41,67 +38,73 @@

            Button

            - -
              - @for (fruit of fruits; track fruit) { - @let optionDisabled = disabledOptions.includes(fruit); -
            • - - {{ fruit }} -
            • - } -
            -
              - @for (fruit of fruits; track fruit) { - @let optionDisabled = disabledOptions.includes(fruit); -
            • - - {{ fruit }} -
            • - } -
            - - + +
            + + + +
            + + + +
            + + @if (orientation === 'horizontal') { + + + } + + + +
            - Cherry - - + + +
            + + + +
            - Date - + + + +
            diff --git a/src/components-examples/aria/toolbar/toolbar-configurable/toolbar-configurable-example.ts b/src/components-examples/aria/toolbar/toolbar-configurable/toolbar-configurable-example.ts index abadbcb38af6..1306d9eea92e 100644 --- a/src/components-examples/aria/toolbar/toolbar-configurable/toolbar-configurable-example.ts +++ b/src/components-examples/aria/toolbar/toolbar-configurable/toolbar-configurable-example.ts @@ -1,21 +1,29 @@ import {Component} from '@angular/core'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; import {MatCheckboxModule} from '@angular/material/checkbox'; import {MatFormFieldModule} from '@angular/material/form-field'; import {MatSelectModule} from '@angular/material/select'; -import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; -import {Toolbar, ToolbarWidget} from '@angular/aria/toolbar'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar'; +import { + SimpleCombobox, + SimpleToolbarButton, + SimpleToolbarRadioButton, + SimpleToolbarToggleButton, +} from '../simple-toolbar'; -/** @title Configurable CDK Radio Group */ +/** @title Configurable Aria Toolbar Example */ @Component({ selector: 'toolbar-configurable-example', templateUrl: 'toolbar-configurable-example.html', styleUrl: '../toolbar-common.css', imports: [ - RadioGroup, - RadioButton, Toolbar, ToolbarWidget, + ToolbarWidgetGroup, + SimpleCombobox, + SimpleToolbarButton, + SimpleToolbarRadioButton, + SimpleToolbarToggleButton, MatCheckboxModule, MatFormFieldModule, MatSelectModule, @@ -24,23 +32,32 @@ import {Toolbar, ToolbarWidget} from '@angular/aria/toolbar'; ], }) export class ToolbarConfigurableExample { - skipDisabled = new FormControl(false, {nonNullable: true}); - wrap = new FormControl(true, {nonNullable: true}); - toolbarDisabled = new FormControl(false, {nonNullable: true}); + wrap = true; + softDisabled = true; + toolbarDisabled = false; orientation: 'vertical' | 'horizontal' = 'horizontal'; - fruits = ['Apple', 'Apricot', 'Banana']; - buttonFruits = ['Pear', 'Blueberry', 'Cherry', 'Date']; + widgets = [ + 'Undo', + 'Redo', + 'Bold', + 'Italic', + 'Underline', + 'Text style', + 'Align left', + 'Align center', + 'Align right', + 'Checklist', + 'Bullet list', + 'Numbered list', + ]; - // Radio group controls - disabled = new FormControl(false, {nonNullable: true}); - readonly = new FormControl(false, {nonNullable: true}); + groups = ['Alignment options', 'List options']; - // Control for which radio options are individually disabled - disabledOptions: string[] = ['Banana']; - disabledButtonOptions: string[] = ['Pear']; + disabledGroups: string[] = []; + disabledWidgets: string[] = []; - test(x: String) { - console.log(x); + isDisabled(value: string) { + return this.disabledWidgets.includes(value) || this.disabledGroups.includes(value); } } diff --git a/src/components-examples/aria/toolbar/toolbar-hard-disabled/toolbar-hard-disabled-example.html b/src/components-examples/aria/toolbar/toolbar-hard-disabled/toolbar-hard-disabled-example.html new file mode 100644 index 000000000000..6e94bd79fae4 --- /dev/null +++ b/src/components-examples/aria/toolbar/toolbar-hard-disabled/toolbar-hard-disabled-example.html @@ -0,0 +1,52 @@ +
            +
            +
            + + +
            + + + +
            + + + +
            + + + + + + + +
            + + + +
            + + + +
            + + + +
            +
            +
            diff --git a/src/components-examples/aria/toolbar/toolbar-hard-disabled/toolbar-hard-disabled-example.ts b/src/components-examples/aria/toolbar/toolbar-hard-disabled/toolbar-hard-disabled-example.ts new file mode 100644 index 000000000000..2d1c27e4863c --- /dev/null +++ b/src/components-examples/aria/toolbar/toolbar-hard-disabled/toolbar-hard-disabled-example.ts @@ -0,0 +1,25 @@ +import {Component} from '@angular/core'; +import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar'; +import { + SimpleCombobox, + SimpleToolbarButton, + SimpleToolbarRadioButton, + SimpleToolbarToggleButton, +} from '../simple-toolbar'; + +/** @title Hard Disabled Toolbar Example */ +@Component({ + selector: 'toolbar-hard-disabled-example', + templateUrl: 'toolbar-hard-disabled-example.html', + styleUrl: '../toolbar-common.css', + imports: [ + Toolbar, + ToolbarWidget, + ToolbarWidgetGroup, + SimpleCombobox, + SimpleToolbarButton, + SimpleToolbarRadioButton, + SimpleToolbarToggleButton, + ], +}) +export class ToolbarHardDisabledExample {} diff --git a/src/components-examples/aria/toolbar/toolbar-rtl/toolbar-rtl-example.html b/src/components-examples/aria/toolbar/toolbar-rtl/toolbar-rtl-example.html new file mode 100644 index 000000000000..519f5e2eed1a --- /dev/null +++ b/src/components-examples/aria/toolbar/toolbar-rtl/toolbar-rtl-example.html @@ -0,0 +1,41 @@ +
            +
            +
            + + +
            + + + +
            + + + +
            + + + + + + + +
            + + + +
            + + + +
            + + + +
            +
            +
            diff --git a/src/components-examples/aria/toolbar/toolbar-rtl/toolbar-rtl-example.ts b/src/components-examples/aria/toolbar/toolbar-rtl/toolbar-rtl-example.ts new file mode 100644 index 000000000000..ddfca5a98528 --- /dev/null +++ b/src/components-examples/aria/toolbar/toolbar-rtl/toolbar-rtl-example.ts @@ -0,0 +1,27 @@ +import {Component} from '@angular/core'; +import {Dir} from '@angular/cdk/bidi'; +import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar'; +import { + SimpleCombobox, + SimpleToolbarButton, + SimpleToolbarRadioButton, + SimpleToolbarToggleButton, +} from '../simple-toolbar'; + +/** @title Basic RTL Toolbar Example */ +@Component({ + selector: 'toolbar-rtl-example', + templateUrl: 'toolbar-rtl-example.html', + styleUrl: '../toolbar-common.css', + imports: [ + Dir, + Toolbar, + ToolbarWidget, + ToolbarWidgetGroup, + SimpleCombobox, + SimpleToolbarButton, + SimpleToolbarRadioButton, + SimpleToolbarToggleButton, + ], +}) +export class ToolbarRtlExample {} diff --git a/src/components-examples/aria/toolbar/toolbar-skip-disabled/toolbar-skip-disabled-example.html b/src/components-examples/aria/toolbar/toolbar-skip-disabled/toolbar-skip-disabled-example.html deleted file mode 100644 index b67a71410005..000000000000 --- a/src/components-examples/aria/toolbar/toolbar-skip-disabled/toolbar-skip-disabled-example.html +++ /dev/null @@ -1,48 +0,0 @@ -
            -
            - - - -
              - @for (alignment of alignments; track alignment) { -
            • - - {{ alignment.label }} -
            • - } -
            - -
            -
            diff --git a/src/components-examples/aria/toolbar/toolbar-skip-disabled/toolbar-skip-disabled-example.ts b/src/components-examples/aria/toolbar/toolbar-skip-disabled/toolbar-skip-disabled-example.ts deleted file mode 100644 index 827b85bc5442..000000000000 --- a/src/components-examples/aria/toolbar/toolbar-skip-disabled/toolbar-skip-disabled-example.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {Component} from '@angular/core'; -import {Toolbar, ToolbarWidget} from '@angular/aria/toolbar'; -import {RadioGroup, RadioButton} from '@angular/aria/radio-group'; -import {LiveAnnouncer} from '@angular/cdk/a11y'; - -/** @title Skip Disabled Toolbar Example */ -@Component({ - selector: 'toolbar-skip-disabled-example', - templateUrl: 'toolbar-skip-disabled-example.html', - styleUrl: '../toolbar-common.css', - imports: [RadioButton, RadioGroup, Toolbar, ToolbarWidget], -}) -export class ToolbarSkipDisabledExample { - constructor(private _liveAnnouncer: LiveAnnouncer) {} - alignments = [ - {value: 'left', label: 'Left'}, - {value: 'center', label: 'Center'}, - {value: 'right', label: 'Right'}, - ]; - - // Control for which radio options are individually disabled - disabledOptions: string[] = ['center']; - - format(tool: string) { - console.log(`Tool activated: ${tool}`); - this._liveAnnouncer.announce(`${tool} applied`, 'polite'); - } - test(action: string) { - console.log(`Action triggered: ${action}`); - this._liveAnnouncer.announce(`${action} button activated`, 'polite'); - } -} diff --git a/src/components-examples/aria/tree/tree-common.css b/src/components-examples/aria/tree/tree-common.css index 643fb5ab385d..959a7f065b39 100644 --- a/src/components-examples/aria/tree/tree-common.css +++ b/src/components-examples/aria/tree/tree-common.css @@ -21,6 +21,20 @@ min-width: 24rem; } +.example-tree[aria-disabled='true'] { + background-color: var(--mat-sys-surface-variant); + color: var(--mat-sys-on-surface-variant); + cursor: not-allowed; +} + +.example-tree[aria-disabled='true']:focus-within { + outline: 2px solid var(--mat-sys-primary); +} + +.example-tree[aria-disabled='true'] .example-tree-item { + pointer-events: none; +} + .example-tree-item { cursor: pointer; list-style: none; diff --git a/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.html b/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.html index 7a308eabebc9..9fbccf4943c4 100644 --- a/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.html +++ b/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.html @@ -2,7 +2,7 @@ Wrap Multi Disabled - Skip Disabled + Soft Disabled Nav Mode @@ -34,9 +34,9 @@ [selectionMode]="selectionMode" [focusMode]="focusMode" [wrap]="wrap.value" - [skipDisabled]="skipDisabled.value" + [softDisabled]="softDisabled.value" [nav]="nav.value" - [(value)]="selectedValues" + [(values)]="selectedValues" #tree="ngTree" > @for (node of nodes; track node.value) { -
          • - - - {{ node.name }} - -
          • + @if (nav.value) { +
          • + + + + {{ node.name }} + + +
          • - @if (node.children) { -
              - - - -
            - } + @if (node.children) { +
              + + + +
            + } + } @else { +
          • + + + {{ node.name }} + +
          • + + @if (node.children) { +
              + + + +
            + } + } }
            diff --git a/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.ts b/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.ts index 1cb048a9c954..d193eb1cdffb 100644 --- a/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.ts +++ b/src/components-examples/aria/tree/tree-configurable/tree-configurable-example.ts @@ -40,7 +40,7 @@ export class TreeConfigurableExample { multi = new FormControl(false, {nonNullable: true}); disabled = new FormControl(false, {nonNullable: true}); wrap = new FormControl(true, {nonNullable: true}); - skipDisabled = new FormControl(true, {nonNullable: true}); + softDisabled = new FormControl(true, {nonNullable: true}); nav = new FormControl(false, {nonNullable: true}); selectedValues = model(['package.json']); diff --git a/src/components-examples/aria/tree/tree-data.ts b/src/components-examples/aria/tree/tree-data.ts index 8436794a43b8..a515bda22e41 100644 --- a/src/components-examples/aria/tree/tree-data.ts +++ b/src/components-examples/aria/tree/tree-data.ts @@ -10,6 +10,7 @@ export type TreeNode = { value: string; children?: TreeNode[]; disabled?: boolean; + expanded?: boolean; }; export const NODES: TreeNode[] = [ @@ -21,6 +22,7 @@ export const NODES: TreeNode[] = [ {name: 'favicon.ico', value: 'public/favicon.ico'}, {name: 'styles.css', value: 'public/styles.css'}, ], + expanded: false, }, { name: 'src', @@ -34,25 +36,33 @@ export const NODES: TreeNode[] = [ {name: 'app.module.ts', value: 'src/app/app.module.ts', disabled: true}, {name: 'app.css', value: 'src/app/app.css'}, ], + expanded: false, }, { name: 'assets', value: 'src/assets', children: [{name: 'logo.png', value: 'src/assets/logo.png'}], + expanded: false, }, { name: 'environments', value: 'src/environments', children: [ - {name: 'environment.prod.ts', value: 'src/environments/environment.prod.ts'}, + { + name: 'environment.prod.ts', + value: 'src/environments/environment.prod.ts', + expanded: false, + }, {name: 'environment.ts', value: 'src/environments/environment.ts'}, ], + expanded: false, }, {name: 'main.ts', value: 'src/main.ts'}, {name: 'polyfills.ts', value: 'src/polyfills.ts'}, {name: 'styles.css', value: 'src/styles.css', disabled: true}, {name: 'test.ts', value: 'src/test.ts'}, ], + expanded: false, }, {name: 'angular.json', value: 'angular.json'}, {name: 'package.json', value: 'package.json'}, diff --git a/src/components-examples/aria/tree/tree-disabled-focusable/tree-disabled-focusable-example.html b/src/components-examples/aria/tree/tree-disabled-focusable/tree-disabled-focusable-example.html index 25346aa88698..f899c831e099 100644 --- a/src/components-examples/aria/tree/tree-disabled-focusable/tree-disabled-focusable-example.html +++ b/src/components-examples/aria/tree/tree-disabled-focusable/tree-disabled-focusable-example.html @@ -1,4 +1,4 @@ -
              +
                +
                  + + + diff --git a/src/components-examples/material/list/list-action/list-action-example.ts b/src/components-examples/material/list/list-action/list-action-example.ts new file mode 100644 index 000000000000..c095b77e9d9a --- /dev/null +++ b/src/components-examples/material/list/list-action/list-action-example.ts @@ -0,0 +1,16 @@ +import {Component} from '@angular/core'; +import {MatListModule} from '@angular/material/list'; + +/** + * @title Action list + */ +@Component({ + selector: 'list-action-example', + templateUrl: 'list-action-example.html', + imports: [MatListModule], +}) +export class ListActionExample { + action(task: string) { + window.alert(task); + } +} diff --git a/src/components-examples/material/list/list-avatar/list-avatar-example.html b/src/components-examples/material/list/list-avatar/list-avatar-example.html new file mode 100644 index 000000000000..2e4b6dbfc7b3 --- /dev/null +++ b/src/components-examples/material/list/list-avatar/list-avatar-example.html @@ -0,0 +1,11 @@ + + + + Shiba Inu + + + + + Other Shiba Inu + + diff --git a/src/components-examples/material/list/list-avatar/list-avatar-example.ts b/src/components-examples/material/list/list-avatar/list-avatar-example.ts new file mode 100644 index 000000000000..d2081b9bbc6d --- /dev/null +++ b/src/components-examples/material/list/list-avatar/list-avatar-example.ts @@ -0,0 +1,12 @@ +import {Component} from '@angular/core'; +import {MatListModule} from '@angular/material/list'; + +/** + * @title Selection list with avatars + */ +@Component({ + selector: 'list-avatar-example', + templateUrl: 'list-avatar-example.html', + imports: [MatListModule], +}) +export class ListAvatarExample {} diff --git a/src/components-examples/material/list/list-navigation/list-navigation-example.html b/src/components-examples/material/list/list-navigation/list-navigation-example.html new file mode 100644 index 000000000000..f371e070827d --- /dev/null +++ b/src/components-examples/material/list/list-navigation/list-navigation-example.html @@ -0,0 +1,27 @@ + + @for (link of fragments; track link) { + {{link | titlecase}} + } + +

                  List with icons

                  + @for (link of fragments; track link) { + + folder + {{ link | titlecase}} +
                  + {{link}} +
                  +
                  + } +
                  diff --git a/src/components-examples/material/list/list-navigation/list-navigation-example.ts b/src/components-examples/material/list/list-navigation/list-navigation-example.ts new file mode 100644 index 000000000000..3a37f23f192d --- /dev/null +++ b/src/components-examples/material/list/list-navigation/list-navigation-example.ts @@ -0,0 +1,17 @@ +import {TitleCasePipe} from '@angular/common'; +import {Component} from '@angular/core'; +import {MatIconModule} from '@angular/material/icon'; +import {MatListModule} from '@angular/material/list'; + +/** + * @title Navigation list + */ +@Component({ + selector: 'list-navigation-example', + templateUrl: 'list-navigation-example.html', + imports: [MatListModule, MatIconModule, TitleCasePipe], +}) +export class ListNavigationExample { + fragments = ['inbox', 'outbox', 'drafts']; + activeLink: string | null = null; +} diff --git a/src/dev-app/BUILD.bazel b/src/dev-app/BUILD.bazel index 041ce095f9c9..b18b11e22ea1 100644 --- a/src/dev-app/BUILD.bazel +++ b/src/dev-app/BUILD.bazel @@ -26,11 +26,13 @@ ng_project( "//src/cdk/bidi", "//src/cdk/overlay", "//src/dev-app/aria-accordion", + "//src/dev-app/aria-autocomplete", "//src/dev-app/aria-combobox", "//src/dev-app/aria-grid", "//src/dev-app/aria-listbox", "//src/dev-app/aria-menu", - "//src/dev-app/aria-radio-group", + "//src/dev-app/aria-menubar", + "//src/dev-app/aria-select", "//src/dev-app/aria-tabs", "//src/dev-app/aria-toolbar", "//src/dev-app/aria-tree", @@ -144,14 +146,6 @@ sass_binary( ], ) -# Variables that are going to be inlined into the dev app index.html. -filegroup( - name = "variables", - # Note that we need the * in the pattern, because there's a lint rule which - # doesn't allow single files in a `glob`. We have to use a glob, because the file is optional. - srcs = glob(["*variables.json"]), -) - # File group for all static files which are needed to serve the dev-app. These files are # used in the devserver as runfiles and will be copied into the static web package that can # be deployed on static hosting services (like firebase). @@ -163,7 +157,6 @@ filegroup( "index.html", ":theme", ":theme_m3", - ":variables", "//:node_modules/moment", "//:node_modules/zone.js", "//src/dev-app/icon:icon_demo_assets", diff --git a/src/dev-app/aria-autocomplete/BUILD.bazel b/src/dev-app/aria-autocomplete/BUILD.bazel new file mode 100644 index 000000000000..571ec2743531 --- /dev/null +++ b/src/dev-app/aria-autocomplete/BUILD.bazel @@ -0,0 +1,17 @@ +load("//tools:defaults.bzl", "ng_project") + +package(default_visibility = ["//visibility:public"]) + +ng_project( + name = "aria-autocomplete", + srcs = glob(["**/*.ts"]), + assets = [ + "autocomplete-demo.css", + "autocomplete-demo.html", + ], + deps = [ + "//:node_modules/@angular/core", + "//:node_modules/@angular/forms", + "//src/components-examples/aria/autocomplete", + ], +) diff --git a/src/dev-app/aria-autocomplete/autocomplete-demo.css b/src/dev-app/aria-autocomplete/autocomplete-demo.css new file mode 100644 index 000000000000..e91c57a78bd9 --- /dev/null +++ b/src/dev-app/aria-autocomplete/autocomplete-demo.css @@ -0,0 +1,9 @@ +:host { + display: flex; + flex-wrap: wrap; + gap: 10rem; +} + +.example-container { + width: 250px; +} diff --git a/src/dev-app/aria-autocomplete/autocomplete-demo.html b/src/dev-app/aria-autocomplete/autocomplete-demo.html new file mode 100644 index 000000000000..a010a9c87585 --- /dev/null +++ b/src/dev-app/aria-autocomplete/autocomplete-demo.html @@ -0,0 +1,19 @@ +
                  +

                  Auto select

                  + +
                  + +
                  +

                  Manual selection

                  + +
                  + +
                  +

                  Highlighted auto selection

                  + +
                  + +
                  +

                  Disabled autocomplete

                  + +
                  diff --git a/src/dev-app/aria-autocomplete/autocomplete-demo.ts b/src/dev-app/aria-autocomplete/autocomplete-demo.ts new file mode 100644 index 000000000000..38179f50296e --- /dev/null +++ b/src/dev-app/aria-autocomplete/autocomplete-demo.ts @@ -0,0 +1,21 @@ +import {ChangeDetectionStrategy, Component} from '@angular/core'; +import { + AutocompleteAutoSelectExample, + AutocompleteManualExample, + AutocompleteHighlightExample, + AutocompleteDisabledExample, +} from '@angular/components-examples/aria/autocomplete'; + +@Component({ + selector: 'autocomplete-demo', + templateUrl: 'autocomplete-demo.html', + styleUrl: 'autocomplete-demo.css', + imports: [ + AutocompleteAutoSelectExample, + AutocompleteManualExample, + AutocompleteHighlightExample, + AutocompleteDisabledExample, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AutocompleteDemo {} diff --git a/src/dev-app/aria-combobox/combobox-demo.css b/src/dev-app/aria-combobox/combobox-demo.css index 8233ba47f19b..607c068d07ef 100644 --- a/src/dev-app/aria-combobox/combobox-demo.css +++ b/src/dev-app/aria-combobox/combobox-demo.css @@ -1,24 +1,22 @@ -.example-combobox-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); - gap: 20px; - justify-items: center; +.example-combobox-row { + display: flex; + gap: 20px; } .example-combobox-container { - display: flex; - flex-direction: column; - justify-content: flex-start; - - /* stylelint-disable material/no-prefixes */ - width: fit-content; -} - -.example-configurable-combobox-container { - padding-top: 40px; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + min-width: 350px; + padding: 20px 0; } h2 { - font-size: 1.1rem; + font-size: 1.5rem; + padding-top: 20px; } +h3 { + font-size: 1rem; +} diff --git a/src/dev-app/aria-combobox/combobox-demo.html b/src/dev-app/aria-combobox/combobox-demo.html index 2a5bd48182a0..01048429e8d6 100644 --- a/src/dev-app/aria-combobox/combobox-demo.html +++ b/src/dev-app/aria-combobox/combobox-demo.html @@ -1,33 +1,72 @@
                  -
                  +

                  Listbox autocomplete examples

                  + +
                  -

                  Combobox with manual filtering

                  +

                  Combobox with manual filtering

                  -

                  Combobox with auto-select filtering

                  +

                  Combobox with auto-select filtering

                  -

                  Combobox with highlight filtering

                  +

                  Combobox with highlight filtering

                  -

                  Combobox with tree popup and manual filtering

                  +

                  Disabled combobox

                  + +
                  +
                  + +

                  Tree autocomplete examples

                  + +
                  +
                  +

                  Combobox with tree popup and manual filtering

                  -

                  Combobox with tree popup and auto-select filtering

                  +

                  Combobox with tree popup and auto-select filtering

                  -

                  Combobox with tree popup and highlight filtering

                  +

                  Combobox with tree popup and highlight filtering

                  + +

                  Select examples

                  + +
                  +
                  +

                  Readonly Combobox

                  + +
                  + +
                  +

                  Readonly Multiselect Combobox

                  + +
                  + +
                  +

                  Disabled Readonly Combobox

                  + +
                  +
                  + +

                  Combobox with dialog popup

                  + +
                  +
                  +

                  Combobox with dialog popup

                  + +
                  +
                  diff --git a/src/dev-app/aria-combobox/combobox-demo.ts b/src/dev-app/aria-combobox/combobox-demo.ts index a013d1dc1f5f..efb033b6a777 100644 --- a/src/dev-app/aria-combobox/combobox-demo.ts +++ b/src/dev-app/aria-combobox/combobox-demo.ts @@ -7,9 +7,14 @@ */ import { + ComboboxDialogExample, ComboboxAutoSelectExample, ComboboxHighlightExample, ComboboxManualExample, + ComboboxDisabledExample, + ComboboxReadonlyExample, + ComboboxReadonlyMultiselectExample, + ComboboxReadonlyDisabledExample, ComboboxTreeAutoSelectExample, ComboboxTreeHighlightExample, ComboboxTreeManualExample, @@ -20,9 +25,14 @@ import {ChangeDetectionStrategy, Component} from '@angular/core'; templateUrl: 'combobox-demo.html', styleUrl: 'combobox-demo.css', imports: [ + ComboboxDialogExample, ComboboxManualExample, ComboboxAutoSelectExample, ComboboxHighlightExample, + ComboboxDisabledExample, + ComboboxReadonlyExample, + ComboboxReadonlyMultiselectExample, + ComboboxReadonlyDisabledExample, ComboboxTreeManualExample, ComboboxTreeAutoSelectExample, ComboboxTreeHighlightExample, diff --git a/src/dev-app/aria-grid/grid-demo.css b/src/dev-app/aria-grid/grid-demo.css index b1c7a60608d0..1e8e47023ec1 100644 --- a/src/dev-app/aria-grid/grid-demo.css +++ b/src/dev-app/aria-grid/grid-demo.css @@ -1,17 +1,7 @@ -.demo-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr)); - gap: 20px; -} - .demo-grid-container { display: flex; flex-direction: column; - justify-content: flex-start; -} - -.demo-configurable-grid-container { - padding-top: 40px; + gap: 40px; } h2 { diff --git a/src/dev-app/aria-grid/grid-demo.html b/src/dev-app/aria-grid/grid-demo.html index f528a4a50e45..2055188cac14 100644 --- a/src/dev-app/aria-grid/grid-demo.html +++ b/src/dev-app/aria-grid/grid-demo.html @@ -1,11 +1,20 @@ -
                  -
                  +
                  +

                  Grid Pill List

                  -
                  -
                  -
                  + +
                  +

                  Grid Calendar

                  + +
                  + +
                  +

                  Grid Table

                  + +
                  + +

                  Configurable

                  diff --git a/src/dev-app/aria-grid/grid-demo.ts b/src/dev-app/aria-grid/grid-demo.ts index 1f415d8153aa..6bebfb9a10b4 100644 --- a/src/dev-app/aria-grid/grid-demo.ts +++ b/src/dev-app/aria-grid/grid-demo.ts @@ -7,11 +7,16 @@ */ import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core'; -import {GridConfigurableExample, GridPillListExample} from '@angular/components-examples/aria/grid'; +import { + GridConfigurableExample, + GridPillListExample, + GridCalendarExample, + GridTableExample, +} from '@angular/components-examples/aria/grid'; @Component({ templateUrl: 'grid-demo.html', - imports: [GridConfigurableExample, GridPillListExample], + imports: [GridConfigurableExample, GridPillListExample, GridCalendarExample, GridTableExample], styleUrl: 'grid-demo.css', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/src/dev-app/aria-menu/menu-demo.html b/src/dev-app/aria-menu/menu-demo.html index eb81a19febec..e17b06194775 100644 --- a/src/dev-app/aria-menu/menu-demo.html +++ b/src/dev-app/aria-menu/menu-demo.html @@ -1,13 +1,13 @@
                  -

                  Menu Bar Example

                  - +

                  Menu Trigger Example

                  +
                  -

                  Menu Trigger Example

                  - +

                  Disabled Menu Trigger Example

                  +
                  @@ -15,6 +15,11 @@

                  Standalone Menu Example

                  +
                  +

                  Disabled Standalone Menu Example

                  + +
                  +

                  Context Menu Example

                  diff --git a/src/dev-app/aria-menu/menu-demo.ts b/src/dev-app/aria-menu/menu-demo.ts index 7303be1bb923..1f2ef3b4ae29 100644 --- a/src/dev-app/aria-menu/menu-demo.ts +++ b/src/dev-app/aria-menu/menu-demo.ts @@ -8,10 +8,11 @@ import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core'; import { - MenuBarExample, MenuContextExample, MenuTriggerExample, MenuStandaloneExample, + MenuStandaloneDisabledExample, + MenuTriggerDisabledExample, } from '@angular/components-examples/aria/menu'; @Component({ @@ -19,6 +20,12 @@ import { styleUrl: 'menu-demo.css', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [MenuBarExample, MenuContextExample, MenuTriggerExample, MenuStandaloneExample], + imports: [ + MenuContextExample, + MenuTriggerExample, + MenuTriggerDisabledExample, + MenuStandaloneExample, + MenuStandaloneDisabledExample, + ], }) export class MenuDemo {} diff --git a/src/dev-app/aria-menubar/BUILD.bazel b/src/dev-app/aria-menubar/BUILD.bazel new file mode 100644 index 000000000000..ce493844fd11 --- /dev/null +++ b/src/dev-app/aria-menubar/BUILD.bazel @@ -0,0 +1,16 @@ +load("//tools:defaults.bzl", "ng_project") + +package(default_visibility = ["//visibility:public"]) + +ng_project( + name = "aria-menubar", + srcs = ["menubar-demo.ts"], + assets = [ + "menubar-demo.html", + "menubar-demo.css", + ], + deps = [ + "//:node_modules/@angular/core", + "//src/components-examples/aria/menubar", + ], +) diff --git a/src/dev-app/aria-radio-group/radio-group-demo.css b/src/dev-app/aria-menubar/menubar-demo.css similarity index 65% rename from src/dev-app/aria-radio-group/radio-group-demo.css rename to src/dev-app/aria-menubar/menubar-demo.css index 65db334e5c3f..218db84dfcf1 100644 --- a/src/dev-app/aria-radio-group/radio-group-demo.css +++ b/src/dev-app/aria-menubar/menubar-demo.css @@ -1,20 +1,16 @@ -.example-radio-grid { +.example-menu-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(500px, 1fr)); gap: 20px; } -.example-radio-container { +.example-menu-container { width: 500px; display: flex; flex-direction: column; justify-content: flex-start; } -.example-configurable-radio-container { - padding-top: 40px; -} - h2 { height: 36px; } diff --git a/src/dev-app/aria-menubar/menubar-demo.html b/src/dev-app/aria-menubar/menubar-demo.html new file mode 100644 index 000000000000..c916452fb272 --- /dev/null +++ b/src/dev-app/aria-menubar/menubar-demo.html @@ -0,0 +1,16 @@ +
                  +
                  +

                  Menu Bar Example

                  + +
                  + +
                  +

                  Disabled Menu Bar Example

                  + +
                  + +
                  +

                  Menu Bar RTL Example

                  + +
                  +
                  diff --git a/src/dev-app/aria-menubar/menubar-demo.ts b/src/dev-app/aria-menubar/menubar-demo.ts new file mode 100644 index 000000000000..aec11c487eaf --- /dev/null +++ b/src/dev-app/aria-menubar/menubar-demo.ts @@ -0,0 +1,23 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core'; +import { + MenuBarExample, + MenuBarRTLExample, + MenuBarDisabledExample, +} from '@angular/components-examples/aria/menubar'; + +@Component({ + templateUrl: 'menubar-demo.html', + styleUrl: 'menubar-demo.css', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [MenuBarExample, MenuBarRTLExample, MenuBarDisabledExample], +}) +export class MenubarDemo {} diff --git a/src/dev-app/aria-radio-group/radio-group-demo.html b/src/dev-app/aria-radio-group/radio-group-demo.html deleted file mode 100644 index 43adee741b9d..000000000000 --- a/src/dev-app/aria-radio-group/radio-group-demo.html +++ /dev/null @@ -1,48 +0,0 @@ -
                  -
                  -
                  -

                  Standard

                  - -
                  - -
                  -

                  Horizontal Orientation

                  - -
                  - -
                  -

                  RTL & Horizontal Orientation

                  - -
                  - -
                  -

                  Active Descendant

                  - -
                  - -
                  -

                  Disabled Radio Buttons are Focusable

                  - -
                  - -
                  -

                  Disabled Radio Buttons are Skipped

                  - -
                  - -
                  -

                  Readonly

                  - -
                  - -
                  -

                  Disabled

                  - -
                  -
                  - -
                  -

                  Configurable

                  - -
                  -
                  diff --git a/src/dev-app/aria-radio-group/radio-group-demo.ts b/src/dev-app/aria-radio-group/radio-group-demo.ts deleted file mode 100644 index 27dd3f929ed2..000000000000 --- a/src/dev-app/aria-radio-group/radio-group-demo.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.dev/license - */ - -import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core'; -import { - RadioGroupConfigurableExample, - RadioGroupStandardExample, - RadioGroupHorizontalExample, - RadioGroupRtlHorizontalExample, - RadioGroupActiveDescendantExample, - RadioGroupDisabledFocusableExample, - RadioGroupDisabledSkippedExample, - RadioGroupReadonlyExample, - RadioGroupDisabledExample, -} from '@angular/components-examples/aria/radio-group'; - -@Component({ - templateUrl: 'radio-group-demo.html', - imports: [ - RadioGroupStandardExample, - RadioGroupHorizontalExample, - RadioGroupRtlHorizontalExample, - RadioGroupActiveDescendantExample, - RadioGroupDisabledFocusableExample, - RadioGroupDisabledSkippedExample, - RadioGroupReadonlyExample, - RadioGroupDisabledExample, - RadioGroupConfigurableExample, - ], - styleUrl: './radio-group-demo.css', - encapsulation: ViewEncapsulation.None, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class RadioGroupDemo {} diff --git a/src/dev-app/aria-radio-group/BUILD.bazel b/src/dev-app/aria-select/BUILD.bazel similarity index 59% rename from src/dev-app/aria-radio-group/BUILD.bazel rename to src/dev-app/aria-select/BUILD.bazel index f9824cfb7fab..8e65d8720b89 100644 --- a/src/dev-app/aria-radio-group/BUILD.bazel +++ b/src/dev-app/aria-select/BUILD.bazel @@ -3,14 +3,14 @@ load("//tools:defaults.bzl", "ng_project") package(default_visibility = ["//visibility:public"]) ng_project( - name = "aria-radio-group", + name = "aria-select", srcs = glob(["**/*.ts"]), assets = [ - "radio-group-demo.html", - ":radio-group-demo.css", + "select-demo.html", + ":select-demo.css", ], deps = [ "//:node_modules/@angular/core", - "//src/components-examples/aria/radio-group", + "//src/components-examples/aria/select", ], ) diff --git a/src/dev-app/aria-select/select-demo.css b/src/dev-app/aria-select/select-demo.css new file mode 100644 index 000000000000..e91c57a78bd9 --- /dev/null +++ b/src/dev-app/aria-select/select-demo.css @@ -0,0 +1,9 @@ +:host { + display: flex; + flex-wrap: wrap; + gap: 10rem; +} + +.example-container { + width: 250px; +} diff --git a/src/dev-app/aria-select/select-demo.html b/src/dev-app/aria-select/select-demo.html new file mode 100644 index 000000000000..b3c95c298274 --- /dev/null +++ b/src/dev-app/aria-select/select-demo.html @@ -0,0 +1,14 @@ +
                  +

                  Select Example

                  + +
                  + +
                  +

                  Multiselect Example

                  + +
                  + +
                  +

                  Disabled Example

                  + +
                  diff --git a/src/dev-app/aria-select/select-demo.ts b/src/dev-app/aria-select/select-demo.ts new file mode 100644 index 000000000000..ef1e85d8c332 --- /dev/null +++ b/src/dev-app/aria-select/select-demo.ts @@ -0,0 +1,22 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {ChangeDetectionStrategy, Component} from '@angular/core'; +import { + SelectDisabledExample, + SelectMultiExample, + SelectExample, +} from '@angular/components-examples/aria/select'; + +@Component({ + templateUrl: 'select-demo.html', + styleUrl: 'select-demo.css', + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [SelectDisabledExample, SelectMultiExample, SelectExample], +}) +export class SelectDemo {} diff --git a/src/dev-app/aria-toolbar/toolbar-demo.html b/src/dev-app/aria-toolbar/toolbar-demo.html index 09b493315371..3a309bf5e0ad 100644 --- a/src/dev-app/aria-toolbar/toolbar-demo.html +++ b/src/dev-app/aria-toolbar/toolbar-demo.html @@ -9,8 +9,12 @@

                  Toolbar Basic Vertical

                  -

                  Toolbar Skip Disabled

                  - +

                  Toolbar with Hard Disabled Items

                  + +
                  +
                  +

                  Toolbar RTL

                  +

                  Configurable CDK Toolbar

                  diff --git a/src/dev-app/aria-toolbar/toolbar-demo.ts b/src/dev-app/aria-toolbar/toolbar-demo.ts index 535db0baa8c7..7f133355b95f 100644 --- a/src/dev-app/aria-toolbar/toolbar-demo.ts +++ b/src/dev-app/aria-toolbar/toolbar-demo.ts @@ -11,7 +11,8 @@ import { ToolbarBasicHorizontalExample, ToolbarBasicVerticalExample, ToolbarConfigurableExample, - ToolbarSkipDisabledExample, + ToolbarRtlExample, + ToolbarHardDisabledExample, } from '@angular/components-examples/aria/toolbar'; @Component({ @@ -20,7 +21,8 @@ import { ToolbarBasicHorizontalExample, ToolbarBasicVerticalExample, ToolbarConfigurableExample, - ToolbarSkipDisabledExample, + ToolbarRtlExample, + ToolbarHardDisabledExample, ], styleUrl: './toolbar-demo.css', encapsulation: ViewEncapsulation.None, diff --git a/src/dev-app/common-classes.css b/src/dev-app/common-classes.css index 768f4e57708a..7da4d3c95c5b 100644 --- a/src/dev-app/common-classes.css +++ b/src/dev-app/common-classes.css @@ -68,7 +68,6 @@ [aria-disabled='true'] .example-selectable:focus-within, [aria-activedescendant] .example-selectable:focus-within { outline-color: transparent; - border-radius: 0; } [aria-disabled='true'] .example-selectable[aria-selected='true'], diff --git a/src/dev-app/dev-app/dev-app-layout.ts b/src/dev-app/dev-app/dev-app-layout.ts index a459ac767f14..8e552a3d0727 100644 --- a/src/dev-app/dev-app/dev-app-layout.ts +++ b/src/dev-app/dev-app/dev-app-layout.ts @@ -64,10 +64,12 @@ export class DevAppLayout { {name: 'CDK Dialog', route: '/cdk-dialog'}, {name: 'Aria Accordion', route: '/aria-accordion'}, {name: 'Aria Combobox', route: '/aria-combobox'}, + {name: 'Aria Autocomplete', route: '/aria-autocomplete'}, {name: 'Aria Grid', route: '/aria-grid'}, {name: 'Aria Listbox', route: '/aria-listbox'}, {name: 'Aria Menu', route: '/aria-menu'}, - {name: 'Aria Radio Group', route: '/aria-radio-group'}, + {name: 'Aria Menubar', route: '/aria-menubar'}, + {name: 'Aria Select', route: '/aria-select'}, {name: 'Aria Tabs', route: '/aria-tabs'}, {name: 'Aria Toolbar', route: '/aria-toolbar'}, {name: 'Aria Tree', route: '/aria-tree'}, diff --git a/src/dev-app/routes.ts b/src/dev-app/routes.ts index f24d0e51258b..2fab9c4af821 100644 --- a/src/dev-app/routes.ts +++ b/src/dev-app/routes.ts @@ -44,6 +44,10 @@ export const DEV_APP_ROUTES: Routes = [ path: 'aria-combobox', loadComponent: () => import('./aria-combobox/combobox-demo').then(m => m.ComboboxDemo), }, + { + path: 'aria-select', + loadComponent: () => import('./aria-select/select-demo').then(m => m.SelectDemo), + }, { path: 'aria-grid', loadComponent: () => import('./aria-grid/grid-demo').then(m => m.GridDemo), @@ -57,8 +61,8 @@ export const DEV_APP_ROUTES: Routes = [ loadComponent: () => import('./aria-menu/menu-demo').then(m => m.MenuDemo), }, { - path: 'aria-radio-group', - loadComponent: () => import('./aria-radio-group/radio-group-demo').then(m => m.RadioGroupDemo), + path: 'aria-menubar', + loadComponent: () => import('./aria-menubar/menubar-demo').then(m => m.MenubarDemo), }, { path: 'aria-tabs', @@ -72,6 +76,11 @@ export const DEV_APP_ROUTES: Routes = [ path: 'aria-tree', loadComponent: () => import('./aria-tree/tree-demo').then(m => m.TreeDemo), }, + { + path: 'aria-autocomplete', + loadComponent: () => + import('./aria-autocomplete/autocomplete-demo').then(m => m.AutocompleteDemo), + }, { path: 'aria-toolbar', loadComponent: () => import('./aria-toolbar/toolbar-demo').then(m => m.ToolbarDemo), diff --git a/src/dev-app/slide-toggle/slide-toggle-demo.html b/src/dev-app/slide-toggle/slide-toggle-demo.html index 59b711ac3e9f..fff54d790328 100644 --- a/src/dev-app/slide-toggle/slide-toggle-demo.html +++ b/src/dev-app/slide-toggle/slide-toggle-demo.html @@ -1,16 +1,30 @@
                  - Default Slide Toggle + Default Slide Toggle Disabled Slide Toggle Disable Bound - Disabled Interactive Toggle + Disabled Interactive Toggle No icon

                  With label before the slide toggle.

                  - Default Slide Toggle - Disabled Slide Toggle + Default Slide Toggle + Disabled Slide Toggle Disable Bound - No icon + No icon + +

                  With no label.

                  + +

                  Example where the slide toggle is required inside of a form.

                  diff --git a/src/dev-app/system/system-demo.ts b/src/dev-app/system/system-demo.ts index ba611cda5fbd..c3e0490359dd 100644 --- a/src/dev-app/system/system-demo.ts +++ b/src/dev-app/system/system-demo.ts @@ -1,4 +1,3 @@ -import {CommonModule} from '@angular/common'; import {ChangeDetectionStrategy, Component} from '@angular/core'; import {MatCardModule} from '@angular/material/card'; @@ -30,7 +29,7 @@ interface ColorGroup { selector: 'system-demo', templateUrl: 'system-demo.html', styleUrls: ['system-demo.css'], - imports: [CommonModule, MatCardModule], + imports: [MatCardModule], changeDetection: ChangeDetectionStrategy.OnPush, }) export class SystemDemo { diff --git a/src/dev-app/theme-m3.scss b/src/dev-app/theme-m3.scss index c079d88b24d0..64a5248ad7aa 100644 --- a/src/dev-app/theme-m3.scss +++ b/src/dev-app/theme-m3.scss @@ -59,10 +59,7 @@ html { @include mat.typography-hierarchy($light-theme); .demo-strong-focus { - // Note: we can theme the indicators directly through `strong-focus-indicators` as well. - // Use the theme so we have some coverage over the entire API surface. @include mat.strong-focus-indicators(); - @include mat.strong-focus-indicators-theme($light-theme); } // Include the alternative theme styles inside of a block with a CSS class. You can make this @@ -79,11 +76,6 @@ body.demo-unicorn-dark-theme { // @include matx.column-resize-color($dark-theme); // @include matx.popover-edit-color($dark-theme); } - - // Include the dark theme colors for focus indicators. - &.demo-strong-focus { - @include mat.strong-focus-indicators-color($dark-theme); - } } // Create classes for all density scales which are supported by all MDC-based components. diff --git a/src/google-maps/schematics/BUILD.bazel b/src/google-maps/schematics/BUILD.bazel index cbf773d41063..9ae5afbaa6e4 100644 --- a/src/google-maps/schematics/BUILD.bazel +++ b/src/google-maps/schematics/BUILD.bazel @@ -1,6 +1,6 @@ load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") -load("//tools:defaults.bzl", "npm_package", "ts_project") load("@aspect_rules_ts//ts:defs.bzl", rules_js_tsconfig = "ts_config") +load("//tools:defaults.bzl", "npm_package", "ts_project") package(default_visibility = ["//visibility:public"]) diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index 486c7a60728a..57406381c01c 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -767,8 +767,15 @@ export class MatAutocompleteTrigger } private _attachOverlay(valueOnAttach: string): void { - if (!this.autocomplete && (typeof ngDevMode === 'undefined' || ngDevMode)) { - throw getMatAutocompleteMissingPanelError(); + if (!this.autocomplete) { + if (typeof ngDevMode === 'undefined' || ngDevMode) { + throw getMatAutocompleteMissingPanelError(); + } else { + // This shouldn't happen only in production mode, but some internal teams have + // observed it in their production logging. Return since the rest of the function + // assumes that the autocomplete is defined. + return; + } } let overlayRef = this._overlayRef; @@ -904,7 +911,8 @@ export class MatAutocompleteTrigger this._getConnectedElement(), ) .withFlexibleDimensions(false) - .withPush(false); + .withPush(false) + .withPopoverLocation('inline'); this._setStrategyPositions(strategy); this._positionStrategy = strategy; diff --git a/src/material/autocomplete/autocomplete.scss b/src/material/autocomplete/autocomplete.scss index b3d3be79f849..d2ee490bfa08 100644 --- a/src/material/autocomplete/autocomplete.scss +++ b/src/material/autocomplete/autocomplete.scss @@ -43,11 +43,12 @@ div.mat-mdc-autocomplete-panel { &.mat-mdc-autocomplete-visible { visibility: visible; } +} - &.mat-mdc-autocomplete-hidden { - visibility: hidden; - pointer-events: none; - } +div.mat-mdc-autocomplete-panel.mat-mdc-autocomplete-hidden, +.cdk-overlay-pane:has(> .mat-mdc-autocomplete-hidden) { + visibility: hidden; + pointer-events: none; } @keyframes _mat-autocomplete-enter { diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts index c335f8e85b27..bcec42255607 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -62,6 +62,7 @@ import { } from './index'; describe('MatAutocomplete', () => { + const supportsPopover = 'showPopover' in document.body; let overlayContainerElement: HTMLElement; // Creates a test component fixture. @@ -77,6 +78,19 @@ describe('MatAutocomplete', () => { return TestBed.createComponent(component); } + function getOverlayHost(fixture: ComponentFixture): HTMLElement | null { + return supportsPopover + ? fixture.nativeElement.querySelector('.cdk-overlay-popover') + : overlayContainerElement.querySelector('.cdk-overlay-connected-position-bounding-box'); + } + + function getBackdrop(fixture: ComponentFixture): HTMLElement | null { + const selector = '.cdk-overlay-backdrop'; + return supportsPopover + ? getOverlayHost(fixture)?.querySelector(selector) || null + : overlayContainerElement.querySelector(selector); + } + describe('panel toggling', () => { let fixture: ComponentFixture; let input: HTMLInputElement; @@ -98,10 +112,10 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected panel state to read open when input is focused.`) .toBe(true); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.textContent) .withContext(`Expected panel to display when input is focused.`) .toContain('Alabama'); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.textContent) .withContext(`Expected panel to display when input is focused.`) .toContain('California'); }); @@ -147,10 +161,10 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected panel state to read open when opened programmatically.`) .toBe(true); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.textContent) .withContext(`Expected panel to display when opened programmatically.`) .toContain('Alabama'); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.textContent) .withContext(`Expected panel to display when opened programmatically.`) .toContain('California'); }); @@ -165,9 +179,9 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected clicking outside the panel to set its state to closed.`) .toBe(false); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)) .withContext(`Expected clicking outside the panel to close the panel.`) - .toEqual(''); + .toBeFalsy(); })); it('should close the panel when the user clicks away via auxiliary button', waitForAsync(async () => { @@ -180,9 +194,9 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected clicking outside the panel to set its state to closed.`) .toBe(false); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)) .withContext(`Expected clicking outside the panel to close the panel.`) - .toEqual(''); + .toBeFalsy(); })); it('should close the panel when the user taps away on a touch device', fakeAsync(() => { @@ -194,9 +208,9 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected tapping outside the panel to set its state to closed.`) .toBe(false); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)) .withContext(`Expected tapping outside the panel to close the panel.`) - .toEqual(''); + .toBeFalsy(); })); it('should close the panel when an option is clicked', waitForAsync(async () => { @@ -204,7 +218,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)!.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); await new Promise(r => setTimeout(r)); @@ -212,9 +226,9 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected clicking an option to set the panel state to closed.`) .toBe(false); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)) .withContext(`Expected clicking an option to close the panel.`) - .toEqual(''); + .toBeFalsy(); })); it('should close the panel when a newly created option is clicked', waitForAsync(async () => { @@ -227,7 +241,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - let options = overlayContainerElement.querySelectorAll( + let options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[0].click(); @@ -240,7 +254,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + options = getOverlayHost(fixture)!.querySelectorAll('mat-option') as NodeListOf; options[1].click(); fixture.detectChanges(); await new Promise(r => setTimeout(r)); @@ -248,9 +262,9 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected clicking a new option to set the panel state to closed.`) .toBe(false); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)) .withContext(`Expected clicking a new option to close the panel.`) - .toEqual(''); + .toBeFalsy(); })); it('should close the panel programmatically', fakeAsync(() => { @@ -264,9 +278,9 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected closing programmatically to set the panel state to closed.`) .toBe(false); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)) .withContext(`Expected closing programmatically to close the panel.`) - .toEqual(''); + .toBeFalsy(); })); it('should not throw when attempting to close the panel of a destroyed autocomplete', () => { @@ -283,7 +297,7 @@ describe('MatAutocomplete', () => { dispatchFakeEvent(input, 'focusin'); fixture.detectChanges(); - const panel = overlayContainerElement.querySelector( + const panel = getOverlayHost(fixture)!.querySelector( '.mat-mdc-autocomplete-panel', ) as HTMLElement; @@ -311,7 +325,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); fixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[1].click(); @@ -349,7 +363,7 @@ describe('MatAutocomplete', () => { flush(); fixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[1].click(); @@ -373,7 +387,7 @@ describe('MatAutocomplete', () => { flush(); fixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[1].click(); @@ -390,7 +404,7 @@ describe('MatAutocomplete', () => { tick(); fixture.detectChanges(); - expect(overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!.classList) + expect(getOverlayHost(fixture)!.querySelector('.mat-mdc-autocomplete-panel')!.classList) .withContext('Expected panel to be visible.') .toContain('mat-mdc-autocomplete-visible'); @@ -399,7 +413,7 @@ describe('MatAutocomplete', () => { tick(); fixture.detectChanges(); - expect(overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!.classList) + expect(getOverlayHost(fixture)!.querySelector('.mat-mdc-autocomplete-panel')!.classList) .withContext('Expected panel to be hidden.') .toContain('mat-mdc-autocomplete-hidden'); @@ -415,7 +429,7 @@ describe('MatAutocomplete', () => { tick(); fixture.detectChanges(); - expect(overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!.classList) + expect(getOverlayHost(fixture)!.querySelector('.mat-mdc-autocomplete-panel')!.classList) .withContext('Expected panel to be visible.') .toContain('mat-mdc-autocomplete-visible'); })); @@ -639,10 +653,7 @@ describe('MatAutocomplete', () => { rtlFixture.componentInstance.trigger.openPanel(); rtlFixture.detectChanges(); - const boundingBox = overlayContainerElement.querySelector( - '.cdk-overlay-connected-position-bounding-box', - )!; - expect(boundingBox.getAttribute('dir')).toEqual('rtl'); + expect(getOverlayHost(rtlFixture)?.getAttribute('dir')).toEqual('rtl'); }); it('should update the panel direction if it changes for the trigger', () => { @@ -653,10 +664,7 @@ describe('MatAutocomplete', () => { rtlFixture.componentInstance.trigger.openPanel(); rtlFixture.detectChanges(); - let boundingBox = overlayContainerElement.querySelector( - '.cdk-overlay-connected-position-bounding-box', - )!; - expect(boundingBox.getAttribute('dir')).toEqual('rtl'); + expect(getOverlayHost(rtlFixture)?.getAttribute('dir')).toEqual('rtl'); rtlFixture.componentInstance.trigger.closePanel(); rtlFixture.detectChanges(); @@ -665,10 +673,7 @@ describe('MatAutocomplete', () => { rtlFixture.componentInstance.trigger.openPanel(); rtlFixture.detectChanges(); - boundingBox = overlayContainerElement.querySelector( - '.cdk-overlay-connected-position-bounding-box', - )!; - expect(boundingBox.getAttribute('dir')).toEqual('ltr'); + expect(getOverlayHost(rtlFixture)?.getAttribute('dir')).toEqual('ltr'); }); it('should be able to set a custom value for the `autocomplete` attribute', () => { @@ -700,7 +705,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); // Select an option and reopen the panel. - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)!.querySelector('mat-option') as HTMLElement).click(); fixture.detectChanges(); await new Promise(r => setTimeout(r)); fixture.detectChanges(); @@ -731,7 +736,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); // Select an option and reopen the panel. - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)!.querySelector('mat-option') as HTMLElement).click(); fixture.detectChanges(); await new Promise(r => setTimeout(r)); fixture.detectChanges(); @@ -799,7 +804,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[1].click(); @@ -815,7 +820,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[1].click(); @@ -836,7 +841,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[1].click(); @@ -857,7 +862,7 @@ describe('MatAutocomplete', () => { fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[1].click(); @@ -898,7 +903,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; const clickedOption = options[0]; @@ -965,7 +970,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[1].click(); @@ -1037,7 +1042,7 @@ describe('MatAutocomplete', () => { fixture.componentInstance.trigger.openPanel(); fixture.detectChanges(); - const panel = overlayContainerElement.querySelector( + const panel = getOverlayHost(fixture)!.querySelector( '.mat-mdc-autocomplete-panel', )! as HTMLElement; expect(panel.classList).toContain('mat-warn'); @@ -1078,17 +1083,17 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected panel state to stay open when DOWN key is pressed.`) .toBe(true); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.textContent) .withContext(`Expected panel to keep displaying when DOWN key is pressed.`) .toContain('Alabama'); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.textContent) .withContext(`Expected panel to keep displaying when DOWN key is pressed.`) .toContain('California'); }); it('should set the active item to the first option when DOWN key is pressed', () => { const componentInstance = fixture.componentInstance; - const optionEls = overlayContainerElement.querySelectorAll( + const optionEls = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -1117,7 +1122,7 @@ describe('MatAutocomplete', () => { it('should set the active item to the last option when UP key is pressed', () => { const componentInstance = fixture.componentInstance; - const optionEls = overlayContainerElement.querySelectorAll( + const optionEls = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -1160,7 +1165,7 @@ describe('MatAutocomplete', () => { componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT); fixture.detectChanges(); - const optionEls = overlayContainerElement.querySelectorAll( + const optionEls = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -1272,9 +1277,9 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected panel state to read closed after ENTER key.`) .toBe(false); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)) .withContext(`Expected panel to close after ENTER key.`) - .toEqual(''); + .toBeFalsy(); dispatchFakeEvent(input, 'focusin'); clearElement(input); @@ -1285,7 +1290,7 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected panel state to read open when typing in input.`) .toBe(true); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.textContent) .withContext(`Expected panel to display when typing in input.`) .toContain('Alabama'); })); @@ -1511,7 +1516,7 @@ describe('MatAutocomplete', () => { input.focus(); flush(); - expect(overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')) + expect(getOverlayHost(fixture)?.querySelector('.mat-mdc-autocomplete-panel')) .withContext('Expected panel to be rendered.') .toBeTruthy(); @@ -1519,7 +1524,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); tick(); - expect(overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')) + expect(getOverlayHost(fixture)?.querySelector('.mat-mdc-autocomplete-panel')) .withContext('Expected panel to be removed.') .toBeFalsy(); })); @@ -1979,7 +1984,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; // Focus the option manually since the synthetic click may not do it. option.focus(); @@ -2015,7 +2020,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); const inputBottom = inputReference.getBoundingClientRect().bottom; - const panel = overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!; + const panel = getOverlayHost(fixture)!.querySelector('.mat-mdc-autocomplete-panel')!; const panelTop = panel.getBoundingClientRect().top; expect(Math.floor(inputBottom)) @@ -2048,7 +2053,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); const inputBottom = inputReference.getBoundingClientRect().bottom; - const panel = overlayContainerElement.querySelector('.cdk-overlay-pane')!; + const panel = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!; const panelTop = panel.getBoundingClientRect().top; expect(Math.floor(inputBottom)) @@ -2074,7 +2079,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); const inputTop = inputReference.getBoundingClientRect().top; - const panel = overlayContainerElement.querySelector('.cdk-overlay-pane')!; + const panel = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!; const panelBottom = panel.getBoundingClientRect().bottom; expect(Math.floor(inputTop)) @@ -2104,7 +2109,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - let panel = overlayContainerElement.querySelector('.cdk-overlay-pane')!; + let panel = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!; let initialPanelHeight = panel.getBoundingClientRect().height; fixture.componentInstance.trigger.closePanel(); @@ -2120,7 +2125,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - panel = overlayContainerElement.querySelector('.cdk-overlay-pane')!; + panel = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!; expect(panel.getBoundingClientRect().height).toBeGreaterThan(initialPanelHeight); })); @@ -2145,7 +2150,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); const inputTop = inputReference.getBoundingClientRect().top; - const panel = overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!; + const panel = getOverlayHost(fixture)!.querySelector('.mat-mdc-autocomplete-panel')!; const panelBottom = panel.getBoundingClientRect().bottom; expect(Math.floor(inputTop)) @@ -2175,7 +2180,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); fixture.detectChanges(); - let panel = overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!; + let panel = getOverlayHost(fixture)!.querySelector('.mat-mdc-autocomplete-panel')!; let inputRect = inputReference.getBoundingClientRect(); let panelRect = panel.getBoundingClientRect(); @@ -2226,7 +2231,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); const inputBottom = inputReference.getBoundingClientRect().bottom; - const panel = overlayContainerElement.querySelector('.cdk-overlay-pane')!; + const panel = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!; const panelTop = panel.getBoundingClientRect().top; expect(Math.floor(inputBottom)) @@ -2253,7 +2258,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); const inputTop = inputReference.getBoundingClientRect().top; - const panel = overlayContainerElement.querySelector('.cdk-overlay-pane')!; + const panel = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!; const panelBottom = panel.getBoundingClientRect().bottom; expect(Math.floor(inputTop)) @@ -2280,7 +2285,7 @@ describe('MatAutocomplete', () => { await openPanel(); let inputRect = inputReference.getBoundingClientRect(); - let panel = overlayContainerElement.querySelector('.cdk-overlay-pane')!; + let panel = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!; let panelRect = panel.getBoundingClientRect(); expect(Math.floor(inputRect.top)) @@ -2297,7 +2302,7 @@ describe('MatAutocomplete', () => { await openPanel(); inputRect = inputReference.getBoundingClientRect(); - panel = overlayContainerElement.querySelector('.cdk-overlay-pane')!; + panel = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!; panelRect = panel.getBoundingClientRect(); expect(Math.floor(inputRect.bottom)) @@ -2320,7 +2325,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - let options = overlayContainerElement.querySelectorAll( + let options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[0].click(); @@ -2337,7 +2342,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + options = getOverlayHost(fixture)!.querySelectorAll('mat-option') as NodeListOf; options[1].click(); fixture.detectChanges(); @@ -2354,7 +2359,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - let options = overlayContainerElement.querySelectorAll( + let options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[0].click(); @@ -2373,7 +2378,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + options = getOverlayHost(fixture)!.querySelectorAll('mat-option') as NodeListOf; options[1].click(); fixture.detectChanges(); @@ -2389,7 +2394,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); fixture.detectChanges(); - expect(overlayContainerElement.querySelectorAll('mat-option')[0].classList) + expect(getOverlayHost(fixture)!.querySelectorAll('mat-option')[0].classList) .withContext('Expected first option to be highlighted.') .toContain('mat-mdc-option-active'); })); @@ -2407,7 +2412,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); fixture.detectChanges(); - expect(overlayContainerElement.querySelectorAll('mat-option')[2].classList) + expect(getOverlayHost(fixture)!.querySelectorAll('mat-option')[2].classList) .withContext('Expected third option to be highlighted.') .toContain('mat-mdc-option-active'); }), @@ -2424,7 +2429,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); fixture.detectChanges(); - const selectedOptions = overlayContainerElement.querySelectorAll( + const selectedOptions = getOverlayHost(fixture)!.querySelectorAll( 'mat-option.mat-mdc-option-active', ); expect(selectedOptions.length).withContext('expected no options to be active').toBe(0); @@ -2469,7 +2474,7 @@ describe('MatAutocomplete', () => { // Note: should not have a detectChanges call here // in order for the test to fail when it's supposed to. - expect(overlayContainerElement.querySelectorAll('mat-option')[0].classList) + expect(getOverlayHost(fixture)!.querySelectorAll('mat-option')[0].classList) .withContext('Expected first option to be highlighted.') .toContain('mat-mdc-option-active'); })); @@ -2487,7 +2492,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); fixture.detectChanges(); - expect(overlayContainerElement.querySelectorAll('mat-option')[0].classList) + expect(getOverlayHost(fixture)!.querySelectorAll('mat-option')[0].classList) .withContext('Expected first option to be highlighted.') .toContain('mat-mdc-option-active'); })); @@ -2509,7 +2514,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)!.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); @@ -2527,7 +2532,7 @@ describe('MatAutocomplete', () => { fixture.componentInstance.trigger.openPanel(); fixture.detectChanges(); await new Promise(r => setTimeout(r)); - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)!.querySelector('mat-option') as HTMLElement).click(); fixture.detectChanges(); await new Promise(r => setTimeout(r)); }; @@ -2580,7 +2585,7 @@ describe('MatAutocomplete', () => { await flushPosition(); const inputBottom = inputReference.getBoundingClientRect().bottom; - const panel = overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!; + const panel = getOverlayHost(fixture)!.querySelector('.mat-mdc-autocomplete-panel')!; const panelTop = panel.getBoundingClientRect().top; expect(Math.floor(inputBottom)) @@ -2604,7 +2609,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); const input = fixture.nativeElement.querySelector('input'); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)!.querySelector('mat-option') as HTMLElement; const optionInstance = fixture.componentInstance.options.first; const spy = jasmine.createSpy('selectionChange spy'); @@ -2644,7 +2649,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; const spy = jasmine.createSpy('optionSelected spy'); @@ -2677,7 +2682,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; const spy = jasmine.createSpy('optionSelected spy'); @@ -2837,7 +2842,7 @@ describe('MatAutocomplete', () => { trigger.openPanel(); fixture.detectChanges(); await new Promise(r => setTimeout(r)); - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)!.querySelector('mat-option') as HTMLElement).click(); await new Promise(r => setTimeout(r)); fixture.detectChanges(); @@ -2928,7 +2933,7 @@ describe('MatAutocomplete', () => { })); it('should emit panel close event when selecting an option', () => { - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)!.querySelector('mat-option') as HTMLElement; expect(closingActionSpy).not.toHaveBeenCalled(); option.click(); @@ -2987,7 +2992,7 @@ describe('MatAutocomplete', () => { fixture.componentInstance.trigger.openPanel(); fixture.detectChanges(); - const panelClassList = overlayContainerElement.querySelector('.cdk-overlay-pane')!.classList; + const panelClassList = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!.classList; expect(panelClassList).toContain('default1'); }); @@ -3003,7 +3008,7 @@ describe('MatAutocomplete', () => { fixture.componentInstance.trigger.openPanel(); fixture.detectChanges(); - const panelClassList = overlayContainerElement.querySelector('.cdk-overlay-pane')!.classList; + const panelClassList = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!.classList; expect(panelClassList).toContain('default1'); expect(panelClassList).toContain('default2'); }); @@ -3018,7 +3023,7 @@ describe('MatAutocomplete', () => { tick(500); - expect(overlayContainerElement.querySelector('.cdk-overlay-backdrop')).toBeFalsy(); + expect(getBackdrop(fixture)).toBeFalsy(); })); it('should be able to add the backdrop using hasBackdrop option', fakeAsync(() => { @@ -3034,7 +3039,7 @@ describe('MatAutocomplete', () => { tick(500); - expect(overlayContainerElement.querySelector('.cdk-overlay-backdrop')).toBeTruthy(); + expect(getBackdrop(fixture)).toBeTruthy(); })); }); @@ -3052,8 +3057,8 @@ describe('MatAutocomplete', () => { tick(500); - const cdkPanelElement = overlayContainerElement.querySelector('.cdk-overlay-backdrop'); - expect(cdkPanelElement?.classList).toContain('my-custom-backdrop-class'); + const backdrop = getBackdrop(fixture); + expect(backdrop?.classList).toContain('my-custom-backdrop-class'); })); }); @@ -3067,7 +3072,7 @@ describe('MatAutocomplete', () => { typeInElement(input, 'd'); fixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; expect(options.length).toBe(1); @@ -3102,10 +3107,10 @@ describe('MatAutocomplete', () => { expect(fixture.componentInstance.trigger.panelOpen) .withContext(`Expected panel state to read open when input is focused.`) .toBe(true); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.textContent) .withContext(`Expected panel to display when input is focused.`) .toContain('One'); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.textContent) .withContext(`Expected panel to display when input is focused.`) .toContain('Two'); }); @@ -3155,7 +3160,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); const autocomplete = fixture.debugElement.nativeElement.querySelector('mat-autocomplete'); - const panel = overlayContainerElement.querySelector('.mat-mdc-autocomplete-panel')!; + const panel = getOverlayHost(fixture)!.querySelector('.mat-mdc-autocomplete-panel')!; expect(autocomplete.classList).not.toContain('class-one'); expect(autocomplete.classList).not.toContain('class-two'); @@ -3172,7 +3177,7 @@ describe('MatAutocomplete', () => { tick(); fixture.detectChanges(); - const classList = overlayContainerElement.querySelector( + const classList = getOverlayHost(fixture)!.querySelector( '.mat-mdc-autocomplete-panel', )!.classList; @@ -3478,7 +3483,7 @@ describe('MatAutocomplete', () => { expect(stateCtrl.value).toBeFalsy(); expect(input.value).toBe('Alabama'); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[2].click(); @@ -3498,7 +3503,9 @@ describe('MatAutocomplete', () => { widthFixture.componentInstance.trigger.openPanel(); widthFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = getOverlayHost(widthFixture)!.querySelector( + '.cdk-overlay-pane', + ) as HTMLElement; // Firefox, Edge return a decimal value for width, so we need to parse and round it to verify expect(Math.ceil(parseFloat(overlayPane.style.width as string))).toBe(300); @@ -3526,7 +3533,9 @@ describe('MatAutocomplete', () => { widthFixture.componentInstance.trigger.openPanel(); widthFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = getOverlayHost(widthFixture)!.querySelector( + '.cdk-overlay-pane', + ) as HTMLElement; const input = widthFixture.debugElement.query(By.css('input'))!.nativeElement; expect(Math.ceil(parseFloat(overlayPane.style.width as string))).toBe(300); @@ -3582,7 +3591,9 @@ describe('MatAutocomplete', () => { widthFixture.componentInstance.trigger.openPanel(); widthFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = getOverlayHost(widthFixture)!.querySelector( + '.cdk-overlay-pane', + ) as HTMLElement; expect(Math.ceil(parseFloat(overlayPane.style.width as string))).toBe(300); @@ -3606,7 +3617,9 @@ describe('MatAutocomplete', () => { widthFixture.componentInstance.trigger.openPanel(); widthFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = getOverlayHost(widthFixture)!.querySelector( + '.cdk-overlay-pane', + ) as HTMLElement; expect(Math.ceil(parseFloat(overlayPane.style.width as string))).toBe(300); }); @@ -3623,7 +3636,9 @@ describe('MatAutocomplete', () => { widthFixture.componentInstance.trigger.openPanel(); widthFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = getOverlayHost(widthFixture)!.querySelector( + '.cdk-overlay-pane', + ) as HTMLElement; expect(overlayPane.style.width).toBe('auto'); }); @@ -3640,7 +3655,9 @@ describe('MatAutocomplete', () => { widthFixture.componentInstance.trigger.openPanel(); widthFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = getOverlayHost(widthFixture)!.querySelector( + '.cdk-overlay-pane', + ) as HTMLElement; expect(Math.ceil(parseFloat(overlayPane.style.width as string))).toBe(400); }); @@ -3656,7 +3673,7 @@ describe('MatAutocomplete', () => { tick(); Promise.resolve().then(() => { - let panel = overlayContainerElement.querySelector( + let panel = getOverlayHost(fixture)!.querySelector( '.mat-mdc-autocomplete-panel', ) as HTMLElement; let visibleClass = 'mat-mdc-autocomplete-visible'; @@ -3675,7 +3692,9 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); fixture.detectChanges(); - let options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + let options = getOverlayHost(fixture)!.querySelectorAll( + 'mat-option', + ) as NodeListOf; let spy = fixture.componentInstance.optionSelected; options[1].click(); @@ -3700,7 +3719,7 @@ describe('MatAutocomplete', () => { await new Promise(r => setTimeout(r)); fixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; spyOn(input, 'focus').and.callFake(() => events.push('focus')); @@ -3727,7 +3746,9 @@ describe('MatAutocomplete', () => { tick(); fixture.detectChanges(); - let options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + let options = getOverlayHost(fixture)!.querySelectorAll( + 'mat-option', + ) as NodeListOf; let spy = fixture.componentInstance.optionSelected; options[3].click(); @@ -3803,7 +3824,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const overlayRect = overlayContainerElement + const overlayRect = getOverlayHost(fixture)! .querySelector('.cdk-overlay-pane')! .getBoundingClientRect(); const originRect = fixture.nativeElement.querySelector('.origin').getBoundingClientRect(); @@ -3832,7 +3853,7 @@ describe('MatAutocomplete', () => { fixture.detectChanges(); await new Promise(r => setTimeout(r)); - const overlayRect = overlayContainerElement + const overlayRect = getOverlayHost(fixture)! .querySelector('.cdk-overlay-pane')! .getBoundingClientRect(); const originRect = fixture.nativeElement.querySelector('.origin').getBoundingClientRect(); diff --git a/src/material/button-toggle/_m3-button-toggle.scss b/src/material/button-toggle/_m3-button-toggle.scss index d7190903d501..667d1ea56d2c 100644 --- a/src/material/button-toggle/_m3-button-toggle.scss +++ b/src/material/button-toggle/_m3-button-toggle.scss @@ -63,7 +63,7 @@ // Tokens that can be configured through Angular Material's density theming API. @function get-density-tokens($scale) { - $scale: theming.clamp-density(scale, -4); + $scale: theming.clamp-density($scale, -4); $index: ($scale * -1) + 1; @return ( diff --git a/src/material/button/_button-base.scss b/src/material/button/_button-base.scss index 644e8b4af773..d4c21b6d58c4 100644 --- a/src/material/button/_button-base.scss +++ b/src/material/button/_button-base.scss @@ -56,7 +56,7 @@ } } - &:focus > .mat-focus-indicator::before { + &:focus-visible > .mat-focus-indicator::before { content: ''; @if ($focus-indicator-inherits-shape) { diff --git a/src/material/button/testing/button-harness.ts b/src/material/button/testing/button-harness.ts index 49edebcb25ce..7f3ba9eacff9 100644 --- a/src/material/button/testing/button-harness.ts +++ b/src/material/button/testing/button-harness.ts @@ -60,8 +60,9 @@ export class MatButtonHarness extends ContentContainerComponentHarness { .addOption('buttonType', options.buttonType, (harness, buttonType) => HarnessPredicate.stringMatches(harness.getType(), buttonType), ) - .addOption('iconName', options.iconName, (harness, iconName) => { - return harness.hasHarness(MatIconHarness.with({name: iconName})); + .addOption('iconName', options.iconName, async (harness, iconName) => { + const result = await harness.locatorForOptional(MatIconHarness.with({name: iconName}))(); + return result !== null; }); } diff --git a/src/material/checkbox/checkbox.scss b/src/material/checkbox/checkbox.scss index 651656e8fb56..c07c0b111e55 100644 --- a/src/material/checkbox/checkbox.scss +++ b/src/material/checkbox/checkbox.scss @@ -105,6 +105,6 @@ $fallbacks: m3-checkbox.get-tokens(); // For checkboxes render the focus indicator when we know // the hidden input is focused (slightly different for each control). -.mdc-checkbox__native-control:focus ~ .mat-focus-indicator::before { +.mdc-checkbox__native-control:focus-visible ~ .mat-focus-indicator::before { content: ''; } diff --git a/src/material/chips/chip.scss b/src/material/chips/chip.scss index acace3db6bb0..f780d673ded6 100644 --- a/src/material/chips/chip.scss +++ b/src/material/chips/chip.scss @@ -737,7 +737,7 @@ $fallbacks: m3-chip.get-tokens(); // The chip has multiple focus targets so we have to put the indicator on // a separate element, rather than on the focusable element itself. -.mat-mdc-chip-action:focus .mat-focus-indicator::before { +.mat-mdc-chip-action:focus-visible .mat-focus-indicator::before { content: ''; } @@ -747,3 +747,9 @@ $fallbacks: m3-chip.get-tokens(); .mdc-evolution-chip__icon, .mat-mdc-chip-edit .mat-icon, .mat-mdc-chip-remove .mat-icon { min-height: fit-content; } + +// The `min-height: fit-content` above can stretch out image in Safari (see #32251). +// It also isn't necessary for image since their content doesn't affect the image container. +img.mdc-evolution-chip__icon { + min-height: 0; +} diff --git a/src/material/chips/chips.md b/src/material/chips/chips.md index 3464f0acddbd..6e52171d810a 100644 --- a/src/material/chips/chips.md +++ b/src/material/chips/chips.md @@ -65,6 +65,9 @@ Users can press delete to remove a chip. Pressing delete triggers the `removed` A `` can be combined with `` to enable free-form chip input with suggestions. +> _Please note: when using `MatChipsModule` together with `MatAutocompleteModule`, the order in which modules are imported matters._ +> _To ensure correct behavior (e.g., preventing adding typed text when autocomplete option is selected via keyboard), make sure to import `MatAutocompleteModule` before `MatChipsModule`._ + ### Icons @@ -141,7 +144,7 @@ The chips components support 3 user interaction patterns, each with its own cont `` and `` : These elements implement a grid accessibility pattern. Use them as part of a free form input that allows users to enter text to add chips. -Note : be sure to have the input element be a sibling of mat-chip-grid to ensure accessibility of the input element by accessibility devices such as Voice Control. It is also recommended to apply an appropriate `aria-label` to the input to optimize accessibility of the input. +> _Please note: be sure to have the input element be a sibling of `mat-chip-grid` to ensure accessibility of the input element by accessibility devices such as Voice Control. It is also recommended to apply an appropriate `aria-label` to the input to optimize accessibility of the input._ ```html diff --git a/src/material/core/focus-indicators/_private.scss b/src/material/core/focus-indicators/_private.scss index 7cee4592e5ab..1d2127e032bb 100644 --- a/src/material/core/focus-indicators/_private.scss +++ b/src/material/core/focus-indicators/_private.scss @@ -28,7 +28,7 @@ $default-border-radius: 4px; // By default, render the focus indicator when the focus indicator host element takes focus. // Defining a pseudo element's content will cause it to render. - &:focus::before { + &:focus-visible::before { content: ''; } } @@ -78,7 +78,7 @@ $default-border-radius: 4px; @mixin strong-focus-indicators($config: ()) { // Default focus indicator config. $default-config: ( - border-color: black, + border-color: var(--mat-sys-secondary, black), display: block, ); diff --git a/src/material/datepicker/calendar.scss b/src/material/datepicker/calendar.scss index 5ec4a394531a..15510913ee1e 100644 --- a/src/material/datepicker/calendar.scss +++ b/src/material/datepicker/calendar.scss @@ -132,7 +132,7 @@ $fallbacks: m3-datepicker.get-tokens(); // For calendar cells, render the focus indicator when the parent cell is // focused. -.mat-calendar-body-cell:focus .mat-focus-indicator::before { +.mat-calendar-body-cell:focus-visible .mat-focus-indicator::before { content: ''; } diff --git a/src/material/datepicker/date-range-input-parts.ts b/src/material/datepicker/date-range-input-parts.ts index d65457b5b093..8bef638e2343 100644 --- a/src/material/datepicker/date-range-input-parts.ts +++ b/src/material/datepicker/date-range-input-parts.ts @@ -186,8 +186,8 @@ abstract class MatDateRangeInputPartBase return source !== this._rangeInput._startInput && source !== this._rangeInput._endInput; } - protected override _assignValueProgrammatically(value: D | null) { - super._assignValueProgrammatically(value); + protected override _assignValueProgrammatically(value: D | null, reformat: boolean) { + super._assignValueProgrammatically(value, reformat); const opposite = ( this === (this._rangeInput._startInput as MatDateRangeInputPartBase) ? this._rangeInput._endInput diff --git a/src/material/datepicker/date-selection-model.ts b/src/material/datepicker/date-selection-model.ts index 5f1f0b98435a..0f0a2970d0e4 100644 --- a/src/material/datepicker/date-selection-model.ts +++ b/src/material/datepicker/date-selection-model.ts @@ -53,9 +53,10 @@ export interface DateSelectionModelChange { * @docs-private */ @Injectable() -export abstract class MatDateSelectionModel> - implements OnDestroy -{ +export abstract class MatDateSelectionModel< + S, + D = ExtractDateTypeFromSelection, +> implements OnDestroy { private readonly _selectionChanged = new Subject>(); /** Emits when the selection has changed. */ diff --git a/src/material/datepicker/datepicker-base.ts b/src/material/datepicker/datepicker-base.ts index 657923acc31e..f7a106d9bcac 100644 --- a/src/material/datepicker/datepicker-base.ts +++ b/src/material/datepicker/datepicker-base.ts @@ -368,10 +368,10 @@ export interface MatDatepickerPanel< /** Base class for a datepicker. */ @Directive() export abstract class MatDatepickerBase< - C extends MatDatepickerControl, - S, - D = ExtractDateTypeFromSelection, - > + C extends MatDatepickerControl, + S, + D = ExtractDateTypeFromSelection, +> implements MatDatepickerPanel, OnDestroy, OnChanges { private _injector = inject(Injector); diff --git a/src/material/datepicker/datepicker-input-base.ts b/src/material/datepicker/datepicker-input-base.ts index 01de0feb77b5..52cff1b59ddc 100644 --- a/src/material/datepicker/datepicker-input-base.ts +++ b/src/material/datepicker/datepicker-input-base.ts @@ -94,7 +94,7 @@ export abstract class MatDatepickerInputBase | undefined; @@ -259,7 +259,7 @@ export abstract class MatDatepickerInputBase { - this._assignValueProgrammatically(this.value); + this._assignValueProgrammatically(this.value, true); }); } @@ -289,22 +289,25 @@ export abstract class MatDatepickerInputBase void): void { this._cvaOnChange = fn; } - // Implemented as part of ControlValueAccessor. + /** Implemented as part of ControlValueAccessor. */ registerOnTouched(fn: () => void): void { this._onTouched = fn; } - // Implemented as part of ControlValueAccessor. + /** Implemented as part of ControlValueAccessor. */ setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; } @@ -398,12 +401,15 @@ export abstract class MatDatepickerInputBase { expect(formControl.hasError('matDatepickerParse')).toBe(true); }); + + it('should not re-format the input value if the forms module re-assigns the same date', () => { + const input = fixture.nativeElement.querySelector('input'); + const date = new Date(2017, JAN, 1); + testComponent.formControl.setValue(date); + fixture.detectChanges(); + expect(input.value).toContain('2017'); + + // Note: this isn't how users would behave, but it captures + // the sequence of events with signal forms. + input.value = 'foo'; + testComponent.formControl.setValue(date); + fixture.detectChanges(); + + expect(input.value).toBe('foo'); + }); + + it('should not re-format the input value if the forms module re-assigns null', () => { + const input = fixture.nativeElement.querySelector('input'); + testComponent.formControl.setValue(null); + fixture.detectChanges(); + expect(input.value).toBe(''); + + // Note: this isn't how users would behave, but it captures + // the sequence of events with signal forms. + input.value = 'foo'; + testComponent.formControl.setValue(null); + fixture.detectChanges(); + + expect(input.value).toBe('foo'); + }); }); describe('datepicker with mat-datepicker-toggle', () => { diff --git a/src/material/dialog/dialog-ref.ts b/src/material/dialog/dialog-ref.ts index c247fad81cb1..21a048acdd7d 100644 --- a/src/material/dialog/dialog-ref.ts +++ b/src/material/dialog/dialog-ref.ts @@ -8,7 +8,7 @@ /** Possible states of the lifecycle of a dialog. */ import {FocusOrigin} from '@angular/cdk/a11y'; -import {merge, Observable, Subject} from 'rxjs'; +import {merge, Observable, ReplaySubject} from 'rxjs'; import {DialogRef} from '@angular/cdk/dialog'; import {DialogPosition, MatDialogConfig} from './dialog-config'; import {MatDialogContainer} from './dialog-container'; @@ -43,10 +43,10 @@ export class MatDialogRef { id: string; /** Subject for notifying the user that the dialog has finished opening. */ - private readonly _afterOpened = new Subject(); + private readonly _afterOpened = new ReplaySubject(1); /** Subject for notifying the user that the dialog has started closing. */ - private readonly _beforeClosed = new Subject(); + private readonly _beforeClosed = new ReplaySubject(1); /** Result to be passed to afterClosed. */ private _result: R | undefined; diff --git a/src/material/dialog/dialog.spec.ts b/src/material/dialog/dialog.spec.ts index d68cc19fe351..1b79514231fe 100644 --- a/src/material/dialog/dialog.spec.ts +++ b/src/material/dialog/dialog.spec.ts @@ -11,7 +11,7 @@ import { dispatchMouseEvent, patchElementFocus, } from '@angular/cdk/testing/private'; -import {Location} from '@angular/common'; +import {AsyncPipe, Location} from '@angular/common'; import {SpyLocation} from '@angular/common/testing'; import { ChangeDetectionStrategy, @@ -39,6 +39,7 @@ import { } from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Subject} from 'rxjs'; +import {map} from 'rxjs/operators'; import {CLOSE_ANIMATION_DURATION, OPEN_ANIMATION_DURATION} from './dialog-container'; import { MAT_DIALOG_DATA, @@ -1240,6 +1241,14 @@ describe('MatDialog', () => { }), ); + it('should be able to use afterOpened in the template while animations are disabled', async () => { + const ref = dialog.open(DialogWithAfterOpenSubscription); + await new Promise(resolve => setTimeout(resolve, 10)); + + expect(ref.componentInstance.animations.animationsDisabled).toBe(true); + expect(overlayContainerElement.textContent).toContain('The dialog is now open!'); + }); + describe('hasBackdrop option', () => { it('should have a backdrop', () => { dialog.open(PizzaMsg, {hasBackdrop: true, viewContainerRef: testViewContainerRef}); @@ -2450,3 +2459,15 @@ class ModuleBoundDialogChildComponent { providers: [ModuleBoundDialogService], }) class ModuleBoundDialogModule {} + +@Component({ + template: `{{message | async}}`, + imports: [AsyncPipe], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +class DialogWithAfterOpenSubscription { + dialogRef = inject(MatDialogRef); + animations = inject(MATERIAL_ANIMATIONS); + + protected message = this.dialogRef.afterOpened().pipe(map(() => 'The dialog is now open!')); +} diff --git a/src/material/form-field/_mdc-text-field-structure.scss b/src/material/form-field/_mdc-text-field-structure.scss index f9b63d6cca94..e84c27a5a683 100644 --- a/src/material/form-field/_mdc-text-field-structure.scss +++ b/src/material/form-field/_mdc-text-field-structure.scss @@ -369,6 +369,8 @@ $fallbacks: m3-form-field.get-tokens(); box-sizing: border-box; height: 100%; pointer-events: none; + // Reset border coming from something like Tailwind (see #32511). + border: none; border-top: 1px solid; border-bottom: 1px solid; diff --git a/src/material/icon/BUILD.bazel b/src/material/icon/BUILD.bazel index bf4df42d2a6e..200496244769 100644 --- a/src/material/icon/BUILD.bazel +++ b/src/material/icon/BUILD.bazel @@ -68,7 +68,6 @@ ng_project( "icon-registry.ts", "index.ts", "public-api.ts", - "trusted-types.ts", ], assets = [ ":css", @@ -79,6 +78,7 @@ ng_project( "//:node_modules/@angular/platform-browser", "//:node_modules/rxjs", "//src:dev_mode_types", + "//src/cdk/private", "//src/material/core", ], ) diff --git a/src/material/icon/icon-registry.ts b/src/material/icon/icon-registry.ts index 2555b6342ddb..3d69ff4a7062 100644 --- a/src/material/icon/icon-registry.ts +++ b/src/material/icon/icon-registry.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ +import {TrustedHTML, trustedHTMLFromString} from '@angular/cdk/private'; import {HttpClient, HttpErrorResponse} from '@angular/common/http'; import { ErrorHandler, @@ -19,7 +20,6 @@ import { import {DomSanitizer, SafeHtml, SafeResourceUrl} from '@angular/platform-browser'; import {forkJoin, Observable, of as observableOf, throwError as observableThrow} from 'rxjs'; import {catchError, finalize, map, share, tap} from 'rxjs/operators'; -import {TrustedHTML, trustedHTMLFromString} from './trusted-types'; /** * Returns an exception to be thrown in the case when attempting to diff --git a/src/material/list/list.scss b/src/material/list/list.scss index 3f78705aaca2..8d1802e2b23c 100644 --- a/src/material/list/list.scss +++ b/src/material/list/list.scss @@ -131,7 +131,7 @@ a.mdc-list-item--activated { // For list items, render the focus indicator when the parent // listem item is focused. - &:focus > .mat-focus-indicator::before { + &:focus-visible > .mat-focus-indicator::before { content: ''; } } diff --git a/src/material/menu/testing/BUILD.bazel b/src/material/menu/testing/BUILD.bazel index 8db24891f557..bb8065b43cb3 100644 --- a/src/material/menu/testing/BUILD.bazel +++ b/src/material/menu/testing/BUILD.bazel @@ -11,6 +11,7 @@ ts_project( deps = [ "//src/cdk/coercion", "//src/cdk/testing", + "//src/material/icon/testing", ], ) @@ -31,6 +32,7 @@ ng_project( "//src/cdk/testing", "//src/cdk/testing/private", "//src/cdk/testing/testbed", + "//src/material/icon", "//src/material/menu", ], ) diff --git a/src/material/menu/testing/menu-harness-filters.ts b/src/material/menu/testing/menu-harness-filters.ts index b2bdccc45653..fc74bc6daa9a 100644 --- a/src/material/menu/testing/menu-harness-filters.ts +++ b/src/material/menu/testing/menu-harness-filters.ts @@ -12,6 +12,9 @@ import {BaseHarnessFilters} from '@angular/cdk/testing'; export interface MenuHarnessFilters extends BaseHarnessFilters { /** Only find instances whose trigger text matches the given value. */ triggerText?: string | RegExp; + + /** Only find instances where the trigger contains an icon whose name matches the given value. */ + triggerIconName?: string | RegExp; } /** A set of criteria that can be used to filter a list of `MatMenuItemHarness` instances. */ diff --git a/src/material/menu/testing/menu-harness.spec.ts b/src/material/menu/testing/menu-harness.spec.ts index 9db9280c9d47..84aa1721d16c 100644 --- a/src/material/menu/testing/menu-harness.spec.ts +++ b/src/material/menu/testing/menu-harness.spec.ts @@ -1,6 +1,7 @@ import {Component} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {HarnessLoader} from '@angular/cdk/testing'; +import {MatIconModule} from '@angular/material/icon'; import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import {MatMenuModule} from '../menu-module'; import {MatMenuHarness} from './menu-harness'; @@ -18,7 +19,7 @@ describe('MatMenuHarness', () => { it('should load all menu harnesses', async () => { const menues = await loader.getAllHarnesses(MatMenuHarness); - expect(menues.length).toBe(2); + expect(menues.length).toBe(3); }); it('should load menu with exact text', async () => { @@ -33,6 +34,12 @@ describe('MatMenuHarness', () => { expect(await menus[0].getTriggerText()).toBe('Settings'); }); + it('should load menu by icon name', async () => { + const menus = await loader.getAllHarnesses(MatMenuHarness.with({triggerIconName: 'wrench'})); + expect(menus.length).toBe(1); + expect(await (await menus[0].host()).getAttribute('id')).toBe('with-icon'); + }); + it('should get disabled state', async () => { const [enabledMenu, disabledMenu] = await loader.getAllHarnesses(MatMenuHarness); expect(await enabledMenu.isDisabled()).toBe(false); @@ -146,39 +153,42 @@ describe('MatMenuHarness', () => { @Component({ template: ` - - - - - Profile - Account - + + + + + + Profile + Account + `, - imports: [MatMenuModule], + imports: [MatMenuModule, MatIconModule], }) class MenuHarnessTest {} @Component({ template: ` - + - - - - - + + + + + - - - + + + - - - + + + - - - + + + `, imports: [MatMenuModule], }) diff --git a/src/material/menu/testing/menu-harness.ts b/src/material/menu/testing/menu-harness.ts index 8bbe6215273f..55951213b65f 100644 --- a/src/material/menu/testing/menu-harness.ts +++ b/src/material/menu/testing/menu-harness.ts @@ -14,6 +14,7 @@ import { TestElement, } from '@angular/cdk/testing'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; +import {MatIconHarness} from '@angular/material/icon/testing'; import {MenuHarnessFilters, MenuItemHarnessFilters} from './menu-harness-filters'; /** Harness for interacting with a mat-menu in tests. */ @@ -32,11 +33,16 @@ export class MatMenuHarness extends ContentContainerComponentHarness { this: ComponentHarnessConstructor, options: MenuHarnessFilters = {}, ): HarnessPredicate { - return new HarnessPredicate(this, options).addOption( - 'triggerText', - options.triggerText, - (harness, text) => HarnessPredicate.stringMatches(harness.getTriggerText(), text), - ); + return new HarnessPredicate(this, options) + .addOption('triggerText', options.triggerText, (harness, text) => + HarnessPredicate.stringMatches(harness.getTriggerText(), text), + ) + .addOption('triggerIconName', options.triggerIconName, async (harness, triggerIconName) => { + const result = await harness.locatorForOptional( + MatIconHarness.with({name: triggerIconName}), + )(); + return result !== null; + }); } /** Whether the menu is disabled. */ diff --git a/src/material/schematics/BUILD.bazel b/src/material/schematics/BUILD.bazel index e695d1279db2..cc4767a7768d 100644 --- a/src/material/schematics/BUILD.bazel +++ b/src/material/schematics/BUILD.bazel @@ -126,19 +126,11 @@ ts_project( "//:node_modules/@types/jasmine", "//:node_modules/@types/node", "//:node_modules/fs-extra", + "//:node_modules/parse5", "//src/cdk/schematics/testing", ], ) -filegroup( - name = "schematics_test_cases", - testonly = True, - srcs = glob([ - "ng-update/test-cases/**/*_input.ts", - "ng-update/test-cases/**/*_expected_output.ts", - ]), -) - jasmine_test( name = "unit_tests", data = [ @@ -146,7 +138,6 @@ jasmine_test( ":ng_generate_assets", ":schema_assets", ":schematics", - ":schematics_test_cases", ":unit_test_sources", "//src/material/schematics:package_json", ], diff --git a/src/material/schematics/migration-utilities/BUILD.bazel b/src/material/schematics/migration-utilities/BUILD.bazel index 36ddf07c8749..975e3da4a06a 100644 --- a/src/material/schematics/migration-utilities/BUILD.bazel +++ b/src/material/schematics/migration-utilities/BUILD.bazel @@ -17,7 +17,7 @@ ts_project( ts_project( name = "unit_tests_lib", testonly = True, - srcs = glob(["**/*.spec.ts"] + ["rules/components/test-setup-helper.ts"]), + srcs = glob(["**/*.spec.ts"]), tsconfig = "//src/material/schematics:tsconfig-test", deps = [ ":migration-utilities", diff --git a/src/material/schematics/ng-add/index.spec.ts b/src/material/schematics/ng-add/index.spec.ts index 9101f6a017c9..34bdae680abc 100644 --- a/src/material/schematics/ng-add/index.spec.ts +++ b/src/material/schematics/ng-add/index.spec.ts @@ -4,7 +4,6 @@ import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; import { getProjectFromWorkspace, getProjectIndexFiles, - getProjectStyleFile, getProjectTargetOptions, } from '@angular/cdk/schematics'; import {createTestApp, createTestLibrary, getFileContent} from '../../../cdk/schematics/testing'; @@ -87,7 +86,7 @@ describe('ng-add schematic', () => { const workspace = await readWorkspace(tree); const project = getProjectFromWorkspace(workspace, baseOptions.project); - expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss'); + expectProjectStyleFile(project, 'projects/material/src/material-theme.scss'); }); it('should support adding a custom theme', async () => { @@ -121,12 +120,12 @@ describe('ng-add schematic', () => { ); const workspace = await readWorkspace(tree); const project = getProjectFromWorkspace(workspace, baseOptions.project); - const expectedStylesPath = normalize(`/${project.root}/src/custom-theme.scss`); + const expectedStylesPath = normalize(`/${project.root}/src/material-theme.scss`); expect(tree.files) .withContext('Expected a custom theme file to be created') .toContain(expectedStylesPath); - expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss'); + expectProjectStyleFile(project, 'projects/material/src/material-theme.scss'); }); it('should add font links', async () => { @@ -154,20 +153,6 @@ describe('ng-add schematic', () => { }); }); - it('should add material app styles', async () => { - const tree = await runner.runSchematic('ng-add-setup-project', baseOptions, appTree); - const workspace = await readWorkspace(tree); - const project = getProjectFromWorkspace(workspace, baseOptions.project); - - const defaultStylesPath = getProjectStyleFile(project)!; - const htmlContent = tree.read(defaultStylesPath)!.toString(); - - expect(htmlContent).toContain('html, body { height: 100%; }'); - expect(htmlContent).toContain( - 'body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }', - ); - }); - describe('custom project builders', () => { /** Overwrites a target builder for the workspace in the given tree */ function overwriteTargetBuilder(tree: Tree, targetName: 'build' | 'test', newBuilder: string) { @@ -217,15 +202,15 @@ describe('ng-add schematic', () => { describe('theme files', () => { it('should not overwrite existing custom theme files', async () => { - appTree.create('/projects/material/custom-theme.scss', 'custom-theme'); + appTree.create('/projects/material/material-theme.scss', 'material-theme'); const tree = await runner.runSchematic( 'ng-add-setup-project', {...baseOptions, theme: 'azure-blue'}, appTree, ); - expect(tree.readContent('/projects/material/custom-theme.scss')) + expect(tree.readContent('/projects/material/material-theme.scss')) .withContext('Expected the old custom theme content to be unchanged.') - .toBe('custom-theme'); + .toBe('material-theme'); }); }); @@ -271,7 +256,7 @@ describe('ng-add schematic', () => { const workspace = await readWorkspace(tree); const project = getProjectFromWorkspace(workspace, baseOptions.project); - expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss'); + expectProjectStyleFile(project, 'projects/material/src/material-theme.scss'); }); }); @@ -317,7 +302,7 @@ describe('ng-add schematic', () => { const workspace = await readWorkspace(tree); const project = getProjectFromWorkspace(workspace, baseOptions.project); - expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss'); + expectProjectStyleFile(project, 'projects/material/src/material-theme.scss'); }); }); @@ -354,7 +339,7 @@ describe('ng-add schematic', () => { const workspace = await readWorkspace(tree); const project = getProjectFromWorkspace(workspace, baseOptions.project); - expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss'); + expectProjectStyleFile(project, 'projects/material/src/material-theme.scss'); }); }); }); diff --git a/src/material/schematics/ng-add/setup-project.ts b/src/material/schematics/ng-add/setup-project.ts index f0897ade7206..652679b52a4e 100644 --- a/src/material/schematics/ng-add/setup-project.ts +++ b/src/material/schematics/ng-add/setup-project.ts @@ -7,7 +7,7 @@ */ import {chain, Rule, SchematicContext, Tree} from '@angular-devkit/schematics'; -import {getProjectFromWorkspace, getProjectStyleFile} from '@angular/cdk/schematics'; +import {getProjectFromWorkspace} from '@angular/cdk/schematics'; import {readWorkspace} from '@schematics/angular/utility'; import {ProjectType} from '@schematics/angular/utility/workspace-models'; import {addFontsToIndex} from './fonts/material-fonts'; @@ -25,11 +25,7 @@ export default function (options: Schema): Rule { const project = getProjectFromWorkspace(workspace, options.project); if (project.extensions['projectType'] === ProjectType.Application) { - return chain([ - addThemeToAppStyles(options), - addFontsToIndex(options), - addMaterialAppStyles(options), - ]); + return chain([addThemeToAppStyles(options), addFontsToIndex(options)]); } context.logger.warn( 'Angular Material has been set up in your workspace. There is no additional setup ' + @@ -40,48 +36,3 @@ export default function (options: Schema): Rule { return; }; } - -/** - * Adds custom Material styles to the project style file. The custom CSS sets up the Roboto font - * and reset the default browser body margin. - */ -function addMaterialAppStyles(options: Schema) { - return async (host: Tree, context: SchematicContext) => { - const workspace = await readWorkspace(host); - const project = getProjectFromWorkspace(workspace, options.project); - const styleFilePath = getProjectStyleFile(project); - const logger = context.logger; - - if (!styleFilePath) { - logger.error(`Could not find the default style file for this project.`); - logger.info(`Consider manually adding the Roboto font to your CSS.`); - logger.info(`More information at https://fonts.google.com/specimen/Roboto`); - return; - } - - const buffer = host.read(styleFilePath); - - if (!buffer) { - logger.error( - `Could not read the default style file within the project ` + `(${styleFilePath})`, - ); - logger.info(`Please consider manually setting up the Roboto font.`); - return; - } - - const htmlContent = buffer.toString(); - const insertion = - '\n' + - `html, body { height: 100%; }\n` + - `body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }\n`; - - if (htmlContent.includes(insertion)) { - return; - } - - const recorder = host.beginUpdate(styleFilePath); - - recorder.insertLeft(htmlContent.length, insertion); - host.commitUpdate(recorder); - }; -} diff --git a/src/material/schematics/ng-add/theming/create-custom-theme.ts b/src/material/schematics/ng-add/theming/create-theme.ts similarity index 88% rename from src/material/schematics/ng-add/theming/create-custom-theme.ts rename to src/material/schematics/ng-add/theming/create-theme.ts index 9a648ead5f45..fb25eb8eb010 100644 --- a/src/material/schematics/ng-add/theming/create-custom-theme.ts +++ b/src/material/schematics/ng-add/theming/create-theme.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.dev/license */ -/** Create custom theme for the given application configuration. */ -export function createCustomTheme(userPaletteChoice: string): string { - const colorPalettes = new Map([ +/** Create theme for the given application configuration. */ +export function createTheme(userPaletteChoice: string): string { + const colorPalettes = new Map([ ['azure-blue', {primary: 'azure', tertiary: 'blue'}], ['rose-red', {primary: 'rose', tertiary: 'red'}], ['magenta-violet', {primary: 'magenta', tertiary: 'violet'}], @@ -23,6 +23,7 @@ export function createCustomTheme(userPaletteChoice: string): string { @use '@angular/material' as mat; html { + height: 100%; @include mat.theme(( color: ( primary: mat.$${colorPalettes.get(userPaletteChoice)!.primary}-palette, @@ -48,6 +49,7 @@ body { // Reset the user agent margin. margin: 0; + height: 100%; } `; } diff --git a/src/material/schematics/ng-add/theming/theming.ts b/src/material/schematics/ng-add/theming/theming.ts index 7486d1b61114..f8ebae0096f3 100644 --- a/src/material/schematics/ng-add/theming/theming.ts +++ b/src/material/schematics/ng-add/theming/theming.ts @@ -19,13 +19,13 @@ import {InsertChange} from '@schematics/angular/utility/change'; import {ProjectDefinition, readWorkspace, updateWorkspace} from '@schematics/angular/utility'; import {join} from 'path'; import {Schema} from '../schema'; -import {createCustomTheme} from './create-custom-theme'; +import {createTheme} from './create-theme'; /** Path segment that can be found in paths that refer to a prebuilt theme. */ const prebuiltThemePathSegment = '@angular/material/prebuilt-themes'; /** Default file name of the custom theme that can be generated. */ -const defaultCustomThemeFilename = 'custom-theme.scss'; +const defaultThemeFilename = 'material-theme.scss'; /** Add pre-built styles to the main project style file. */ export function addThemeToAppStyles(options: Schema): Rule { @@ -40,15 +40,15 @@ export function addThemeToAppStyles(options: Schema): Rule { palettes = 'azure-blue'; } - return insertCustomTheme(palettes, options.project, host, context.logger); + return insertTheme(palettes, options.project, host, context.logger); }; } /** - * Insert an Angular Material theme to project style file. If no valid style file could be found, a new - * Scss file for the custom theme will be created. + * Insert an Angular Material theme to project style file. If no valid style file could be found, + * a new Sass file for the theme will be created. */ -async function insertCustomTheme( +async function insertTheme( palettes: string, projectName: string, host: Tree, @@ -57,7 +57,7 @@ async function insertCustomTheme( const workspace = await readWorkspace(host); const project = getProjectFromWorkspace(workspace, projectName); const stylesPath = getProjectStyleFile(project, 'scss'); - const themeContent = createCustomTheme(palettes); + const themeContent = createTheme(palettes); if (!stylesPath) { if (!project.sourceRoot) { @@ -69,16 +69,16 @@ async function insertCustomTheme( // Normalize the path through the devkit utilities because we want to avoid having // unnecessary path segments and windows backslash delimiters. - const customThemePath = normalize(join(project.sourceRoot, defaultCustomThemeFilename)); + const themePath = normalize(join(project.sourceRoot, defaultThemeFilename)); - if (host.exists(customThemePath)) { - logger.warn(`Cannot create a custom Angular Material theme because - ${customThemePath} already exists. Skipping theme generation.`); + if (host.exists(themePath)) { + logger.warn(`Cannot create an Angular Material theme because + ${themePath} already exists. Skipping theme generation.`); return noop(); } - host.create(customThemePath, themeContent); - return addThemeStyleToTarget(projectName, 'build', customThemePath, logger); + host.create(themePath, themeContent); + return addThemeStyleToTarget(projectName, 'build', themePath, logger); } const insertion = new InsertChange(stylesPath, 0, themeContent); @@ -122,10 +122,10 @@ function addThemeStyleToTarget( // theme file. If a custom theme is set up, we are not able to safely replace the custom // theme because these files can contain custom styles, while prebuilt themes are // always packaged and considered replaceable. - if (stylePath.includes(defaultCustomThemeFilename)) { + if (stylePath.includes(defaultThemeFilename)) { logger.error( `Could not add the selected theme to the CLI project ` + - `configuration because there is already a custom theme file referenced.`, + `configuration because there is already a theme file referenced.`, ); logger.info(`Please manually add the following style file to your configuration:`); logger.info(` ${assetPath}`); diff --git a/src/material/schematics/ng-generate/theme-color/BUILD.bazel b/src/material/schematics/ng-generate/theme-color/BUILD.bazel index 2c09bc59d954..d557aa39f459 100644 --- a/src/material/schematics/ng-generate/theme-color/BUILD.bazel +++ b/src/material/schematics/ng-generate/theme-color/BUILD.bazel @@ -58,8 +58,9 @@ ts_project( testonly = True, srcs = glob([ "**/*.spec.ts", + ]) + [ "index_bundled.d.ts", - ] + ["rules/components/test-setup-helper.ts"]), + ], data = [":index_bundled"], tsconfig = "//src/material/schematics:tsconfig-test", deps = [ diff --git a/src/material/schematics/ng-update/BUILD.bazel b/src/material/schematics/ng-update/BUILD.bazel index 6ee349fda826..92a6ea981dd8 100644 --- a/src/material/schematics/ng-update/BUILD.bazel +++ b/src/material/schematics/ng-update/BUILD.bazel @@ -1,5 +1,5 @@ -load("//tools:defaults.bzl", "jasmine_test", "ts_project") load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild") +load("//tools:defaults.bzl", "jasmine_test", "ts_project") ts_project( name = "ng_update_lib", @@ -40,15 +40,6 @@ esbuild( deps = [":ng_update_lib"], ) -filegroup( - name = "schematics_test_cases", - testonly = True, - srcs = glob([ - "test-cases/**/*_input.ts", - "test-cases/**/*_expected_output.ts", - ]), -) - ts_project( name = "test_lib", testonly = True, @@ -59,6 +50,7 @@ ts_project( "//:node_modules/@angular-devkit/core", "//:node_modules/@angular-devkit/schematics", "//:node_modules/@bazel/runfiles", + "//:node_modules/parse5", "//src/cdk/schematics/testing", "//src/material/schematics:node_modules/@angular/cdk/schematics", "//src/material/schematics:paths", @@ -69,7 +61,6 @@ jasmine_test( name = "test", data = [ ":ng_update_index", - ":schematics_test_cases", ":test_lib", "//src/material/schematics:collection_assets", "//src/material/schematics:node_modules/@angular/cdk/schematics", diff --git a/src/material/select/select.html b/src/material/select/select.html index 6eaecee7f5c3..ba6439f3fe45 100644 --- a/src/material/select/select.html +++ b/src/material/select/select.html @@ -40,6 +40,7 @@ [cdkConnectedOverlayPositions]="_positions" [cdkConnectedOverlayWidth]="_overlayWidth" [cdkConnectedOverlayFlexibleDimensions]="true" + cdkConnectedOverlayUsePopover="inline" (detach)="close()" (backdropClick)="close()" (overlayKeydown)="_handleOverlayKeydown($event)"> diff --git a/src/material/select/select.spec.ts b/src/material/select/select.spec.ts index 45a24a15d45f..e58ee1e5bee7 100644 --- a/src/material/select/select.spec.ts +++ b/src/material/select/select.spec.ts @@ -76,7 +76,7 @@ import { const DEFAULT_TYPEAHEAD_DEBOUNCE_INTERVAL = 200; describe('MatSelect', () => { - let overlayContainerElement: HTMLElement; + const supportsPopover = 'showPopover' in document.body; let dir: WritableSignal; let scrolledSubject = new Subject(); @@ -94,10 +94,23 @@ describe('MatSelect', () => { }, ], }); - - overlayContainerElement = TestBed.inject(OverlayContainer).getContainerElement(); }); + function getOverlayHost(fixture: ComponentFixture): HTMLElement | null { + return supportsPopover + ? fixture.nativeElement.querySelector('.cdk-overlay-popover') + : TestBed.inject(OverlayContainer) + .getContainerElement() + .querySelector('.cdk-overlay-connected-position-bounding-box'); + } + + function getBackdrop(fixture: ComponentFixture): HTMLElement | null { + const parent = supportsPopover + ? fixture.nativeElement + : TestBed.inject(OverlayContainer).getContainerElement(); + return parent.querySelector('.cdk-overlay-backdrop'); + } + describe('core', () => { describe('accessibility', () => { describe('for select', () => { @@ -414,7 +427,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - (overlayContainerElement.querySelectorAll('mat-option')[3] as HTMLElement).click(); + (getOverlayHost(fixture)?.querySelectorAll('mat-option')[3] as HTMLElement).click(); fixture.detectChanges(); flush(); @@ -769,7 +782,7 @@ describe('MatSelect', () => { multiFixture.componentInstance.select.open(); multiFixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(multiFixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -982,7 +995,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll('mat-option'); + const options = getOverlayHost(fixture)!.querySelectorAll('mat-option'); expect(host.getAttribute('aria-activedescendant')) .withContext('Expected aria-activedescendant to match the active option.') @@ -1004,7 +1017,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll('mat-option'); + const options = getOverlayHost(fixture)!.querySelectorAll('mat-option'); expect(host.getAttribute('aria-activedescendant')).toBe(options[0].id); @@ -1028,7 +1041,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll('mat-option'); + const options = getOverlayHost(fixture)!.querySelectorAll('mat-option'); expect(host.getAttribute('aria-activedescendant')).toBe(options[0].id); @@ -1055,7 +1068,7 @@ describe('MatSelect', () => { select.blur(); expect(document.activeElement).not.toBe(select, 'Expected trigger not to be focused.'); - const option = overlayContainerElement.querySelector('mat-option')! as HTMLElement; + const option = getOverlayHost(multiFixture)!.querySelector('mat-option')! as HTMLElement; option.click(); multiFixture.detectChanges(); @@ -1154,7 +1167,9 @@ describe('MatSelect', () => { trigger.click(); fixture.detectChanges(); - options = Array.from(overlayContainerElement.querySelectorAll('mat-option')); + options = Array.from( + getOverlayHost(fixture)!.querySelectorAll('mat-option'), + ); }); it('should set the role of mat-option to option', fakeAsync(() => { @@ -1202,7 +1217,9 @@ describe('MatSelect', () => { trigger.click(); multiFixture.detectChanges(); - options = Array.from(overlayContainerElement.querySelectorAll('mat-option')); + options = Array.from( + getOverlayHost(multiFixture)!.querySelectorAll('mat-option'), + ); expect( options.every( @@ -1340,7 +1357,9 @@ describe('MatSelect', () => { multiFixture.detectChanges(); flush(); - options = Array.from(overlayContainerElement.querySelectorAll('mat-option')); + options = Array.from( + getOverlayHost(multiFixture)!.querySelectorAll('mat-option'), + ); const pseudoCheckboxes = options .map(option => option.querySelector('.mat-pseudo-checkbox.mat-pseudo-checkbox-full')) .filter((x): x is HTMLElement => !!x); @@ -1366,7 +1385,7 @@ describe('MatSelect', () => { trigger = fixture.debugElement.query(By.css('.mat-mdc-select-trigger'))!.nativeElement; trigger.click(); fixture.detectChanges(); - groups = overlayContainerElement.querySelectorAll( + groups = getOverlayHost(fixture)!.querySelectorAll( 'mat-optgroup', ) as NodeListOf; }); @@ -1431,10 +1450,11 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); + const overlay = getOverlayHost(fixture)!; expect(fixture.componentInstance.select.panelOpen).toBe(true); - expect(overlayContainerElement.textContent).toContain('Steak'); - expect(overlayContainerElement.textContent).toContain('Pizza'); - expect(overlayContainerElement.textContent).toContain('Tacos'); + expect(overlay.textContent).toContain('Steak'); + expect(overlay.textContent).toContain('Pizza'); + expect(overlay.textContent).toContain('Tacos'); })); it('should close the panel when an item is clicked', fakeAsync(() => { @@ -1442,12 +1462,12 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); flush(); - expect(overlayContainerElement.textContent).toEqual(''); + expect(getOverlayHost(fixture)!).toBeFalsy(); expect(fixture.componentInstance.select.panelOpen).toBe(false); })); @@ -1456,15 +1476,11 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const backdrop = overlayContainerElement.querySelector( - '.cdk-overlay-backdrop', - ) as HTMLElement; - - backdrop.click(); + getBackdrop(fixture)!.click(); fixture.detectChanges(); flush(); - expect(overlayContainerElement.textContent).toEqual(''); + expect(getOverlayHost(fixture)!).toBeFalsy(); expect(fixture.componentInstance.select.panelOpen).toBe(false); })); @@ -1475,7 +1491,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const pane = getOverlayHost(fixture)?.querySelector('.cdk-overlay-pane') as HTMLElement; expect(pane.style.width).toBe('200px'); })); @@ -1486,7 +1502,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const pane = getOverlayHost(fixture)?.querySelector('.cdk-overlay-pane') as HTMLElement; const initialWidth = parseInt(pane.style.width || '0'); expect(initialWidth).toBeGreaterThan(0); @@ -1509,7 +1525,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const pane = getOverlayHost(fixture)?.querySelector('.cdk-overlay-pane') as HTMLElement; expect(pane.style.width).toBe('42px'); })); @@ -1522,7 +1538,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const pane = getOverlayHost(fixture)?.querySelector('.cdk-overlay-pane') as HTMLElement; expect(pane.style.width).toBeFalsy(); })); @@ -1535,7 +1551,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const pane = getOverlayHost(fixture)?.querySelector('.cdk-overlay-pane') as HTMLElement; expect(pane.style.width).toBeFalsy(); })); @@ -1590,7 +1606,7 @@ describe('MatSelect', () => { expect(fixture.componentInstance.select.panelOpen).toBe(true); - const panel = overlayContainerElement.querySelector('.mat-mdc-select-panel')!; + const panel = getOverlayHost(fixture)!.querySelector('.mat-mdc-select-panel')!; dispatchKeyboardEvent(panel, 'keydown', TAB); fixture.detectChanges(); flush(); @@ -1663,7 +1679,9 @@ describe('MatSelect', () => { trigger.click(); fixture.detectChanges(); - const panel = overlayContainerElement.querySelector('.mat-mdc-select-panel') as HTMLElement; + const panel = getOverlayHost(fixture)!.querySelector( + '.mat-mdc-select-panel', + ) as HTMLElement; expect(panel.classList).toContain('custom-one'); expect(panel.classList).toContain('custom-two'); @@ -1694,7 +1712,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const option = overlayContainerElement.querySelector('mat-option')!; + const option = getOverlayHost(fixture)!.querySelector('mat-option')!; dispatchFakeEvent(option, 'mousedown'); dispatchFakeEvent(option, 'mouseup'); @@ -1711,7 +1729,7 @@ describe('MatSelect', () => { trigger.click(); groupFixture.detectChanges(); - expect(document.querySelectorAll('.cdk-overlay-container mat-option').length) + expect(getOverlayHost(groupFixture)!.querySelectorAll('mat-option').length) .withContext('Expected at least one option to be rendered.') .toBeGreaterThan(0); }); @@ -1804,7 +1822,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - let option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + let option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); flush(); @@ -1813,7 +1831,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; expect(option.classList).toContain('mdc-list-item--selected'); expect(fixture.componentInstance.options.first.selected).toBe(true); @@ -1829,7 +1847,7 @@ describe('MatSelect', () => { const optionInstances = fixture.componentInstance.options.toArray(); const optionNodes: NodeListOf = - overlayContainerElement.querySelectorAll('mat-option'); + getOverlayHost(fixture)!.querySelectorAll('mat-option'); optionInstances[1].select(); fixture.detectChanges(); @@ -1844,7 +1862,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - let options = overlayContainerElement.querySelectorAll( + let options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -1856,7 +1874,9 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + options = getOverlayHost(fixture)!.querySelectorAll( + 'mat-option', + ) as NodeListOf; expect(options[1].classList).not.toContain('mdc-list-item--selected'); expect(options[2].classList).not.toContain('mdc-list-item--selected'); @@ -1873,7 +1893,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - let options = overlayContainerElement.querySelectorAll( + let options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -1888,7 +1908,9 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + options = getOverlayHost(fixture)!.querySelectorAll( + 'mat-option', + ) as NodeListOf; expect(options[0].classList).not.toContain( 'mdc-list-item--selected', @@ -1915,7 +1937,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - let firstOption = overlayContainerElement.querySelectorAll('mat-option')[0] as HTMLElement; + let firstOption = getOverlayHost(fixture)!.querySelectorAll('mat-option')[0] as HTMLElement; firstOption.click(); fixture.detectChanges(); @@ -1939,7 +1961,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); flush(); @@ -1974,7 +1996,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[8].click(); @@ -2018,7 +2040,7 @@ describe('MatSelect', () => { trigger.click(); fixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; options[2].click(); @@ -2037,7 +2059,7 @@ describe('MatSelect', () => { groupFixture.debugElement.query(By.css('.mat-mdc-select-trigger'))!.nativeElement.click(); groupFixture.detectChanges(); - const disabledGroup = overlayContainerElement.querySelectorAll('mat-optgroup')[1]; + const disabledGroup = getOverlayHost(groupFixture)!.querySelectorAll('mat-optgroup')[1]; const options = disabledGroup.querySelectorAll('mat-option'); (options[0] as HTMLElement).click(); @@ -2059,7 +2081,7 @@ describe('MatSelect', () => { const spy = jasmine.createSpy('option selection spy'); const subscription = fixture.componentInstance.select.optionSelectionChanges.subscribe(spy); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); flush(); @@ -2088,7 +2110,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); flush(); @@ -2106,7 +2128,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); flush(); @@ -2169,7 +2191,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; expect(options[1].classList) @@ -2193,7 +2215,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; expect(options[1].classList) @@ -2210,7 +2232,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); flush(); @@ -2240,7 +2262,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; expect(options[1].classList).not.toContain( @@ -2269,7 +2291,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; expect(options[1].classList).not.toContain( @@ -2292,10 +2314,7 @@ describe('MatSelect', () => { .withContext(`Expected the control to stay untouched when menu opened.`) .toEqual(false); - const backdrop = overlayContainerElement.querySelector( - '.cdk-overlay-backdrop', - ) as HTMLElement; - backdrop.click(); + getBackdrop(fixture)!.click(); dispatchFakeEvent(trigger, 'blur'); fixture.detectChanges(); flush(); @@ -2350,7 +2369,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); flush(); @@ -2417,9 +2436,9 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.querySelector('.mat-mdc-select-panel')) .withContext(`Expected select panel to stay closed.`) - .toEqual(''); + .toBeFalsy(); expect(fixture.componentInstance.select.panelOpen) .withContext(`Expected select panelOpen property to stay false.`) .toBe(false); @@ -2434,7 +2453,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.querySelector('.mat-mdc-select-panel')?.textContent) .withContext(`Expected select panel to open normally on re-enabled control`) .toContain('Steak'); expect(fixture.componentInstance.select.panelOpen) @@ -2478,7 +2497,7 @@ describe('MatSelect', () => { fixture.detectChanges(); host = fixture.debugElement.query(By.css('mat-select'))!.nativeElement; - panel = overlayContainerElement.querySelector('.mat-mdc-select-panel')! as HTMLElement; + panel = getOverlayHost(fixture)!.querySelector('.mat-mdc-select-panel')! as HTMLElement; })); it('should not scroll to options that are completely in the view', () => { @@ -2527,7 +2546,9 @@ describe('MatSelect', () => { flush(); host = groupFixture.debugElement.query(By.css('mat-select'))!.nativeElement; - panel = overlayContainerElement.querySelector('.mat-mdc-select-panel')! as HTMLElement; + panel = getOverlayHost(groupFixture)!.querySelector( + '.mat-mdc-select-panel', + )! as HTMLElement; for (let i = 0; i < 8; i++) { dispatchKeyboardEvent(host, 'keydown', DOWN_ARROW); @@ -2649,7 +2670,9 @@ describe('MatSelect', () => { flush(); host = groupFixture.debugElement.query(By.css('mat-select'))!.nativeElement; - panel = overlayContainerElement.querySelector('.mat-mdc-select-panel')! as HTMLElement; + panel = getOverlayHost(groupFixture)!.querySelector( + '.mat-mdc-select-panel', + )! as HTMLElement; for (let i = 0; i < 5; i++) { dispatchKeyboardEvent(host, 'keydown', DOWN_ARROW); @@ -2703,7 +2726,7 @@ describe('MatSelect', () => { trigger.click(); fixture.detectChanges(); - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement).click(); expect(fixture.componentInstance.changeListener).toHaveBeenCalled(); }); @@ -2712,7 +2735,7 @@ describe('MatSelect', () => { trigger.click(); fixture.detectChanges(); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; option.click(); option.click(); @@ -2750,9 +2773,9 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.querySelector('.mat-mdc-select-panel')) .withContext(`Expected select panel to stay closed.`) - .toEqual(''); + .toBeFalsy(); expect(fixture.componentInstance.select.panelOpen) .withContext(`Expected select panelOpen property to stay false.`) .toBe(false); @@ -2771,7 +2794,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - expect(overlayContainerElement.textContent) + expect(getOverlayHost(fixture)?.querySelector('.mat-mdc-select-panel')?.textContent) .withContext(`Expected select panel to open normally on re-enabled control`) .toContain('Steak'); expect(fixture.componentInstance.select.panelOpen) @@ -2802,13 +2825,13 @@ describe('MatSelect', () => { .withContext(`Expected trigger to be populated by the control's initial value.`) .toContain('Pizza'); - const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const pane = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane') as HTMLElement; expect(pane.style.width).toEqual('300px'); expect(fixture.componentInstance.select.panelOpen).toBe(true); - expect(overlayContainerElement.textContent).toContain('Steak'); - expect(overlayContainerElement.textContent).toContain('Pizza'); - expect(overlayContainerElement.textContent).toContain('Tacos'); + expect(pane.textContent).toContain('Steak'); + expect(pane.textContent).toContain('Pizza'); + expect(pane.textContent).toContain('Tacos'); })); }); @@ -2826,7 +2849,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + options = getOverlayHost(fixture)!.querySelectorAll('mat-option') as NodeListOf; })); it('should set the option id', fakeAsync(() => { @@ -2837,10 +2860,7 @@ describe('MatSelect', () => { .toContain('mat-option'); expect(options[0].id).not.toEqual(options[1].id, `Expected option IDs to be unique.`); - const backdrop = overlayContainerElement.querySelector( - '.cdk-overlay-backdrop', - ) as HTMLElement; - backdrop.click(); + getBackdrop(fixture)!.click(); fixture.detectChanges(); flush(); @@ -2848,7 +2868,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + options = getOverlayHost(fixture)!.querySelectorAll('mat-option') as NodeListOf; expect(options[0].id) .withContext(`Expected option ID to have the correct prefix.`) .toContain('mat-option'); @@ -2963,7 +2983,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const pane = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane') as HTMLElement; expect(pane.style.width).toBe('300px'); })); }); @@ -2979,7 +2999,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const pane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const pane = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane') as HTMLElement; expect(parseInt(pane.style.width as string)).toBeGreaterThan(0); })); }); @@ -3000,7 +3020,7 @@ describe('MatSelect', () => { fixture.componentInstance.select.open(); fixture.detectChanges(); - const panel = overlayContainerElement.querySelector('.mat-mdc-select-panel')! as HTMLElement; + const panel = getOverlayHost(fixture)!.querySelector('.mat-mdc-select-panel')! as HTMLElement; expect(panel.classList).toContain('mat-warn'); }); }); @@ -3329,7 +3349,7 @@ describe('MatSelect', () => { expect(fixture.componentInstance.options.first.selected) .withContext('Expected first option to be selected') .toBe(true); - expect(overlayContainerElement.querySelectorAll('mat-option')[0].classList) + expect(getOverlayHost(fixture)!.querySelectorAll('mat-option')[0].classList) .withContext('Expected first option to be selected') .toContain('mdc-list-item--selected'); })); @@ -3409,7 +3429,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + options = getOverlayHost(fixture)!.querySelectorAll('mat-option') as NodeListOf; options[0].click(); fixture.detectChanges(); flush(); @@ -3504,7 +3524,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf; + options = getOverlayHost(fixture)!.querySelectorAll('mat-option') as NodeListOf; options[0].click(); fixture.detectChanges(); flush(); @@ -3590,7 +3610,7 @@ describe('MatSelect', () => { trigger = fixture.debugElement.query(By.css('.mat-mdc-select-trigger'))!.nativeElement; trigger.click(); fixture.detectChanges(); - options = Array.from(overlayContainerElement.querySelectorAll('mat-option')); + options = Array.from(getOverlayHost(fixture)!.querySelectorAll('mat-option')); }); it('should set the select value', fakeAsync(() => { @@ -3648,7 +3668,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement).click(); fixture.detectChanges(); flush(); @@ -3660,7 +3680,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - (overlayContainerElement.querySelectorAll('mat-option')[2] as HTMLElement).click(); + (getOverlayHost(fixture)!.querySelectorAll('mat-option')[2] as HTMLElement).click(); fixture.detectChanges(); flush(); @@ -3684,7 +3704,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const option = overlayContainerElement.querySelectorAll('mat-option')[2]; + const option = getOverlayHost(fixture)!.querySelectorAll('mat-option')[2]; expect(option.classList).toContain('mdc-list-item--selected'); expect(fixture.componentInstance.select.value).toBe('sandwich-2'); @@ -3702,7 +3722,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement).click(); fixture.detectChanges(); flush(); @@ -3732,7 +3752,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const option = overlayContainerElement.querySelectorAll('mat-option')[1]; + const option = getOverlayHost(fixture)!.querySelectorAll('mat-option')[1]; expect(option.classList).toContain('mdc-list-item--selected'); expect(fixture.componentInstance.select.value).toBe('pizza-1'); @@ -3750,7 +3770,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -3784,7 +3804,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement).click(); fixture.detectChanges(); flush(); @@ -3806,7 +3826,7 @@ describe('MatSelect', () => { expect(document.activeElement).withContext('Expected trigger to be focused.').toBe(select); select.blur(); // Blur manually since the programmatic click might not do it. - (overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement).click(); + getBackdrop(fixture)!.click(); fixture.detectChanges(); flush(); @@ -3827,7 +3847,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement).click(); fixture.detectChanges(); flush(); @@ -3931,7 +3951,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement).click(); fixture.detectChanges(); flush(); @@ -3957,7 +3977,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement).click(); fixture.detectChanges(); flush(); @@ -3967,7 +3987,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - (overlayContainerElement.querySelector('mat-option') as HTMLElement).click(); + (getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement).click(); fixture.detectChanges(); flush(); @@ -4031,7 +4051,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const panel = overlayContainerElement.querySelector('.cdk-overlay-pane')!; + const panel = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!; const paneRect = panel.getBoundingClientRect(); const formFieldWrapperRect = formFieldWrapper.getBoundingClientRect(); @@ -4049,7 +4069,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const panel = overlayContainerElement.querySelector('.cdk-overlay-pane')!; + const panel = getOverlayHost(fixture)!.querySelector('.cdk-overlay-pane')!; const paneRect = panel.getBoundingClientRect(); const formFieldWrapperRect = formFieldWrapper.getBoundingClientRect(); @@ -4076,7 +4096,7 @@ describe('MatSelect', () => { trigger.click(); fixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -4092,7 +4112,7 @@ describe('MatSelect', () => { trigger.click(); fixture.detectChanges(); - const option = overlayContainerElement.querySelector('mat-option') as HTMLElement; + const option = getOverlayHost(fixture)?.querySelector('mat-option') as HTMLElement; option.click(); fixture.detectChanges(); @@ -4110,7 +4130,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -4132,7 +4152,7 @@ describe('MatSelect', () => { testInstance.control.setValue(['steak-0', 'eggs-5']); fixture.detectChanges(); - const optionNodes = overlayContainerElement.querySelectorAll( + const optionNodes = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -4149,7 +4169,7 @@ describe('MatSelect', () => { trigger.click(); fixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -4171,7 +4191,7 @@ describe('MatSelect', () => { expect(testInstance.select.panelOpen).toBe(true); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -4187,7 +4207,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -4206,7 +4226,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -4230,7 +4250,7 @@ describe('MatSelect', () => { fixture.detectChanges(); flush(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -4303,7 +4323,7 @@ describe('MatSelect', () => { expect(fixture.componentInstance.select._keyManager.activeItemIndex).toBe(0); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -4325,7 +4345,7 @@ describe('MatSelect', () => { trigger.click(); fixture.detectChanges(); - const options = overlayContainerElement.querySelectorAll( + const options = getOverlayHost(fixture)!.querySelectorAll( 'mat-option', ) as NodeListOf; @@ -4479,7 +4499,9 @@ describe('MatSelect', () => { trigger.click(); fixture.detectChanges(); - const optionNodes = Array.from(overlayContainerElement.querySelectorAll('mat-option')); + const optionNodes = Array.from( + getOverlayHost(fixture)!.querySelectorAll('mat-option'), + ); const optionInstances = testInstance.options.toArray(); expect(optionNodes.map(node => node.classList.contains('mdc-list-item--selected'))).toEqual([ @@ -4508,7 +4530,7 @@ describe('MatSelect', () => { fixture.detectChanges(); const optionNodes = Array.from( - overlayContainerElement.querySelectorAll('mat-option'), + getOverlayHost(fixture)!.querySelectorAll('mat-option'), ); const optionInstances = testInstance.options.toArray(); diff --git a/src/material/select/select.ts b/src/material/select/select.ts index b05f7f8b6e3a..a80bed47b3c9 100644 --- a/src/material/select/select.ts +++ b/src/material/select/select.ts @@ -71,6 +71,7 @@ import { NgForm, Validators, } from '@angular/forms'; +import {_getEventTarget} from '@angular/cdk/platform'; import { _animationsDisabled, _countGroupLabelsBeforeOption, @@ -1461,10 +1462,12 @@ export class MatSelect * @docs-private */ setDescribedByIds(ids: string[]) { + const element = this._elementRef.nativeElement; + if (ids.length) { - this._elementRef.nativeElement.setAttribute('aria-describedby', ids.join(' ')); + element.setAttribute('aria-describedby', ids.join(' ')); } else { - this._elementRef.nativeElement.removeAttribute('aria-describedby'); + element.removeAttribute('aria-describedby'); } } @@ -1472,7 +1475,22 @@ export class MatSelect * Implemented as part of MatFormFieldControl. * @docs-private */ - onContainerClick() { + onContainerClick(event: MouseEvent) { + const target = _getEventTarget(event) as HTMLElement | null; + + // Since the overlay is inside the form field, this handler can fire for interactions + // with the container. Note that while it's redundant to select both for the popover + // and select panel, we need to do it because it tests the clicks can occur after + // the panel was detached from the popover. + if ( + target && + (target.tagName === 'MAT-OPTION' || + target.classList.contains('cdk-overlay-backdrop') || + target.closest('.mat-mdc-select-panel')) + ) { + return; + } + this.focus(); this.open(); } diff --git a/src/material/slide-toggle/slide-toggle.scss b/src/material/slide-toggle/slide-toggle.scss index babf986b0f8d..dfc10d88bc9f 100644 --- a/src/material/slide-toggle/slide-toggle.scss +++ b/src/material/slide-toggle/slide-toggle.scss @@ -33,6 +33,11 @@ $fallbacks: m3-slide-toggle.get-tokens(); } } +// Ensure no label element (with a click handler) present to ensure hidden from screen readers. +label:empty { + display: none; +} + .mdc-switch__track { overflow: hidden; position: relative; @@ -66,9 +71,13 @@ $fallbacks: m3-slide-toggle.get-tokens(); .mdc-switch--disabled & { border-width: token-utils.slot( - slide-toggle-disabled-unselected-track-outline-width, $fallbacks); + slide-toggle-disabled-unselected-track-outline-width, + $fallbacks + ); border-color: token-utils.slot( - slide-toggle-disabled-unselected-track-outline-color, $fallbacks); + slide-toggle-disabled-unselected-track-outline-color, + $fallbacks + ); } } @@ -223,7 +232,9 @@ $fallbacks: m3-slide-toggle.get-tokens(); &:has(.mdc-switch__icons) { margin: token-utils.slot( - slide-toggle-unselected-with-icon-handle-horizontal-margin, $fallbacks); + slide-toggle-unselected-with-icon-handle-horizontal-margin, + $fallbacks + ); } } @@ -234,7 +245,9 @@ $fallbacks: m3-slide-toggle.get-tokens(); &:has(.mdc-switch__icons) { margin: token-utils.slot( - slide-toggle-selected-with-icon-handle-horizontal-margin, $fallbacks); + slide-toggle-selected-with-icon-handle-horizontal-margin, + $fallbacks + ); } } @@ -275,7 +288,8 @@ $fallbacks: m3-slide-toggle.get-tokens(); left: 0; position: absolute; top: 0; - transition: background-color 75ms 0ms cubic-bezier(0.4, 0, 0.2, 1), + transition: + background-color 75ms 0ms cubic-bezier(0.4, 0, 0.2, 1), border-color 75ms 0ms cubic-bezier(0.4, 0, 0.2, 1); z-index: -1; diff --git a/src/material/slide-toggle/slide-toggle.spec.ts b/src/material/slide-toggle/slide-toggle.spec.ts index 6b6616830b32..ca91e65bef28 100644 --- a/src/material/slide-toggle/slide-toggle.spec.ts +++ b/src/material/slide-toggle/slide-toggle.spec.ts @@ -654,6 +654,8 @@ describe('MatSlideToggle with forms', () => { it('should update checked state on click if control is checked initially', fakeAsync(() => { fixture = TestBed.createComponent(SlideToggleWithModel); + fixture.detectChanges(); + slideToggle = fixture.debugElement.query(By.directive(MatSlideToggle))!.componentInstance; labelElement = fixture.debugElement.query(By.css('label'))!.nativeElement; diff --git a/src/material/sort/sort.spec.ts b/src/material/sort/sort.spec.ts index 10181b65bf72..a5a3e3e94fa5 100644 --- a/src/material/sort/sort.spec.ts +++ b/src/material/sort/sort.spec.ts @@ -504,8 +504,8 @@ class SimpleMatSortApp { } } -class FakeDataSource extends DataSource { - connect(collectionViewer: CollectionViewer): Observable { +class FakeDataSource extends DataSource { + connect(collectionViewer: CollectionViewer): Observable { return collectionViewer.viewChange.pipe(map(() => [])); } disconnect() {} diff --git a/src/material/stepper/_m3-stepper.scss b/src/material/stepper/_m3-stepper.scss index 433352c141f1..3fa45be5b7d4 100644 --- a/src/material/stepper/_m3-stepper.scss +++ b/src/material/stepper/_m3-stepper.scss @@ -57,7 +57,7 @@ $prefix: (mat, stepper); // Tokens that can be configured through Angular Material's density theming API. @function get-density-tokens($scale) { - $scale: theming.clamp-density(scale, -4); + $scale: theming.clamp-density($scale, -4); $index: ($scale * -1) + 1; @return ( diff --git a/src/material/stepper/step-content.ts b/src/material/stepper/step-content.ts index 8328c0d10f5e..569f22e23fb3 100644 --- a/src/material/stepper/step-content.ts +++ b/src/material/stepper/step-content.ts @@ -14,8 +14,8 @@ import {Directive, TemplateRef, inject} from '@angular/core'; @Directive({ selector: 'ng-template[matStepContent]', }) -export class MatStepContent { - _template = inject>(TemplateRef); +export class MatStepContent { + _template = inject>(TemplateRef); constructor(...args: unknown[]); constructor() {} diff --git a/src/material/stepper/step-header.scss b/src/material/stepper/step-header.scss index 346e8ea3f09a..9ea7bf14836d 100644 --- a/src/material/stepper/step-header.scss +++ b/src/material/stepper/step-header.scss @@ -16,7 +16,7 @@ $fallbacks: m3-stepper.get-tokens(); // Stepper headers have the focus indicator as a descendant, // because `::before` is used for other styling. - &:focus .mat-focus-indicator::before { + &:focus-visible .mat-focus-indicator::before { content: ''; } diff --git a/src/material/table/table-data-source.ts b/src/material/table/table-data-source.ts index 81c16d3acd14..72cb5c1729b0 100644 --- a/src/material/table/table-data-source.ts +++ b/src/material/table/table-data-source.ts @@ -40,7 +40,11 @@ const MAX_SAFE_INTEGER = 9007199254740991; * interactions. If your app needs to support more advanced use cases, consider implementing your * own `DataSource`. */ -export class MatTableDataSource extends DataSource { +export class MatTableDataSource< + // TODO: Remove `any` type below in a breaking change: + T extends object | any, + P extends MatPaginator = MatPaginator, +> extends DataSource { /** Stream that emits when a new data array is set on the data source. */ private readonly _data: BehaviorSubject; @@ -232,7 +236,8 @@ export class MatTableDataSource extend // Transform the filter by converting it to lowercase and removing whitespace. const transformedFilter = filter.trim().toLowerCase(); // Loops over the values in the array and returns true if any of them match the filter string - return Object.values(data as {[key: string]: any}).some(value => + // TODO: Remove `as object` cast when `T` stops extending `any`: + return Object.values(data as object).some(value => `${value}`.toLowerCase().includes(transformedFilter), ); }; diff --git a/src/material/table/table.scss b/src/material/table/table.scss index 5ec66248528a..010bb7a2b037 100644 --- a/src/material/table/table.scss +++ b/src/material/table/table.scss @@ -30,6 +30,12 @@ $fallbacks: m3-table.get-tokens(); background-color: token-utils.slot(table-background-color, $fallbacks); } +// These styles already come from a similar class in the CDK, +// but the `.mat-mdc-table` styles override them. +.mat-table-fixed-layout { + table-layout: fixed; +} + .mdc-data-table__cell { box-sizing: border-box; overflow: hidden; diff --git a/src/material/table/table.spec.ts b/src/material/table/table.spec.ts index ef9b41b31f17..6b03b81bfe38 100644 --- a/src/material/table/table.spec.ts +++ b/src/material/table/table.spec.ts @@ -16,9 +16,9 @@ describe('MatTable', () => { const data = fixture.componentInstance.dataSource!.data; expectTableToMatchContent(tableElement, [ ['Column A', 'Column B', 'Column C'], - [data[0].a, data[0].b, data[0].c], - [data[1].a, data[1].b, data[1].c], - [data[2].a, data[2].b, data[2].c], + [data[0].a, data[0].b, data[0].c] as string[], + [data[1].a, data[1].b, data[1].c] as string[], + [data[2].a, data[2].b, data[2].c] as string[], ['fourth_row'], ['Footer A', 'Footer B', 'Footer C'], ]); @@ -64,10 +64,10 @@ describe('MatTable', () => { const data = fixture.componentInstance.dataSource!.data; expectTableToMatchContent(tableElement, [ ['Column A', 'Column B', 'Column C'], - [data[0].a, data[0].b, data[0].c], - [data[1].a, data[1].b, data[1].c], - [data[2].a, data[2].b, data[2].c], - [data[3].a, data[3].b, data[3].c], + [data[0].a, data[0].b, data[0].c] as string[], + [data[1].a, data[1].b, data[1].c] as string[], + [data[2].a, data[2].b, data[2].c] as string[], + [data[3].a, data[3].b, data[3].c] as string[], ]); }); @@ -159,9 +159,9 @@ describe('MatTable', () => { const data = fixture.componentInstance.dataSource!.data; expectTableToMatchContent(tableElement, [ ['Column A', 'Column B', 'Column C'], - [data[0].a, data[0].b, data[0].c], - [data[1].a, data[1].b, data[1].c], - [data[2].a, data[2].b, data[2].c], + [data[0].a, data[0].b, data[0].c] as string[], + [data[1].a, data[1].b, data[1].c] as string[], + [data[2].a, data[2].b, data[2].c] as string[], ]); }); @@ -173,9 +173,9 @@ describe('MatTable', () => { const data = fixture.componentInstance.dataSource!.data; expectTableToMatchContent(tableElement, [ ['Column A', 'Column B', 'Column C'], - [data[0].a, data[0].b, data[0].c], - [data[1].a, data[1].b, data[1].c], - [data[2].a, data[2].b, data[2].c], + [data[0].a, data[0].b, data[0].c] as string[], + [data[1].a, data[1].b, data[1].c] as string[], + [data[2].a, data[2].b, data[2].c] as string[], ]); }); @@ -357,7 +357,7 @@ describe('MatTable', () => { ]); // Change the filter to a falsy value that might come in from the view. - dataSource.filter = 0 as any; + dataSource.filter = 0 as unknown as string; flushMicrotasks(); fixture.detectChanges(); expectTableToMatchContent(tableElement, [ @@ -604,7 +604,7 @@ describe('MatTable', () => { ['Footer A', 'Footer B', 'Footer C'], ]); - dataSource.data = {} as any; + dataSource.data = {} as TestData[]; fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expectTableToMatchContent(tableElement, [ @@ -1108,7 +1108,7 @@ function getActualTableContent(tableElement: Element): string[][] { return actualTableContent.map(row => row.map(cell => cell.textContent!.trim())); } -export function expectTableToMatchContent(tableElement: Element, expected: any[]) { +export function expectTableToMatchContent(tableElement: Element, expected: string[][]) { const missedExpectations: string[] = []; function checkCellContent(actualCell: string, expectedCell: string) { if (actualCell !== expectedCell) { @@ -1134,7 +1134,7 @@ export function expectTableToMatchContent(tableElement: Element, expected: any[] } row.forEach((actualCell, cellIndex) => { - const expectedCell = expectedRow ? expectedRow[cellIndex] : null; + const expectedCell = expectedRow[cellIndex]; checkCellContent(actualCell, expectedCell); }); }); diff --git a/src/material/table/table.ts b/src/material/table/table.ts index 45878e61d58d..77106e322782 100644 --- a/src/material/table/table.ts +++ b/src/material/table/table.ts @@ -70,7 +70,7 @@ export class MatRecycleRows {} styleUrl: 'table.css', host: { 'class': 'mat-mdc-table mdc-data-table__table', - '[class.mdc-table-fixed-layout]': 'fixedLayout', + '[class.mat-table-fixed-layout]': 'fixedLayout', }, providers: [ {provide: CdkTable, useExisting: MatTable}, diff --git a/src/material/timepicker/timepicker-input.ts b/src/material/timepicker/timepicker-input.ts index a6fbe28430b9..d06b164b549e 100644 --- a/src/material/timepicker/timepicker-input.ts +++ b/src/material/timepicker/timepicker-input.ts @@ -41,7 +41,7 @@ import {MAT_INPUT_VALUE_ACCESSOR} from '../input'; import {Subscription} from 'rxjs'; import {DOWN_ARROW, ESCAPE, hasModifierKey, UP_ARROW} from '@angular/cdk/keycodes'; import {validateAdapter} from './util'; -import {_getFocusedElementPierceShadowDom} from '@angular/cdk/platform'; +import {_getEventTarget, _getFocusedElementPierceShadowDom} from '@angular/cdk/platform'; /** * Input that can be used to enter time and connect to a `mat-timepicker`. @@ -88,7 +88,7 @@ export class MatTimepickerInput private _dateFormats = inject(MAT_DATE_FORMATS, {optional: true})!; private _formField = inject(MAT_FORM_FIELD, {optional: true}); - private _onChange: ((value: any) => void) | undefined; + private _onChange: ((value: unknown) => void) | undefined; private _onTouched: (() => void) | undefined; private _validatorOnChange: (() => void) | undefined; private _cleanupClick: () => void; @@ -97,6 +97,8 @@ export class MatTimepickerInput private _timepickerSubscription: OutputRefSubscription | undefined; private _validator: ValidatorFn; private _lastValueValid = true; + private _minValid = true; + private _maxValid = true; private _lastValidDate: D | null = null; /** Value of the `aria-activedescendant` attribute. */ @@ -173,8 +175,7 @@ export class MatTimepickerInput const renderer = inject(Renderer2); this._validator = this._getValidator(); - this._respondToValueChanges(); - this._respondToMinMaxChanges(); + this._updateFormsState(); this._registerTimepicker(); this._localeSubscription = this._dateAdapter.localeChanges.subscribe(() => { if (!this._hasFocus()) { @@ -195,7 +196,7 @@ export class MatTimepickerInput * Implemented as a part of `ControlValueAccessor`. * @docs-private */ - writeValue(value: any): void { + writeValue(value: unknown): void { // Note that we need to deserialize here, rather than depend on the value change effect, // because `getValidDateOrNull` will clobber the value if it's parseable, but not created by // the current adapter (see #30140). @@ -207,7 +208,7 @@ export class MatTimepickerInput * Implemented as a part of `ControlValueAccessor`. * @docs-private */ - registerOnChange(fn: (value: any) => void): void { + registerOnChange(fn: (value: unknown) => void): void { this._onChange = fn; } @@ -265,8 +266,15 @@ export class MatTimepickerInput } /** Handles clicks on the input or the containing form field. */ - private _handleClick = (): void => { - if (!this.disabled() && this.openOnClick()) { + private _handleClick = (event: MouseEvent): void => { + if (this.disabled() || !this.openOnClick()) { + return; + } + + const target = _getEventTarget(event) as Node | null; + const overlayHost = this.timepicker()._getOverlayHost(); + + if (!target || !overlayHost || !overlayHost.contains(target)) { this.timepicker().open(); } }; @@ -327,24 +335,37 @@ export class MatTimepickerInput } } - /** Sets up the code that watches for changes in the value and adjusts the input. */ - private _respondToValueChanges(): void { + /** Sets up the code that keeps the input state in sync with the forms module. */ + private _updateFormsState(): void { effect(() => { - const value = this._dateAdapter.deserialize(this.value()); - const wasValid = this._lastValueValid; - this._lastValueValid = this._isValid(value); + const { + _dateAdapter: adapter, + _lastValueValid: prevValueValid, + _minValid: prevMinValid, + _maxValid: prevMaxValid, + } = this; + const value = adapter.deserialize(this.value()); + const min = this.min(); + const max = this.max(); + const valueValid = (this._lastValueValid = this._isValid(value)); + this._minValid = !min || !value || !valueValid || adapter.compareTime(min, value) <= 0; + this._maxValid = !max || !value || !valueValid || adapter.compareTime(max, value) >= 0; + const stateChanged = + prevValueValid !== valueValid || + prevMinValid !== this._minValid || + prevMaxValid !== this._maxValid; // Reformat the value if it changes while the user isn't interacting. if (!this._hasFocus()) { this._formatValue(value); } - if (value && this._lastValueValid) { + if (value && valueValid) { this._lastValidDate = value; } // Trigger the validator if the state changed. - if (wasValid !== this._lastValueValid) { + if (stateChanged) { this._validatorOnChange?.(); } }); @@ -359,16 +380,6 @@ export class MatTimepickerInput }); } - /** Sets up the logic that adjusts the input if the min/max changes. */ - private _respondToMinMaxChanges(): void { - effect(() => { - // Read the min/max so the effect knows when to fire. - this.min(); - this.max(); - this._validatorOnChange?.(); - }); - } - /** * Assigns a value set by the user to the input's model. * @param selection Time selected by the user that should be assigned. @@ -434,24 +445,28 @@ export class MatTimepickerInput this._lastValueValid ? null : {'matTimepickerParse': {'text': this._elementRef.nativeElement.value}}, - control => { - const controlValue = this._dateAdapter.getValidDateOrNull( - this._dateAdapter.deserialize(control.value), - ); - const min = this.min(); - return !min || !controlValue || this._dateAdapter.compareTime(min, controlValue) <= 0 + control => + this._minValid ? null - : {'matTimepickerMin': {'min': min, 'actual': controlValue}}; - }, - control => { - const controlValue = this._dateAdapter.getValidDateOrNull( - this._dateAdapter.deserialize(control.value), - ); - const max = this.max(); - return !max || !controlValue || this._dateAdapter.compareTime(max, controlValue) >= 0 + : { + 'matTimepickerMin': { + 'min': this.min(), + 'actual': this._dateAdapter.getValidDateOrNull( + this._dateAdapter.deserialize(control.value), + ), + }, + }, + control => + this._maxValid ? null - : {'matTimepickerMax': {'max': max, 'actual': controlValue}}; - }, + : { + 'matTimepickerMax': { + 'max': this.max(), + 'actual': this._dateAdapter.getValidDateOrNull( + this._dateAdapter.deserialize(control.value), + ), + }, + }, ])!; } } diff --git a/src/material/timepicker/timepicker.spec.ts b/src/material/timepicker/timepicker.spec.ts index d340714006c3..22d973678b32 100644 --- a/src/material/timepicker/timepicker.spec.ts +++ b/src/material/timepicker/timepicker.spec.ts @@ -1225,6 +1225,20 @@ describe('MatTimepicker', () => { expectSameTime(eventValue, controlValue); subscription.unsubscribe(); }); + + it('should not emit toValueOnChanges on init', () => { + const fixture = TestBed.createComponent(TimepickerWithForms); + const spy = jasmine.createSpy('valueChanges'); + const subscription = fixture.componentInstance.control.valueChanges.subscribe(spy); + fixture.detectChanges(); + expect(spy).not.toHaveBeenCalled(); + + typeInElement(getInput(fixture), '1:37 PM'); + fixture.detectChanges(); + + expect(spy).toHaveBeenCalled(); + subscription.unsubscribe(); + }); }); describe('timepicker toggle', () => { diff --git a/src/material/timepicker/timepicker.ts b/src/material/timepicker/timepicker.ts index 042e0524a321..eee9a66f51f7 100644 --- a/src/material/timepicker/timepicker.ts +++ b/src/material/timepicker/timepicker.ts @@ -312,6 +312,10 @@ export class MatTimepicker implements OnDestroy, MatOptionParentComponent { this._overlayRef?.dispose(); } + _getOverlayHost() { + return this._overlayRef?.hostElement; + } + /** Selects a specific time value. */ protected _selectValue(option: MatOption) { this.close(); @@ -356,6 +360,7 @@ export class MatTimepicker implements OnDestroy, MatOptionParentComponent { .withFlexibleDimensions(false) .withPush(false) .withTransformOriginOn('.mat-timepicker-panel') + .withPopoverLocation('inline') .withPositions([ { originX: 'start', diff --git a/src/material/tooltip/tooltip.spec.ts b/src/material/tooltip/tooltip.spec.ts index 3509ff5fbd96..3c515043f191 100644 --- a/src/material/tooltip/tooltip.spec.ts +++ b/src/material/tooltip/tooltip.spec.ts @@ -1386,7 +1386,7 @@ describe('MatTooltip', () => { fixture.detectChanges(); const styles = fixture.nativeElement.querySelector('button').style; - expect(styles.touchAction || (styles as any).webkitUserDrag).toBe('none'); + expect(styles.touchAction || styles.webkitUserDrag).toBe('none'); }); it('should allow native touch interactions if touch gestures are turned off', () => { @@ -1395,7 +1395,7 @@ describe('MatTooltip', () => { fixture.detectChanges(); const styles = fixture.nativeElement.querySelector('button').style; - expect(styles.touchAction || (styles as any).webkitUserDrag).toBeFalsy(); + expect(styles.touchAction || styles.webkitUserDrag).toBeFalsy(); }); it('should allow text selection on inputs when gestures are set to auto', () => { @@ -1407,13 +1407,13 @@ describe('MatTooltip', () => { expect(inputStyle.userSelect).toBeFalsy(); expect(inputStyle.webkitUserSelect).toBeFalsy(); - expect((inputStyle as any).msUserSelect).toBeFalsy(); - expect((inputStyle as any).MozUserSelect).toBeFalsy(); + expect(inputStyle.msUserSelect).toBeFalsy(); + expect(inputStyle.MozUserSelect).toBeFalsy(); expect(textareaStyle.userSelect).toBeFalsy(); expect(textareaStyle.webkitUserSelect).toBeFalsy(); - expect((textareaStyle as any).msUserSelect).toBeFalsy(); - expect((textareaStyle as any).MozUserSelect).toBeFalsy(); + expect(textareaStyle.msUserSelect).toBeFalsy(); + expect(textareaStyle.MozUserSelect).toBeFalsy(); }); it('should disable text selection on inputs when gestures are set to on', () => { @@ -1425,14 +1425,14 @@ describe('MatTooltip', () => { const inputUserSelect = inputStyle.userSelect || inputStyle.webkitUserSelect || - (inputStyle as any).msUserSelect || - (inputStyle as any).MozUserSelect; + inputStyle.msUserSelect || + inputStyle.MozUserSelect; const textareaStyle = fixture.componentInstance.textarea.nativeElement.style; const textareaUserSelect = textareaStyle.userSelect || textareaStyle.webkitUserSelect || - (textareaStyle as any).msUserSelect || - (textareaStyle as any).MozUserSelect; + textareaStyle.msUserSelect || + textareaStyle.MozUserSelect; expect(inputUserSelect).toBe('none'); expect(textareaUserSelect).toBe('none'); @@ -1570,7 +1570,7 @@ describe('MatTooltip', () => { }) class BasicTooltipDemo { position: TooltipPosition = 'below'; - message: any = initialTooltipMessage; + message: string | number = initialTooltipMessage; showButton = true; showTooltipClass = false; tooltipDisabled = false; @@ -1683,7 +1683,7 @@ class TooltipOnDraggableElement { imports: [MatTooltip], }) class TooltipDemoWithoutPositionBinding { - message: any = initialTooltipMessage; + message: string = initialTooltipMessage; @ViewChild(MatTooltip) tooltip: MatTooltip; @ViewChild('button') button: ElementRef; } @@ -1705,7 +1705,7 @@ class TooltipDemoWithoutTooltipClassBinding { imports: [MatTooltip], }) class TooltipDemoWithTooltipClassBinding { - message: any = initialTooltipMessage; + message: string = initialTooltipMessage; @ViewChild(MatTooltip) tooltip: MatTooltip; @ViewChild('button') button: ElementRef; } diff --git a/src/material/tooltip/tooltip.ts b/src/material/tooltip/tooltip.ts index 7245a9bd7abf..7f15dfd63721 100644 --- a/src/material/tooltip/tooltip.ts +++ b/src/material/tooltip/tooltip.ts @@ -55,6 +55,15 @@ import {ComponentPortal} from '@angular/cdk/portal'; import {Observable, Subject} from 'rxjs'; import {_animationsDisabled} from '../core'; +declare global { + interface CSSStyleDeclaration { + msUserSelect: string; + MozUserSelect: string; + webkitUserDrag: string; + webkitTapHighlightColor: string; + } +} + /** Possible positions for a tooltip. */ export type TooltipPosition = 'left' | 'right' | 'above' | 'below' | 'before' | 'after'; @@ -194,7 +203,7 @@ export class MatTooltip implements OnDestroy, AfterViewInit { private _position: TooltipPosition = 'below'; private _positionAtOrigin: boolean = false; private _disabled: boolean = false; - private _tooltipClass: string | string[] | Set | {[key: string]: any}; + private _tooltipClass: string | string[] | Set | {[key: string]: unknown}; private _viewInitialized = false; private _pointerExitEventsInitialized = false; private readonly _tooltipComponent = TooltipComponent; @@ -310,7 +319,7 @@ export class MatTooltip implements OnDestroy, AfterViewInit { return this._message; } - set message(value: string | null | undefined) { + set message(value: string | number | null | undefined) { const oldMessage = this._message; // If the message is not a string (e.g. number), convert it to a string and trim it. @@ -336,7 +345,7 @@ export class MatTooltip implements OnDestroy, AfterViewInit { return this._tooltipClass; } - set tooltipClass(value: string | string[] | Set | {[key: string]: any}) { + set tooltipClass(value: string | string[] | Set | {[key: string]: unknown}) { this._tooltipClass = value; if (this._tooltipInstance) { this._setTooltipClass(this._tooltipClass); @@ -508,7 +517,8 @@ export class MatTooltip implements OnDestroy, AfterViewInit { .withTransformOriginOn(`.${this._cssClassPrefix}-tooltip`) .withFlexibleDimensions(false) .withViewportMargin(this._viewportMargin) - .withScrollableContainers(scrollableAncestors); + .withScrollableContainers(scrollableAncestors) + .withPopoverLocation('global'); strategy.positionChanges.pipe(takeUntil(this._destroyed)).subscribe(change => { this._updateCurrentPositionClass(change.connectionPair); @@ -699,7 +709,9 @@ export class MatTooltip implements OnDestroy, AfterViewInit { } /** Updates the tooltip class */ - private _setTooltipClass(tooltipClass: string | string[] | Set | {[key: string]: any}) { + private _setTooltipClass( + tooltipClass: string | string[] | Set | {[key: string]: unknown}, + ) { if (this._tooltipInstance) { this._tooltipInstance.tooltipClass = tooltipClass; this._tooltipInstance._markForCheck(); @@ -887,20 +899,20 @@ export class MatTooltip implements OnDestroy, AfterViewInit { // textareas, because it prevents the user from typing into them on iOS Safari. if (gestures === 'on' || (element.nodeName !== 'INPUT' && element.nodeName !== 'TEXTAREA')) { style.userSelect = - (style as any).msUserSelect = + style.msUserSelect = style.webkitUserSelect = - (style as any).MozUserSelect = + style.MozUserSelect = 'none'; } // If we have `auto` gestures and the element uses native HTML dragging, // we don't set `-webkit-user-drag` because it prevents the native behavior. if (gestures === 'on' || !element.draggable) { - (style as any).webkitUserDrag = 'none'; + style.webkitUserDrag = 'none'; } style.touchAction = 'none'; - (style as any).webkitTapHighlightColor = 'transparent'; + style.webkitTapHighlightColor = 'transparent'; } } @@ -961,7 +973,7 @@ export class TooltipComponent implements OnDestroy { message: string; /** Classes to be added to the tooltip. Supports the same syntax as `ngClass`. */ - tooltipClass: string | string[] | Set | {[key: string]: any}; + tooltipClass: string | string[] | Set | {[key: string]: unknown}; /** The timeout ID of any current timer set to show the tooltip */ private _showTimeoutId: ReturnType | undefined; diff --git a/src/material/tree/node.ts b/src/material/tree/node.ts index ef7c17a1d970..d88c18db27e1 100644 --- a/src/material/tree/node.ts +++ b/src/material/tree/node.ts @@ -31,7 +31,7 @@ import {NoopTreeKeyManager, TreeKeyManagerItem, TreeKeyManagerStrategy} from '@a function isNoopTreeKeyManager( keyManager: TreeKeyManagerStrategy, ): keyManager is NoopTreeKeyManager { - return !!(keyManager as any)._isNoopTreeKeyManager; + return !!(keyManager as NoopTreeKeyManager)._isNoopTreeKeyManager; } /** diff --git a/src/material/tree/tree-using-tree-control.spec.ts b/src/material/tree/tree-using-tree-control.spec.ts index b44b11f9f2b8..d34676c2bd6e 100644 --- a/src/material/tree/tree-using-tree-control.spec.ts +++ b/src/material/tree/tree-using-tree-control.spec.ts @@ -19,9 +19,12 @@ import { MatTreeNestedDataSource, } from './index'; +type NodeContent = string[]; +type TreeContent = NodeContent[]; + describe('MatTree', () => { /** Represents an indent for expectNestedTreeToMatch */ - const _ = {}; + const _ = ''; let treeElement: HTMLElement; let underlyingDataSource: FakeDataSource; @@ -754,11 +757,11 @@ function getNodes(treeElement: Element): HTMLElement[] { function expectFlatTreeToMatch( treeElement: Element, expectedPaddingIndent: number = 28, - ...expectedTree: any[] + ...expectedTree: TreeContent ) { const missedExpectations: string[] = []; - function checkNode(node: Element, expectedNode: any[]) { + function checkNode(node: Element, expectedNode: NodeContent) { const actualTextContent = node.textContent!.trim(); const expectedTextContent = expectedNode[expectedNode.length - 1]; if (actualTextContent !== expectedTextContent) { @@ -768,7 +771,7 @@ function expectFlatTreeToMatch( } } - function checkLevel(node: Element, expectedNode: any[]) { + function checkLevel(node: Element, expectedNode: NodeContent) { const rawLevel = (node as HTMLElement).style.paddingLeft; // Some browsers return 0, while others return 0px. @@ -788,7 +791,7 @@ function expectFlatTreeToMatch( } getNodes(treeElement).forEach((node, index) => { - const expected = expectedTree ? expectedTree[index] : null; + const expected = expectedTree[index]; checkLevel(node, expected); checkNode(node, expected); @@ -799,9 +802,9 @@ function expectFlatTreeToMatch( } } -function expectNestedTreeToMatch(treeElement: Element, ...expectedTree: any[]) { +function expectNestedTreeToMatch(treeElement: Element, ...expectedTree: TreeContent) { const missedExpectations: string[] = []; - function checkNodeContent(node: Element, expectedNode: any[]) { + function checkNodeContent(node: Element, expectedNode: NodeContent) { const expectedTextContent = expectedNode[expectedNode.length - 1]; const actualTextContent = node.childNodes.item(0).textContent!.trim(); if (actualTextContent !== expectedTextContent) { @@ -811,7 +814,7 @@ function expectNestedTreeToMatch(treeElement: Element, ...expectedTree: any[]) { } } - function checkNodeDescendants(node: Element, expectedNode: any[], currentIndex: number) { + function checkNodeDescendants(node: Element, expectedNode: NodeContent, currentIndex: number) { let expectedDescendant = 0; for (let i = currentIndex + 1; i < expectedTree.length; ++i) { @@ -831,7 +834,7 @@ function expectNestedTreeToMatch(treeElement: Element, ...expectedTree: any[]) { } getNodes(treeElement).forEach((node, index) => { - const expected = expectedTree ? expectedTree[index] : null; + const expected = expectedTree[index]; checkNodeDescendants(node, expected, index); checkNodeContent(node, expected); diff --git a/src/material/tree/tree.spec.ts b/src/material/tree/tree.spec.ts index b85f68b84543..129f679aedb1 100644 --- a/src/material/tree/tree.spec.ts +++ b/src/material/tree/tree.spec.ts @@ -12,9 +12,12 @@ import {BehaviorSubject, Observable} from 'rxjs'; import {map} from 'rxjs/operators'; import {MatTree, MatTreeModule, MatTreeNestedDataSource} from './index'; +type NodeContent = string[]; +type TreeContent = NodeContent[]; + describe('MatTree', () => { /** Represents an indent for expectNestedTreeToMatch */ - const _ = {}; + const _ = ''; let treeElement: HTMLElement; let underlyingDataSource: FakeDataSource; @@ -756,11 +759,11 @@ function getNodes(treeElement: Element): HTMLElement[] { function expectFlatTreeToMatch( treeElement: Element, expectedPaddingIndent: number = 28, - ...expectedTree: any[] + ...expectedTree: TreeContent ) { const missedExpectations: string[] = []; - function checkNode(node: Element, expectedNode: any[]) { + function checkNode(node: Element, expectedNode: NodeContent) { const actualTextContent = node.textContent!.trim(); const expectedTextContent = expectedNode[expectedNode.length - 1]; if (actualTextContent !== expectedTextContent) { @@ -770,7 +773,7 @@ function expectFlatTreeToMatch( } } - function checkLevel(node: Element, expectedNode: any[]) { + function checkLevel(node: Element, expectedNode: NodeContent) { const rawLevel = (node as HTMLElement).style.paddingLeft; // Some browsers return 0, while others return 0px. @@ -790,7 +793,7 @@ function expectFlatTreeToMatch( } getNodes(treeElement).forEach((node, index) => { - const expected = expectedTree ? expectedTree[index] : null; + const expected = expectedTree[index]; checkLevel(node, expected); checkNode(node, expected); @@ -801,9 +804,9 @@ function expectFlatTreeToMatch( } } -function expectNestedTreeToMatch(treeElement: Element, ...expectedTree: any[]) { +function expectNestedTreeToMatch(treeElement: Element, ...expectedTree: TreeContent) { const missedExpectations: string[] = []; - function checkNodeContent(node: Element, expectedNode: any[]) { + function checkNodeContent(node: Element, expectedNode: NodeContent) { const expectedTextContent = expectedNode[expectedNode.length - 1]; const actualTextContent = node.childNodes.item(0).textContent!.trim(); if (actualTextContent !== expectedTextContent) { @@ -813,7 +816,7 @@ function expectNestedTreeToMatch(treeElement: Element, ...expectedTree: any[]) { } } - function checkNodeDescendants(node: Element, expectedNode: any[], currentIndex: number) { + function checkNodeDescendants(node: Element, expectedNode: NodeContent, currentIndex: number) { let expectedDescendant = 0; for (let i = currentIndex + 1; i < expectedTree.length; ++i) { @@ -833,7 +836,7 @@ function expectNestedTreeToMatch(treeElement: Element, ...expectedTree: any[]) { } getNodes(treeElement).forEach((node, index) => { - const expected = expectedTree ? expectedTree[index] : null; + const expected = expectedTree[index]; checkNodeDescendants(node, expected, index); checkNodeContent(node, expected); diff --git a/test/browser-providers.js b/test/browser-providers.js index 8d8a4c4ca86b..6917083699b8 100644 --- a/test/browser-providers.js +++ b/test/browser-providers.js @@ -4,7 +4,7 @@ * - `browserstack`: Launches the browser within BrowserStack */ const browserConfig = { - 'Safari16': {unitTest: {target: 'browserstack'}}, + 'Safari26': {unitTest: {target: 'browserstack'}}, }; /** Exports all available custom Karma browsers. */ diff --git a/test/karma-browsers.json b/test/karma-browsers.json index b46b1a4b9883..3480a4f036b4 100644 --- a/test/karma-browsers.json +++ b/test/karma-browsers.json @@ -1,9 +1,9 @@ { - "BROWSERSTACK_SAFARI16": { + "BROWSERSTACK_SAFARI26": { "base": "BrowserStack", "browser": "Safari", - "browser_version": "16.0", + "browser_version": "26.0", "os": "OS X", - "os_version": "Ventura" + "os_version": "Tahoe" } } diff --git a/tools/adev-api-extraction/BUILD.bazel b/tools/adev-api-extraction/BUILD.bazel index b4058c2a0227..0af88f8e17a7 100644 --- a/tools/adev-api-extraction/BUILD.bazel +++ b/tools/adev-api-extraction/BUILD.bazel @@ -1,6 +1,6 @@ load("@aspect_rules_js//js:defs.bzl", "js_binary") -load("//tools:defaults.bzl", "ts_project") load("@aspect_rules_ts//ts:defs.bzl", "ts_config") +load("//tools:defaults.bzl", "ts_project") package(default_visibility = ["//visibility:public"]) diff --git a/tools/adev-api-extraction/extract_api_to_json.bzl b/tools/adev-api-extraction/extract_api_to_json.bzl index b8ca2439b401..dd4d6d3e21e3 100644 --- a/tools/adev-api-extraction/extract_api_to_json.bzl +++ b/tools/adev-api-extraction/extract_api_to_json.bzl @@ -1,3 +1,5 @@ +load("@aspect_rules_js//js:providers.bzl", "JsInfo") + def _extract_api_to_json(ctx): """Implementation of the extract_api_to_json rule""" @@ -35,11 +37,43 @@ def _extract_api_to_json(ctx): # specifying them # https://github.com/bazelbuild/rules_nodejs/blob/5.x/internal/linker/link_node_modules.bzl#L236 path_map = {} - for target, path in ctx.attr.import_map.items(): + import_map_files = [] + for path, target in ctx.attr.import_map.items(): files = target.files.to_list() - if len(files) != 1: - fail("Expected a single file in import_map target %s" % target.label) - path_map[path] = files[0].path + + # Include transitive declarations if available in JsInfo + if JsInfo in target: + files.extend(target[JsInfo].transitive_types.to_list()) + + import_map_files.extend(files) + if len(files) == 1: + path_map[path] = files[0].path + else: + found_path = None + for f in files: + if f.path.endswith("/node_modules/" + path): + found_path = f.path + break + + # Handle @angular package subentries + if path.startswith("@angular/"): + parts = path.split("/") + if len(parts) > 2: + pkg_name = "/".join(parts[:2]) + if f.path.endswith("/node_modules/" + pkg_name): + subentry = parts[-1] + found_path = f.path + "/types/" + subentry + ".d.ts" + break + + if not found_path: + candidates = [f for f in files if f.path.endswith("/index.d.ts")] + sorted_candidates = sorted(candidates, key = lambda f: len(f.path)) + found_path = sorted_candidates[0].path + + if found_path: + path_map[path] = found_path + else: + fail("Expected a single file in import_map target %s, but found %s. Could not determine entry point. Files: %s" % (target.label, len(files), [f.path for f in files])) args.add(json.encode(path_map)) # Pass the set of (optional) extra entries @@ -48,7 +82,7 @@ def _extract_api_to_json(ctx): # Define an action that runs the nodejs_binary executable. This is # the main thing that this rule does. ctx.actions.run( - inputs = depset(ctx.files.srcs + ctx.files.extra_entries), + inputs = depset(ctx.files.srcs + ctx.files.extra_entries + import_map_files), executable = ctx.executable._extract_api_to_json, outputs = [json_output], arguments = [args], @@ -86,7 +120,7 @@ extract_api_to_json = rule( "private_modules": attr.string_list( doc = """List of private modules that should not be included in the API symbol linking""", ), - "import_map": attr.label_keyed_string_dict( + "import_map": attr.string_keyed_label_dict( doc = """Map of import path to the index.ts file for that import""", allow_files = True, ), diff --git a/tools/bazel/ng_package_interop.bzl b/tools/bazel/ng_package_interop.bzl index c44572e9d071..e66b2e46a195 100644 --- a/tools/bazel/ng_package_interop.bzl +++ b/tools/bazel/ng_package_interop.bzl @@ -1,5 +1,5 @@ -load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") load("@aspect_rules_js//js:libs.bzl", "js_lib_helpers") +load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") def _ng_package_interop_impl(ctx): # forward all npm_package_store_infos diff --git a/tools/defaults.bzl b/tools/defaults.bzl index 059379e5401b..a2c628790a7c 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -14,6 +14,7 @@ load("@rules_pkg//:pkg.bzl", "pkg_tar") load("@rules_sass//src:index.bzl", _sass_binary = "sass_binary", _sass_library = "sass_library") load("//:packages.bzl", "NO_STAMP_NPM_PACKAGE_SUBSTITUTIONS", "NPM_PACKAGE_SUBSTITUTIONS") load("//:pkg-externals.bzl", "PKG_EXTERNALS") +load("//tools/adev-api-extraction:extract_api_to_json.bzl", _extract_api_to_json = "extract_api_to_json") load("//tools/bazel:ng_package_interop.bzl", "ng_package_interop") load("//tools/bazel:web_test_suite.bzl", _ng_web_test_suite = "ng_web_test_suite") load("//tools/extract-tokens:index.bzl", _extract_tokens = "extract_tokens") @@ -78,6 +79,7 @@ def ng_package( }), visibility = visibility, rollup_runtime_deps = [ + "//:node_modules/@babel/core", "//:node_modules/@rollup/plugin-commonjs", "//:node_modules/@rollup/plugin-node-resolve", "//:node_modules/magic-string", @@ -246,3 +248,14 @@ def protractor_web_test_suite(name, deps, **kwargs): ], **kwargs ) + +def extract_api_to_json(**kwargs): + _extract_api_to_json( + import_map = { + "@angular/core": "//:node_modules/@angular/core", + "@angular/core/*": "//:node_modules/@angular/core", + "@angular/cdk/bidi": "//src/cdk/bidi", + "@angular/aria/private": "//src/aria/private", + }, + **kwargs + ) diff --git a/tools/dgeni/common/dgeni-definitions.ts b/tools/dgeni/common/dgeni-definitions.ts index 0da3771dac50..7be9839e9fe7 100644 --- a/tools/dgeni/common/dgeni-definitions.ts +++ b/tools/dgeni/common/dgeni-definitions.ts @@ -51,15 +51,11 @@ export interface CategorizedPropertyMemberDoc extends PropertyMemberDoc, Depreca /** Extended Dgeni method-member document that simplifies logic for the Dgeni template. */ export interface CategorizedMethodMemberDoc - extends NormalizedFunctionParameters, - MethodMemberDoc, - DeprecationInfo {} + extends NormalizedFunctionParameters, MethodMemberDoc, DeprecationInfo {} /** Extended Dgeni function export document that simplifies logic for the Dgeni template. */ export interface CategorizedFunctionExportDoc - extends NormalizedFunctionParameters, - FunctionExportDoc, - DeprecationInfo {} + extends NormalizedFunctionParameters, FunctionExportDoc, DeprecationInfo {} /** Extended Dgeni const export document that simplifies logic for the Dgeni template. */ export interface CategorizedConstExportDoc extends ConstExportDoc, DeprecationInfo {} diff --git a/tools/tslint-rules/memberNamingRule.ts b/tools/tslint-rules/memberNamingRule.ts index 043723b58e8f..8e6fb9f659cb 100644 --- a/tools/tslint-rules/memberNamingRule.ts +++ b/tools/tslint-rules/memberNamingRule.ts @@ -28,10 +28,13 @@ class Walker extends Lint.RuleWalker { const args = options.ruleArguments[0] || {}; - this._config = Object.keys(args).reduce((config, key) => { - config[key] = new RegExp(args[key]); - return config; - }, {} as {[key: string]: RegExp}); + this._config = Object.keys(args).reduce( + (config, key) => { + config[key] = new RegExp(args[key]); + return config; + }, + {} as {[key: string]: RegExp}, + ); } override visitClassDeclaration(node: ts.ClassDeclaration) { diff --git a/tslint.json b/tslint.json index aa514c5ed925..b8c41104390a 100644 --- a/tslint.json +++ b/tslint.json @@ -40,6 +40,7 @@ {"name": ["Object", "assign"], "message": "Use the spread operator instead."}, {"name": ["*", "asObservable"], "message": "Cast to Observable type instead."}, {"name": ["*", "removeChild"], "message": "Use `remove` instead instead."}, + {"name": ["CommonModule"], "message": "Import the necessary symbols directly instead."}, {"name": ["*", "compileComponents"], "message": "`compileComponents` is not necessary."}, { "name": ["isDevMode"],