Full Code of ionic-team/ionicons for AI

main 2a8e43aff06a cached
62 files
287.4 KB
79.3k tokens
41 symbols
1 requests
Download .txt
Showing preview only (305K chars total). Download the full file or copy to clipboard to get everything.
Repository: ionic-team/ionicons
Branch: main
Commit: 2a8e43aff06a
Files: 62
Total size: 287.4 KB

Directory structure:
gitextract_m0sxkfw_/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   ├── feature_request.yml
│   │   ├── icon_request.yml
│   │   └── incorrect_icon.yml
│   ├── ionic-issue-bot.yml
│   └── workflows/
│       ├── actions/
│       │   ├── build-core/
│       │   │   └── action.yml
│       │   ├── download-archive/
│       │   │   └── action.yml
│       │   ├── publish-npm/
│       │   │   └── action.yml
│       │   ├── test-e2e/
│       │   │   └── action.yml
│       │   ├── test-spec/
│       │   │   └── action.yml
│       │   ├── update-reference-screenshots/
│       │   │   └── action.yml
│       │   └── upload-archive/
│       │       └── action.yml
│       ├── dev-release.yml
│       ├── production-release.yml
│       ├── release-orchestrator.yml
│       ├── update-screenshots.yml
│       └── validation.yml
├── .gitignore
├── .prettierrc.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── jest.config.mjs
├── package.json
├── playwright.config.ts
├── readme.md
├── scripts/
│   ├── build.ts
│   ├── cheatsheet-template.html
│   ├── collection-copy.ts
│   ├── constants.ts
│   ├── plugins.ts
│   ├── readme.md
│   └── types.ts
├── src/
│   ├── components/
│   │   ├── icon/
│   │   │   ├── icon.css
│   │   │   ├── icon.tsx
│   │   │   ├── readme.md
│   │   │   ├── request.ts
│   │   │   ├── svg/
│   │   │   │   └── .gitignore
│   │   │   ├── test/
│   │   │   │   ├── icon.e2e.ts
│   │   │   │   ├── icon.spec.ts
│   │   │   │   ├── utils.spec.ts
│   │   │   │   └── validate.spec.ts
│   │   │   ├── utils.ts
│   │   │   └── validate.ts
│   │   └── test/
│   │       ├── csp/
│   │       │   ├── icon.e2e.ts
│   │       │   └── index.html
│   │       └── dynamic-type/
│   │           ├── icon.e2e.ts
│   │           └── index.html
│   ├── components.d.ts
│   ├── data.json
│   ├── index.html
│   ├── index.ts
│   ├── ionicons.web-types.json
│   └── utils/
│       └── test/
│           └── playwright/
│               ├── index.ts
│               ├── page/
│               │   └── utils/
│               │       ├── goto.ts
│               │       └── index.ts
│               ├── playwright-declarations.ts
│               └── playwright-page.ts
├── stencil.config.ts
├── tsconfig.json
└── tsconfig.spec.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: 🐛 Bug Report
description: Report a bug in the ion-icon component. Incorrect icons should use the "Incorrect Icon" template instead.
labels: ['triage']
title: 'bug: '
body:
  - type: textarea
    attributes:
      label: Current Behavior
      description: A clear description of what the bug is and how it manifests.
    validations:
      required: true
  - type: textarea
    attributes:
      label: Expected Behavior
      description: A clear description of what you expected to happen.
    validations:
      required: true
  - type: textarea
    attributes:
      label: Steps to Reproduce
      description: Please explain the steps required to duplicate this issue.
    validations:
      required: true
  - type: input
    attributes:
      label: Code Reproduction URL
      description: Please provide an application with the minimum code required to reproduce the issue. This is the best way to ensure this issue is triaged quickly. Issues without a code reproduction may be closed if the Ionic Team cannot reproduce the issue you are reporting.
      placeholder: https://github.com/...
  - type: textarea
    attributes:
      label: Additional Information
      description: List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to fix, Stack Overflow links, forum links, etc.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: 💡 Feature Request
description: Suggest a new feature for the ion-icon component. Icon requests should use the "Icon Request" template instead.
labels: ['triage']
title: 'feat: '
body:
  - type: textarea
    attributes:
      label: Describe Problem
      description: A clear and concise description of what the problem is. Ex. I am always frustrated when [...]
    validations:
      required: true
  - type: textarea
    attributes:
      label: Describe Preferred Solution
      description: A clear and concise description of what you want to happen.
  - type: textarea
    attributes:
      label: Describe Alternatives
      description: A clear and concise description of any alternative solutions or features you have considered.
  - type: textarea
    attributes:
      label: Additional Information
      description: Add any other context or screenshots about the feature request here.


================================================
FILE: .github/ISSUE_TEMPLATE/icon_request.yml
================================================
name: 🚀 Icon Request
description: Request a new icon
labels: ['triage']
title: 'icon request: '
body:
  - type: textarea
    attributes:
      label: Describe the Icon
      description: A clear and concise description of the icon you would like added.
    validations:
      required: true
  - type: textarea
    attributes:
      label: Links to Examples
      description: Add links to any examples of the icon in other libraries that you like.
  - type: textarea
    attributes:
      label: Additional Information
      description: Add any other context about the icon request here.


================================================
FILE: .github/ISSUE_TEMPLATE/incorrect_icon.yml
================================================
name: 😒 Incorrect Icon
description: Report an incorrect icon
labels: ['triage']
title: 'incorrect icon: '
body:
  - type: textarea
    attributes:
      label: Describe the Issue
      description: A clear description of what is wrong with the icon. Please include any relevant screenshots.
    validations:
      required: true
  - type: textarea
    attributes:
      label: Expected Behavior
      description: A clear description of what the icon should look like. Please include any relevant screenshots.
    validations:
      required: true


================================================
FILE: .github/ionic-issue-bot.yml
================================================
triage:
  label: triage
  dryRun: false

closeAndLock:
  labels:
    - label: 'ionitron: support'
      message: >
        Thanks for the issue! This issue appears to be a support request. We use this issue tracker exclusively for
        bug reports and feature requests. Please use our [forum](https://forum.ionicframework.com/) for help or
        questions about Ionicons.


        Thank you for using Ionicons!
    - label: 'ionitron: missing template'
      message: >
        Thanks for the issue! It appears that you have not filled out the provided issue template. We use this issue
        template in order to gather more information and further assist you. Please create a new issue and ensure the
        template is fully filled out.


        Thank you for using Ionicons!
  close: true
  lock: true
  dryRun: false

comment:
  labels:
    - label: 'help wanted'
      message: >
        This issue has been labeled as `help wanted`. This label is added to issues
        that we believe would be good for contributors.


        If you'd like to work on this issue, please comment here letting us know that
        you would like to submit a pull request for it. This helps us to keep track of
        the pull request and make sure there isn't duplicated effort.


        For a guide on how to create a pull request and test this project locally to see
        your changes, see our [contributing documentation](https://github.com/ionic-team/ionicons/blob/main/.github/CONTRIBUTING.md#creating-a-pull-request).


        Thank you!
    - label: 'ionitron: needs reproduction'
      message: >
        Thanks for the issue! This issue has been labeled as `needs reproduction`. This label is added to issues that
        need a code reproduction.


        Please reproduce this issue and provide a way for us to access it (GitHub repo, StackBlitz, etc). Without a
        reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed.


        If you have already provided a code snippet and are seeing this message, it is likely that the code snippet was
        not enough for our team to reproduce the issue.
    - label: 'community feedback wanted'
      message: >
        This issue has been labeled as `community feedback wanted`. This label is added to issues that we would like to hear from the community on before moving forward with any final decision on the feature request.


        If the requested feature is something you would find useful for your applications, please react to the original post with 👍 (`+1`). If you would like to provide an additional use case for the feature, please post a comment.


        The team will review this feedback and make a final decision. Any decision will be posted on this thread, but please note that we may ultimately decide not to pursue this feature.


        Thank you!
  dryRun: false

noReply:
  days: 14
  maxIssuesPerRun: 100
  label: 'needs: reply'
  responseLabel: triage
  exemptProjects: true
  exemptMilestones: true
  message: >
    Thanks for the issue! This issue is being closed due to the lack of a reply. If this is still
    an issue with the latest version of Ionicons, please create a new issue and ensure the
    template is fully filled out.


    Thank you for using Ionicons!
  close: true
  lock: true
  dryRun: false

noReproduction:
  days: 14
  maxIssuesPerRun: 100
  label: 'ionitron: needs reproduction'
  responseLabel: triage
  exemptProjects: true
  exemptMilestones: true
  message: >
    Thanks for the issue! This issue is being closed due to the lack of a code reproduction. If this is still
    an issue with the latest version of Ionicons, please create a new issue and ensure the
    template is fully filled out.


    Thank you for using Ionicons!
  close: true
  lock: true
  dryRun: false


================================================
FILE: .github/workflows/actions/build-core/action.yml
================================================
name: 'Build Ionicons'
description: 'Build Ionicons'
runs:
  using: 'composite'
  steps:
    - uses: actions/checkout@v4
      with:
        # Checkout the latest commit in this branch
        ref: ${{ github.event.pull_request.head.sha }}
    - uses: actions/setup-node@v4

    - name: Cache Node Modules
      uses: actions/cache@v4
      env:
        cache-name: node-modules
      with:
        path: ./node_modules
        key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./package-lock.json') }}-v1
    - name: Install Dependencies
      run: npm install
      shell: bash
    - name: Build
      run: npm run build
      shell: bash
    - uses: ./.github/workflows/actions/upload-archive
      with:
        name: ionicons-build
        output: IoniconsBuild.zip
        paths: dist components icons www
    - uses: ./.github/workflows/actions/upload-archive
      with:
        name: ionicons-src
        output: IoniconsSrc.zip
        paths: src


================================================
FILE: .github/workflows/actions/download-archive/action.yml
================================================
name: 'Archive Download'
description: 'Downloads and decompresses an archive from a previous job'
inputs:
  path:
    description: 'Input archive name'
  filename:
    description: 'Input file name'
  name:
    description: 'Archive name'
runs:
  using: 'composite'
  steps:
    - uses: actions/download-artifact@v4
      with:
        name: ${{ inputs.name }}
        path: ${{ inputs.path }}
    - name: Exract Archive
      run: unzip -q -o ${{ inputs.path }}/${{ inputs.filename }}
      shell: bash


================================================
FILE: .github/workflows/actions/publish-npm/action.yml
================================================
name: 'Release'
description: 'Releases a package'
inputs:
  version:
    description: 'The type of version to release.'
  tag:
    description: 'The tag to publish to on NPM.'
  working-directory:
    description: 'The directory of the package.'
  folder:
    default: './'
    description: 'A folder containing a package.json file.'
  createRelease:
    description: 'Create a release on GitHub.'
    default: 'false'
  ghToken:
    description: 'The GitHub authentication token required to create a release.'

runs:
  using: 'composite'
  steps:
    - uses: actions/setup-node@v4
      with:
        node-version: 22.x
    - name: Install latest npm
      run: npm install -g npm@latest
      shell: bash
    - name: Install Dependencies
      run: npm ci
      shell: bash
      working-directory: ${{ inputs.working-directory }}
    - name: Set Git User
      run: |
        git config user.name ionitron
        git config user.email hi@ionicframework.com
      shell: bash
    - name: Update Version
      id: update_version
      run: |
        npm version ${{ inputs.version }}
        echo "VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
      shell: bash
      working-directory: ${{ inputs.working-directory }}
    - name: Run Build
      run: npm run build
      shell: bash
      working-directory: ${{ inputs.working-directory }}
    - name: Publish to NPM
      run: npm publish ${{ inputs.folder }} --tag ${{ inputs.tag }} --provenance
      shell: bash
      working-directory: ${{ inputs.working-directory }}

    - name: Create Release
      if: ${{ inputs.createRelease == 'true' }}
      run: |
        git remote set-url origin https://${GH_TOKEN}:x-oauth-basic@github.com/ionic-team/ionicons.git
        git remote -v
        git push origin main --tags
        gh release create "v$VERSION" --title "v$VERSION" --generate-notes
      shell: bash
      env:
        GH_TOKEN: ${{ inputs.ghToken }}
        VERSION: ${{ env.VERSION }}


================================================
FILE: .github/workflows/actions/test-e2e/action.yml
================================================
name: 'Test E2E'
description: 'Test E2E'
inputs:
  shard:
    description: 'Playwright Test Shard (ex: 2)'
  totalShards:
    description: 'Playwright total number of test shards (ex: 4)'
  update:
    description: 'Whether or not to update the reference snapshots'
runs:
  using: 'composite'
  steps:
    - uses: actions/setup-node@v4

    - name: Cache Node Modules
      uses: actions/cache@v4
      env:
        cache-name: node-modules
      with:
        path: ./node_modules
        key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./package-lock.json') }}-v1
    - uses: ./.github/workflows/actions/download-archive
      with:
        name: ionicons-build
        path: .
        filename: IoniconsBuild.zip
    - uses: ./.github/workflows/actions/download-archive
      with:
        name: ionicons-src
        path: .
        filename: IoniconsSrc.zip
    - name: Install Playwright Dependencies
      run: npx playwright install && npx playwright install-deps
      shell: bash
    - name: Test
      if: inputs.update != 'true'
      run: npx playwright test --shard=${{ inputs.shard }}/${{ inputs.totalShards }}
      shell: bash
    - name: Test and Update
      id: test-and-update
      if: inputs.update == 'true'
      # Keep track of the files that were
      # changed so they can be correctly restored
      # in the combine step.
      # To do this, we move only the changed files
      # to a separate directory, while preserving the
      # directory structure of the source.
      # When, we create and archive of these results
      # so that the combine step can simply
      # unzip and move the changed files into place.
      # We have extra logic added so that job runners
      # that do not have any new screenshots do not create
      # an unnecessary .zip.
      run: |
        npx playwright test --shard=${{ inputs.shard }}/${{ inputs.totalShards }} --update-snapshots
        git add src/\*.png --force
        mkdir updated-screenshots
        rsync -R --progress $(git diff --name-only --cached) updated-screenshots
        if [ "$(ls -A updated-screenshots)" ]; then
          echo "hasUpdatedScreenshots=$(echo 'true')" >> $GITHUB_OUTPUT
          cd updated-screenshots
          ls
          zip -q -r ../UpdatedScreenshots-${{ inputs.shard }}-${{ inputs.totalShards }}.zip ./
        fi
      shell: bash
    - name: Archive Updated Screenshots
      if: inputs.update == 'true' && steps.test-and-update.outputs.hasUpdatedScreenshots == 'true'
      uses: actions/upload-artifact@v4
      with:
        name: updated-screenshots-${{ inputs.shard }}-${{ inputs.totalShards }}
        path: UpdatedScreenshots-${{ inputs.shard }}-${{ inputs.totalShards }}.zip
    - name: Archive Test Results
      # The always() ensures that this step
      # runs even if the previous step fails.
      # We want the test results to be archived
      # even if the test fails in the previous
      # step, otherwise there would be no way
      # to debug these tests.
      if: always()
      uses: ./.github/workflows/actions/upload-archive
      with:
        name: test-results-${{ inputs.shard }}-${{ inputs.totalShards }}
        output: TestResults-${{ inputs.shard }}-${{ inputs.totalShards }}.zip
        paths: playwright-report


================================================
FILE: .github/workflows/actions/test-spec/action.yml
================================================
name: 'Test Spec'
description: 'Test Spec'
runs:
  using: 'composite'
  steps:
    - uses: actions/setup-node@v4

    - name: Cache Node Modules
      uses: actions/cache@v4
      env:
        cache-name: node-modules
      with:
        path: ./node_modules
        key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./package-lock.json') }}-v1
    - uses: ./.github/workflows/actions/download-archive
      with:
        name: ionicons-build
        path: .
        filename: IoniconsBuild.zip
    - name: Test
      run: npm run test.spec -- --ci
      shell: bash


================================================
FILE: .github/workflows/actions/update-reference-screenshots/action.yml
================================================
name: 'Update Reference Screenshots'
description: 'Update Reference Screenshots'

on:
  workflow_dispatch:

runs:
  using: 'composite'
  steps:
    - uses: actions/setup-node@v4
    - uses: actions/download-artifact@v4
      with:
        path: ./artifacts
    - name: Extract Archives
      # This finds all .zip files in the ./artifacts
      # directory, including nested directories.
      # It then unzips every .zip to the root directory
      run: |
        find . -type f -name 'UpdatedScreenshots-*.zip' -exec unzip -q -o -d ../ {} \;
      shell: bash
      working-directory: ./artifacts
    - name: Push Screenshots
      # Configure user as Ionitron
      # and push only the changed .png snapshots
      # to the remote branch.
      # Screenshots are in .gitignore
      # to prevent local screenshots from getting
      # pushed to Git. As a result, we need --force
      # here so that CI generated screenshots can
      # get added to git. Screenshot ground truths
      # should only be added via this CI process.
      run: |
        git config user.name ionitron
        git config user.email hi@ionicframework.com
        git add src/\*.png --force
        git commit -m "chore(): add updated snapshots"
        git push
      shell: bash


================================================
FILE: .github/workflows/actions/upload-archive/action.yml
================================================
name: 'Archive Upload'
description: 'Compresses and uploads an archive to be reused across jobs'
inputs:
  paths:
    description: 'Paths to files or directories to archive'
  output:
    description: 'Output file name'
  name:
    description: 'Archive name'
runs:
  using: 'composite'
  steps:
    - name: Create Archive
      run: zip -q -r ${{ inputs.output }} ${{ inputs.paths }}
      shell: bash
    - uses: actions/upload-artifact@v4
      with:
        name: ${{ inputs.name }}
        path: ${{ inputs.output }}


================================================
FILE: .github/workflows/dev-release.yml
================================================
name: 'Dev Release'

on:
  workflow_call:

jobs:
  create-dev-hash:
    runs-on: ubuntu-latest
    outputs:
      dev-hash: ${{ steps.create-dev-hash.outputs.DEV_HASH }}
    steps:
      - uses: actions/checkout@v4
      - name: Install Dependencies
        run: npm ci --no-package-lock
        shell: bash
      - id: create-dev-hash
        name: Create Dev Hash
        run: |
          echo "DEV_HASH=$(node ./scripts/bump-version.js)-dev.1$(date +%s).1$(git log -1 --format=%H | cut -c 1-7)" >> $GITHUB_OUTPUT
        shell: bash

  release-ionicons:
    runs-on: ubuntu-latest
    needs: [create-dev-hash]
    permissions:
      id-token: write
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Publish to NPM
        uses: ./.github/workflows/actions/publish-npm
        with:
          tag: dev
          version: ${{ needs.create-dev-hash.outputs.dev-hash }}
          working-directory: './'
          createRelease: 'false'

  get-build:
    name: Get your dev build!
    runs-on: ubuntu-latest
    needs: [create-dev-hash, release-ionicons]
    steps:
      - run: echo ${{ needs.create-dev-hash.outputs.dev-hash }}


================================================
FILE: .github/workflows/production-release.yml
================================================
name: 'Production Release'

on:
  workflow_call:
    inputs:
      version:
        required: false
        type: string
        description: npm version (major, minor, or patch)

jobs:
  release-ionicons:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.IONITRON_TOKEN }}
      - name: Publish to NPM
        uses: ./.github/workflows/actions/publish-npm
        with:
          tag: latest
          version: ${{ inputs.version }}
          working-directory: './'
          createRelease: true
          ghToken: ${{ secrets.IONITRON_TOKEN }}


================================================
FILE: .github/workflows/release-orchestrator.yml
================================================
name: 'Release Orchestrator'

on:
  workflow_dispatch:
    inputs:
      release-type:
        description: 'Release type'
        required: true
        type: choice
        options:
          - dev
          - production
      version:
        description: 'Version for production releases'
        required: false
        type: choice
        options:
          - patch
          - minor
          - major

permissions:
  id-token: write
  contents: read

jobs:
  run-dev:
    if: ${{ inputs.release-type == 'dev' }}
    uses: ./.github/workflows/dev-release.yml
    secrets: inherit

  run-production:
    if: ${{ inputs.release-type == 'production' }}
    uses: ./.github/workflows/production-release.yml
    secrets: inherit
    with:
      version: ${{ inputs.version }}


================================================
FILE: .github/workflows/update-screenshots.yml
================================================
name: 'Update Reference Screenshots'

on:
  workflow_dispatch:

jobs:
  build-core:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/workflows/actions/build-core

  test-e2e:
    strategy:
      # This ensures that all screenshot shard
      # failures are reported so the dev can
      # review everything at once.
      fail-fast: false
      matrix:
        # Divide the tests into n buckets
        # and run those buckets in parallel.
        # To increase the number of shards,
        # add new items to the shard array
        # and change the value of totalShards
        # to be the length of the shard array.
        shard: [1, 2, 3]
        totalShards: [3]
    needs: [build-core]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/workflows/actions/test-e2e
        with:
          shard: ${{ matrix.shard }}
          totalShards: ${{ matrix.totalShards }}
          update: true

  update-reference-screenshots:
    runs-on: ubuntu-latest
    needs: [test-e2e]
    steps:
      - uses: actions/checkout@v4
        # Normally, we could just push with the
        # default GITHUB_TOKEN, but that will
        # not cause the build workflow
        # to re-run. We use Ionitron's
        # Personal Access Token instead
        # to allow for this build workflow
        # to run when the screenshots are pushed.
        with:
          token: ${{ secrets.IONITRON_TOKEN }}
      - uses: ./.github/workflows/actions/update-reference-screenshots


================================================
FILE: .github/workflows/validation.yml
================================================
name: 'Validation'

on:
  pull_request:
    branches: ['**']
  push:
    branches: ['main']

# When pushing a new commit we should
# cancel the previous test run to not
# consume more runners than we need to.
concurrency:
  group: ${{ github.ref }}
  cancel-in-progress: true

jobs:
  build-core:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          # Checkout the latest commit in this branch
          ref: ${{ github.event.pull_request.head.sha }}
      - uses: ./.github/workflows/actions/build-core

  test-spec:
    needs: [build-core]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/workflows/actions/test-spec

  test-e2e:
    strategy:
      # This ensures that all screenshot shard
      # failures are reported so the dev can
      # review everything at once.
      fail-fast: false
      matrix:
        # Divide the tests into n buckets
        # and run those buckets in parallel.
        # To increase the number of shards,
        # add new items to the shard array
        # and change the value of totalShards
        # to be the length of the shard array.
        shard: [1, 2, 3]
        totalShards: [3]
    needs: [build-core]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/workflows/actions/test-e2e
        with:
          shard: ${{ matrix.shard }}
          totalShards: ${{ matrix.totalShards }}

  # Screenshots are required to pass
  # in order for the branch to be merge
  # eligible. However, the screenshot tests
  # are run on n runners where n can change
  # over time. The verify-screenshots step allows
  # us to have a required status check for screenshot
  # results without having to manually add each
  # matrix run in the branch protection rules
  # Source: https://github.community/t/status-check-for-a-matrix-jobs/127354
  verify-e2e:
    if: ${{ always() }}
    needs: test-e2e
    runs-on: ubuntu-latest
    steps:
      - name: Check build matrix status
        if: ${{ needs.test-e2e.result != 'success' }}
        run: exit 1


================================================
FILE: .gitignore
================================================
*~
*.sw[mnpcod]
*.log
*.lock
*.tmp
*.tmp.*
log.txt
*.sublime-project
*.sublime-workspace
.idea/
.versions/
.vscode/
/components/
node_modules/
tmp/
dist/
icons/
.DS_Store
scripts/*.js
!scripts/install-loader.js

www/
/test-results/
/playwright-report/
/playwright/.cache/
/src/**/*-snapshots
*.tgz

================================================
FILE: .prettierrc.json
================================================
{
  "arrowParens": "always",
  "bracketSpacing": true,
  "jsxBracketSameLine": false,
  "jsxSingleQuote": false,
  "quoteProps": "consistent",
  "printWidth": 120,
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "all",
  "useTabs": false
}


================================================
FILE: CHANGELOG.md
================================================
# Change Log

Please see https://github.com/ionic-team/ionicons/releases

================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Code of Conduct

As contributors and maintainers of the Ionicons project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.

Communication through any of Ionic's channels (GitHub, Slack, Forum, IRC, mailing lists, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Ionicons project to do the same.

If any member of the community violates this code of conduct, the maintainers of the Ionicons project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate.

If you are subject to or witness unacceptable behavior, or have any other concerns, please email us at [hi@ionicframework.com](mailto:hi@ionicframework.com).


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Ionicons

Thank you for your interest in contributing to Ionicons! :tada:

This document outlines the guidelines and processes for contributing to this project.

## Table of Contents

- [Contributing to Ionicons](#contributing-to-ionicons)
  - [Table of Contents](#table-of-contents)
  - [Code of Conduct](#code-of-conduct)
  - [Getting Started](#getting-started)
    - [Prerequisites](#prerequisites)
    - [Environment Setup](#environment-setup)
  - [Development Workflow](#development-workflow)
    - [Branch Strategy](#branch-strategy)
    - [Component Modifications](#component-modifications)
    - [Testing Changes](#testing-changes)
    - [Code Style](#code-style)
    - [Building](#building)
  - [Submitting Issues](#submitting-issues)
  - [Submitting Pull Requests](#submitting-pull-requests)

## Code of Conduct

Please read our [Contributor Code of Conduct](./CODE_OF_CONDUCT.md) for information on our rules of conduct. By contributing to Ionicons, you agree to abide by its terms.

## Getting Started

### Prerequisites

- [Node.js](https://nodejs.org/) (LTS version recommended)
- [npm](https://www.npmjs.com/) (comes with Node.js)
- Git

### Environment Setup

1. We recommend using [nvm](https://github.com/nvm-sh/nvm) (Node Version Manager) to manage Node.js versions:
   - For macOS/Linux: `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash`
   - For Windows: Use [nvm-windows](https://github.com/coreybutler/nvm-windows)
   - Install and use the LTS version: `nvm install --lts && nvm use --lts`

   Alternatively, you can [download the installer](https://nodejs.org/) for the LTS version of Node.js directly.

2. Fork the repository on GitHub
3. Clone your fork locally:
   ```bash
   git clone https://github.com/YOUR-USERNAME/ionicons.git
   cd ionicons
   ```
4. Add the original repository as an upstream remote:
   ```bash
   git remote add upstream https://github.com/ionic-team/ionicons.git
   ```
5. Create a new branch from `main` for your change:
   ```bash
   git checkout -b your-feature-branch
   ```
6. Install dependencies:
   ```bash
   npm install
   ```
7. Run the initial build:
   ```bash
   npm run build
   ```
8. If desired, [modify the Icon Component](#component-modifications)
9. Or, modify and preview the site

## Development Workflow

### Branch Strategy

- Always create a new branch from `main` for your changes:
  ```bash
  git checkout main
  git pull upstream main
  git checkout -b your-feature-branch
  ```

### Component Modifications

If you're modifying the `ion-icon` component:

1. Navigate to `src/components/` directory and open the `icon` component to modify
2. Make your changes to the component code
3. Test your changes (see [Testing Changes](#testing-changes))

### Testing Changes

To preview component changes:

1. Run:
   ```bash
   npm start
   ```
   This will start a local version of the icon test with a test page
   
2. Modify the test page in `index.html` as needed to test your changes
3. If you are modifying icons, you can run `npm run build.files` to re-run the SVG optimization script to verify there are no changes after optimizing the SVG

### Code Style

- This project uses Prettier for code formatting
- Run `npm run prettier` to format your code before submitting

### Building

- Run `npm run build` to build the complete package
- Run `npm run build.files` to rebuild only the SVG icon files

## Submitting Issues

Please submit issues for:
- Bug reports
- Feature requests
- General questions about the project

When creating issues:

1. If you have a question about using Ionicons, please ask on the [Ionic Forum](http://forum.ionicframework.com/) or in the [Ionic Discord](https://ionic.link/discord).

2. It is required that you clearly describe the steps necessary to reproduce the issue you are running into. Although we would love to help our users as much as possible, diagnosing issues without clear reproduction steps is extremely time-consuming and simply not sustainable.

3. The issue list of this repository is exclusively for bug reports and feature requests. Non-conforming issues will be closed immediately.

4. Check if a similar issue already exists by searching through [existing issues](https://github.com/ionic-team/ionicons/issues?utf8=%E2%9C%93&q=is%3Aissue). You can search through existing issues to see if there is a similar one reported. Include closed issues as it may have been closed with a solution.

5. Use the provided issue templates and clearly describe:
   - Expected behavior
   - Actual behavior
   - Steps to reproduce (for bugs)
   - Browser/device information when relevant

6. [Create a new issue](https://github.com/ionic-team/ionicons/issues/new/choose) that thoroughly explains the problem.

## Submitting Pull Requests

1. Before submitting a Pull Request (PR), please:
   - Create an issue first to discuss the proposed changes
   - Comment on an existing issue mentioning you'd like to work on it
   - Look for issues labeled with [`help wanted`](https://github.com/ionic-team/ionicons/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) if you're new to the project

2. Creating the PR:
   - Update your fork to the latest upstream main
   - Make your changes in a new git branch
   - Follow the code style of the project
   - Include relevant tests
   - Make sure all tests pass: `npm test`
   - Update documentation if needed
   - [Create a new pull request](https://github.com/ionic-team/ionicons/compare) with the `main` branch as the base.

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015-present Ionic (http://ionic.io/)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: jest.config.mjs
================================================
import path from 'path';
import url from 'url';

import { createJestStencilPreset } from 'jest-stencil-runner';

const __dirname = path.dirname(url.fileURLToPath(import.meta.url));

export default createJestStencilPreset({
  rootDir: __dirname,  
  // Add any additional Jest configuration here
  collectCoverageFrom: [
    'src/**/*.{ts,tsx}',
    '!src/**/*.d.ts',
  ],
  testMatch: [
    '**/__tests__/**/*.(ts|tsx|js)',
    '**/*.(test|spec).(ts|tsx|js)'
  ]
});

================================================
FILE: package.json
================================================
{
  "name": "ionicons",
  "version": "8.0.13",
  "description": "Premium icons for Ionic.",
  "files": [
    "components/",
    "dist/",
    "icons/"
  ],
  "main": "./dist/index.cjs.js",
  "module": "./dist/index.js",
  "types": "dist/types/index.d.ts",
  "unpkg": "dist/ionicons/ionicons.esm.js",
  "jsdelivr": "dist/ionicons/ionicons.esm.js",
  "collection": "dist/collection/collection-manifest.json",
  "collection:main": "dist/collection/index.js",
  "exports": {
    ".": {
      "types": "./dist/types/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs.js"
    },
    "./loader": {
      "types": "./dist/loader/index.d.ts",
      "import": "./dist/loader/index.js",
      "require": "./dist/loader/index.cjs.js"
    },
    "./components": {
      "types": "./components/index.d.ts",
      "import": "./components/index.js"
    },
    "./components/ion-icon.js": {
      "types": "./components/ion-icon.d.ts",
      "import": "./components/ion-icon.js"
    },
    "./icons": {
      "types": "./icons/index.d.ts",
      "import": "./icons/index.mjs",
      "require": "./icons/index.js"
    },
    "./dist/ionicons.json": {
      "default": "./dist/ionicons.json"
    }
  },
  "scripts": {
    "build": "run-s clean build.* prettier",
    "build.files": "tsx scripts/build.ts",
    "build.component": "stencil build",
    "build.collection": "tsx scripts/collection-copy.ts",
    "clean": "rimraf dist components icons www",
    "prettier": "npm run prettier.base -- --write",
    "prettier.base": "prettier --cache \"./({bin,scripts,src,test}/**/*.{ts,tsx,js,jsx})|bin/stencil|.github/(**/)?*.(yml|yaml)|*.js\"",
    "prettier.dry-run": "npm run prettier.base -- --list-different",
    "start": "run-s build.files start.stencil",
    "start.stencil": "stencil build --dev --watch --serve",
    "test": "run-s test.spec",
    "test.spec": "jest",
    "test.e2e": "playwright test",
    "test.e2e.install": "playwright install && playwright install-deps"
  },
  "dependencies": {
    "@stencil/core": "^4.35.3"
  },
  "devDependencies": {
    "@playwright/test": "^1.53.2",
    "@types/fs-extra": "^11.0.4",
    "@types/jest": "^30.0.0",
    "@types/node": "^22.15.3",
    "@types/svgo": "^3.0.0",
    "fs-extra": "^11.3.0",
    "jest": "^30.0.4",
    "jest-cli": "^30.0.4",
    "jest-stencil-runner": "^0.0.8",
    "npm-run-all2": "^8.0.4",
    "prettier": "^3.6.2",
    "puppeteer": "^24.12.0",
    "rimraf": "^6.0.1",
    "semver": "^7.7.2",
    "serve": "^14.2.4",
    "svgo": "4.0.0",
    "tsx": "^4.20.3",
    "typescript": "^5.8.3"
  },
  "keywords": [
    "icon pack",
    "ionic",
    "icon",
    "svg",
    "mobile",
    "web component",
    "component",
    "custom element",
    "material design",
    "ios"
  ],
  "homepage": "http://ionicons.com/",
  "author": {
    "name": "Ben Sperry",
    "web": "https://twitter.com/benjsperry"
  },
  "contributors": [
    {
      "name": "Adam Bradley",
      "web": "http://twitter.com/adamdbradley"
    }
  ],
  "repository": {
    "type": "git",
    "url": "https://github.com/ionic-team/ionicons.git"
  },
  "bugs": {
    "url": "https://github.com/ionic-team/ionicons/issues"
  },
  "license": "MIT",
  "sideEffects": [
    "icons/imports/"
  ],
  "web-types": "dist/ionic.web-types.json"
}


================================================
FILE: playwright.config.ts
================================================
import type { PlaywrightTestConfig } from '@playwright/test';
import { devices, expect } from '@playwright/test';

const projects: PlaywrightTestConfig['projects'] = [
  {
    /**
     * This is really just desktop Firefox
     * but with a mobile viewport.
     */
    name: 'Mobile Firefox',
    use: {
      browserName: 'firefox',
      /**
       * This is the Pixel 5 configuration.
       * We can't use devices['Pixel 5']
       * because the "isMobile" option is
       * not supported on Firefox.
       */
      viewport: {
        width: 393,
        height: 727
      }
    },
  },
  {
    name: 'Mobile Chrome',
    use: {
      browserName: 'chromium',
      ...devices['Pixel 5']
    }
  },
  {
    name: 'Mobile Safari',
    use: {
      browserName: 'webkit',
      ...devices['iPhone 12']
    }
  }
];

/**
 * See https://playwright.dev/docs/test-configuration.
 */
const config: PlaywrightTestConfig = {
  testMatch: '*.e2e.ts',
  expect: {
    /**
     * Maximum time expect() should wait for the condition to be met.
     * For example in `await expect(locator).toHaveText();`
     */
    timeout: 5000,
    
    /**
     * Configure screenshot comparison settings
     * to be more tolerant of minor visual differences
     */
    toHaveScreenshot: {
      // Increase the threshold to allow for small font rendering differences
      // This sets the maximum allowed ratio of pixels that can be different
      maxDiffPixelRatio: 0.02, // Allow up to 2% of pixels to be different
      
      // Alternatively, you can use absolute pixel count
      // maxDiffPixels: 100, // Allow up to 100 pixels to be different
      
      // Add a threshold for per-pixel difference to handle anti-aliasing
      threshold: 0.2, // Default is 0.1
    }
  },
  /* Fail the build on CI if you accidentally left test.only in the source code. */
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  /* Opt out of parallel tests on CI. */
  workers: process.env.CI ? 1 : undefined,
  /* Reporter to use. See https://playwright.dev/docs/test-reporters */
  reporter: 'html',
  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
  use: {
    /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
    actionTimeout: 0,
    /* Base URL to use in actions like `await page.goto('/')`. */
    // baseURL: 'http://localhost:3000',

    /**
     * All failed tests should create
     * a trace file for easier debugging.
     *
     * See https://playwright.dev/docs/trace-viewer
     */
    trace: 'retain-on-failure',
    baseURL: 'http://localhost:3333',
  },

  /* Configure projects for major browsers */
  projects,
  webServer: {
    command: 'serve www -p 3333',
    port: 3333,
    reuseExistingServer: !process.env.CI
  }
};

export default config;

================================================
FILE: readme.md
================================================
# Ionicons

[Ionicons](http://ionicons.com/) is a completely open-source icon set with 1,300 icons crafted for web, iOS, Android, and desktop apps. Ionicons was built for [Ionic Framework](https://ionicframework.com/), so icons have both Material Design and iOS versions.

Note: All brand icons are trademarks of their respective owners. The use of these trademarks does not indicate endorsement of the trademark holder by Ionic, nor vice versa.

We intend for this icon pack to be used with [Ionic](http://ionicframework.com/), but it’s by no means limited to it. Use them wherever you see fit, personal or commercial. They are free to use and licensed under [MIT](http://opensource.org/licenses/MIT).


## Contributing

Thanks for your interest in contributing! Read up on our guidelines for
[contributing](https://github.com/ionic-team/ionicons/blob/main/CONTRIBUTING.md)
and then look through our issues with a [help wanted](https://github.com/ionic-team/ionicons/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
label.


## Using the Web Component

The Ionicons Web Component is an easy and performant way to use Ionicons in your app. The component will dynamically load an SVG for each icon, so your app is only requesting the icons that you need.

Also note that only visible icons are loaded, and icons that are "below the fold" and hidden from the user's view do not make fetch requests for the svg resource.

### Installation

If you're using [Ionic Framework](https://ionicframework.com/), Ionicons is packaged by default, so no installation is necessary. Want to use Ionicons without Ionic Framework? Place the following `<script>` near the end of your page, right before the closing `</body>` tag, to enable them.

```html
<script type="module" src="https://esm.sh/ionicons@latest/loader"></script>
<script nomodule src="https://esm.sh/ionicons@latest/loader"></script>
```

you can replace `latest` to pick any version of Ionicon, e.g.:

```html
<script type="module" src="https://esm.sh/ionicons@8.0.0/loader"></script>
<script nomodule src="https://esm.sh/ionicons@8.0.0/loader"></script>
```

### Basic usage

To use a built-in icon from the Ionicons package, populate the `name` attribute on the ion-icon component:

```html
<ion-icon name="heart"></ion-icon>
```

### Custom icons

To use a custom SVG, provide its url in the `src` attribute to request the external SVG file. The `src` attribute works the same as `<img src="...">` in that the url must be accessible from the webpage that's making a request for the image. Additionally, the external file can only be a valid svg and does not allow scripts or events within the svg element.

```html
<ion-icon src="/path/to/external/file.svg"></ion-icon>
```

#### Custom Asset Path

If you have a different set of icons you would like to load or if the Ionicon icons are hosted on a different page or path, you can set the asset url from which Ionicons pulls the icons via:

```ts
import { setAssetPath, addIcons } from 'ionicons';
import { add, logoIonic, save } from 'ionicons/icons';

// set root path for loading icons to "<root>/public/svg"
setAssetPath(`${window.location.origin}/public/svg/`);

// only load specific icons
addIcons({ add, logoIonic, save });
```

This allows the use of named icons like this:

```html
<!-- now pulls the svg from "<root>/public/svg/heart.svg" -->
<ion-icon name="heart"></ion-icon>
```

## Variants
Each app icon in Ionicons has a `filled`, `outline` and `sharp` variant. These different variants are provided to make your app feel native to a variety of platforms. The filled variant uses the default name without a suffix. Note: Logo icons do not have outline or sharp variants.

```html
<ion-icon name="heart"></ion-icon> <!--filled-->
<ion-icon name="heart-outline"></ion-icon> <!--outline-->
<ion-icon name="heart-sharp"></ion-icon> <!--sharp-->
```

### Platform specificity
When using icons in Ionic Framework you can specify different icons per platform. Use the `md` and `ios` attributes and provide the platform-specific icon/variant name.

```html
<ion-icon ios="heart-outline" md="heart-sharp"></ion-icon>
```

## Size

To specify the icon size, you can use the size attribute for our pre-defined font sizes.

```html
<ion-icon size="small"></ion-icon>
<ion-icon size="large"></ion-icon>
```

Or you can set a specific size by applying the `font-size` CSS property on the `ion-icon` component. It's recommended to use pixel sizes that are a multiple of 8 (8, 16, 32, 64, etc.)

```css
ion-icon {
  font-size: 64px;
}
```

## Color

Specify the icon color by applying the `color` CSS property on the `ion-icon` component.

```css
ion-icon {
  color: blue;
}
```

## Stroke width
When using an `outline` icon variant it is possible to adjust the stroke width, for improved visual balance relative to the icon's size or relative to the width of adjacent text. You can set a specific size by applying the `--ionicon-stroke-width` CSS custom property to the `ion-icon` component. The default value is 32px.

```html
<ion-icon name="heart-outline"></ion-icon>
```

```css
ion-icon {
  --ionicon-stroke-width: 16px;
}
```

## Migrating from v4

See the [5.0 release notes](https://github.com/ionic-team/ionicons/releases/tag/5.0.0) for a list of icon deletions/renames.

## License

Ionicons is licensed under the [MIT license](http://opensource.org/licenses/MIT).


## Related

* [Ionicons Homepage](http://ionicons.com/)
* [Ionic Framework](https://ionicframework.com/)
* [Ionic Discord](https://ionic.link/discord)
* [Ionic Forum](https://forum.ionicframework.com/)
* [Stencil](https://stenciljs.com/)
* [Capacitor](https://capacitorjs.com/)


================================================
FILE: scripts/build.ts
================================================
import path from 'node:path';

import fs from 'fs-extra';
import { optimize } from 'svgo';

import { webComponentPassPlugins, sourcePassPlugins } from './plugins';
import { reservedKeywords } from './constants';
import pkgData from '../package.json' with { type: 'json' };
import type { SvgData } from './types';

async function build(rootDir: string) {
  try {
    const srcDir = path.join(rootDir, 'src');
    const srcSvgDir = path.join(srcDir, 'svg');
    const iconDir = path.join(rootDir, 'icons');
    const distDir = path.join(rootDir, 'dist');
    const distIoniconsDir = path.join(distDir, 'ionicons');
    const distSvgDir = path.join(distDir, 'svg');
    const optimizedSvgDir = path.join(distIoniconsDir, 'svg');

    /**
     * Create the directories first, then empty them
     * This ensures they exist before we try to write files to them
     */
    await Promise.all([
      fs.ensureDir(iconDir),
      fs.ensureDir(distDir),
      fs.ensureDir(distSvgDir),
      fs.ensureDir(optimizedSvgDir),
      fs.ensureDir(distIoniconsDir),
    ]);

    /**
     * Empty the directories
     */
    await Promise.all([
      fs.emptyDir(iconDir),
      fs.emptyDir(distDir),
      fs.emptyDir(distSvgDir),
      fs.emptyDir(optimizedSvgDir),
      fs.emptyDir(distIoniconsDir),
    ]);

    const version = pkgData.version as string;
    const srcSvgData = await getSvgs(srcSvgDir, distSvgDir, optimizedSvgDir);
    await optimizeSvgs(srcSvgData);
    await Promise.all([
      createDataJson(version, srcDir, distDir, srcSvgData),
      createIconPackage(version, iconDir, srcSvgData),
    ]);

    const svgSymbolsContent = await createSvgSymbols(version, distDir, srcSvgData);

    await createCheatsheet(version, rootDir, distDir, svgSymbolsContent, srcSvgData);
    await createWebTypes(version, rootDir, distDir, srcSvgData);
    await copyToTesting(rootDir, distDir, srcSvgData);
  } catch (e) {
    console.error(e);
    process.exit(1);
  }
}

async function optimizeSvgs(srcSvgData: SvgData[]) {
  await Promise.all(
    srcSvgData.map(async (svgData) => {
      return optimizeSvg(svgData);
    }),
  );
}

async function optimizeSvg(svgData: SvgData) {
  const srcSvgContent = await fs.readFile(svgData.srcFilePath, 'utf8');

  const optimizedSvg = await optimize(srcSvgContent, { path: svgData.srcFilePath });
  const webComponentSvg = await optimize(optimizedSvg.data, {
    path: svgData.srcFilePath,
    plugins: webComponentPassPlugins,
  });
  const sourceSvg = await optimize(optimizedSvg.data, {
    path: svgData.srcFilePath,
    plugins: sourcePassPlugins,
  });

  // Ensure directories exist before writing files
  await Promise.all([
    fs.ensureDir(path.dirname(svgData.optimizedFilePath)),
    fs.ensureDir(path.dirname(svgData.distSvgFilePath)),
  ]);

  svgData.optimizedSvgContent = webComponentSvg.data;
  await Promise.all([
    fs.writeFile(svgData.optimizedFilePath, svgData.optimizedSvgContent),
    fs.writeFile(svgData.distSvgFilePath, sourceSvg.data),
  ]);
}

async function copyToTesting(rootDir: string, distDir: string, srcSvgData: SvgData[]) {
  const testDir = path.join(rootDir, 'www');
  const testBuildDir = path.join(testDir, 'build');
  const testSvgDir = path.join(testBuildDir, 'svg');

  // Ensure all directories exist
  await Promise.all([fs.ensureDir(testDir), fs.ensureDir(testBuildDir), fs.ensureDir(testSvgDir)]);

  await Promise.all(
    srcSvgData
      .filter((svgData): svgData is SvgData & { optimizedSvgContent: string } => Boolean(svgData.optimizedSvgContent))
      .map(async (svgData) => {
        const testSvgFilePath = path.join(testSvgDir, svgData.fileName);
        await fs.writeFile(testSvgFilePath, svgData.optimizedSvgContent);
      }),
  );

  const distCheatsheetFilePath = path.join(distDir, 'cheatsheet.html');
  const testCheatsheetFilePath = path.join(testDir, 'cheatsheet.html');
  await fs.copyFile(distCheatsheetFilePath, testCheatsheetFilePath);
}

async function createSvgSymbols(version: string, distDir: string, srcSvgData: SvgData[]) {
  srcSvgData = srcSvgData.sort((a, b) => {
    if (a.iconName < b.iconName) return -1;
    if (a.iconName > b.iconName) return 1;
    return 0;
  });

  const symbolsSvgFilePath = path.join(distDir, 'ionicons.symbols.svg');

  const lines = [
    `<svg data-ionicons="${version}" style="display:none">`,
    `<style>`,
    `.ionicon {`,
    `  fill: currentColor;`,
    `  stroke: currentColor;`,
    `}`,
    `.ionicon-fill-none {`,
    `  fill: none;`,
    `}`,
    `.ionicon-stroke-width {`,
    `  stroke-width: 32px;`,
    `}`,
    `</style>`,
  ];

  srcSvgData
    .filter((svgData): svgData is SvgData & { optimizedSvgContent: string } => Boolean(svgData.optimizedSvgContent))
    .forEach((svgData) => {
      const svg = svgData.optimizedSvgContent
        .replace(`<svg xmlns="http://www.w3.org/2000/svg"`, `<symbol id="${svgData.iconName}"`)
        .replace(`</svg>`, `</symbol>`);
      lines.push(svg);
    });

  lines.push(`</svg>`, ``);

  const content = lines.join('\n');
  await fs.writeFile(symbolsSvgFilePath, content);
  return content;
}

async function createCheatsheet(
  version: string,
  rootDir: string,
  distDir: string,
  svgSymbolsContent: string,
  srcSvgData: SvgData[],
) {
  const CheatsheetTmpFilePath = path.join(rootDir, 'scripts', 'cheatsheet-template.html');
  const distCheatsheetFilePath = path.join(distDir, 'cheatsheet.html');

  const c = srcSvgData.map(
    (svgData) =>
      `<a href="./svg/${svgData.fileName}"><svg><use href="#${svgData.iconName}" xlink:href="#${svgData.iconName}"/></svg></a>`,
  );

  c.push(svgSymbolsContent);

  const html = (await fs.readFile(CheatsheetTmpFilePath, 'utf8'))
    .replace(/{{version}}/g, version)
    .replace(/{{count}}/g, srcSvgData.length.toString())
    .replace(/{{content}}/g, c.join('\n'));

  await fs.writeFile(distCheatsheetFilePath, html);
}

async function createWebTypes(version: string, rootDir: string, distDir: string, srcSvgData: SvgData[]) {
  const srcWebTypeFilePath = path.join(rootDir, 'src/ionicons.web-types.json');
  const distWebTypesFilePath = path.join(distDir, 'ionicons.web-types.json');
  const webTypes = JSON.parse(await fs.readFile(srcWebTypeFilePath, 'utf8'));

  webTypes.version = version;

  const icons = webTypes.contributions.html.ionicons;
  for (let data of srcSvgData) {
    icons.push({
      name: data.iconName,
      icon: 'dist/svg/' + data.fileName,
    });
  }

  const jsonStr = JSON.stringify(webTypes, null, 2) + '\n';
  await fs.writeFile(distWebTypesFilePath, jsonStr);
}

async function getSvgs(srcSvgDir: string, distSvgDir: string, optimizedSvgDir: string): Promise<SvgData[]> {
  const svgFiles = (await fs.readdir(srcSvgDir)).filter((fileName) => {
    return !fileName.startsWith('.') && fileName.endsWith('.svg');
  });

  const svgData = await Promise.all(
    svgFiles.map(async (fileName) => {
      // fileName: airplane-outline.svg

      if (fileName.toLowerCase() !== fileName) {
        throw new Error(`svg filename "${fileName}" must be all lowercase`);
      }

      // srcFilePath: /src/svg/airplane-outline.svg
      const srcFilePath = path.join(srcSvgDir, fileName);

      // srcFilePath: /src/svg/airplane-outline.svg
      const distSvgFilePath = path.join(distSvgDir, fileName);

      // optimizedFilePath: /dist/ionicons/svg/airplane-outline.svg
      const optimizedFilePath = path.join(optimizedSvgDir, fileName);

      const dotSplit = fileName.split('.');
      if (dotSplit.length > 2) {
        throw new Error(`svg filename "${fileName}" cannot contain more than one period`);
      }

      // iconName: airplane-outline
      const iconName = dotSplit[0];

      if (reservedKeywords.has(iconName)) {
        throw new Error(`svg icon name "${iconName}" is a reserved JavaScript keyword`);
      }

      // fileNameMjs: airplane-outline.mjs
      const fileNameMjs = iconName + '.mjs';

      // fileNameCjs: airplane-outline.mjs
      const fileNameCjs = iconName + '.js';

      // exportName: airplaneOutline
      const exportName = camelize(iconName);

      const title = toTitleCase(
        fileName.replace('.svg', '').replace('-outline', '').replace('-sharp', '').replace(/-/g, ' '),
      );

      return {
        fileName,
        title,
        srcFilePath,
        distSvgFilePath,
        srcSvgContent: await fs.readFile(srcFilePath, 'utf8'),
        optimizedFilePath,
        iconName,
        fileNameMjs,
        fileNameCjs,
        exportName,
      };
    }),
  );

  return svgData.sort((a, b) => {
    if (a.exportName < b.exportName) return -1;
    if (a.exportName > b.exportName) return 1;
    return 0;
  });
}

async function createIconPackage(version: string, iconDir: string, srcSvgData: SvgData[]) {
  await Promise.all([
    createEsmIcons(version, iconDir, srcSvgData),
    createCjsIcons(version, iconDir, srcSvgData),
    createDtsIcons(version, iconDir, srcSvgData),
  ]);
}

async function createEsmIcons(version: string, iconDir: string, srcSvgData: SvgData[]) {
  const iconEsmFilePath = path.join(iconDir, 'index.mjs');

  const o = [`/* Ionicons v${version}, ES Modules */`, ``];

  srcSvgData.forEach((svgData) => {
    o.push(`export const ${svgData.exportName} = ${getDataUrl(svgData)}`);
  });

  await fs.writeFile(iconEsmFilePath, o.join('\n') + '\n');
}

async function createCjsIcons(version: string, iconDir: string, srcSvgData: SvgData[]) {
  const iconCjsFilePath = path.join(iconDir, 'index.js');

  const o = [`/* Ionicons v${version}, CommonJS */`, ``];

  srcSvgData.forEach((svgData) => {
    o.push(`exports.${svgData.exportName} = ${getDataUrl(svgData)}`);
  });

  await fs.writeFile(iconCjsFilePath, o.join('\n') + '\n');
}

async function createDtsIcons(version: string, iconDir: string, srcSvgData: SvgData[]) {
  const iconDtsFilePath = path.join(iconDir, 'index.d.ts');

  const o = [`/* Ionicons v${version}, Types */`, ``];

  srcSvgData.forEach((svgData) => {
    o.push(`export declare var ${svgData.exportName}: string;`);
  });

  await fs.writeFile(iconDtsFilePath, o.join('\n') + '\n');
}

function getDataUrl(svgData: SvgData) {
  let svg = svgData.optimizedSvgContent;

  if (!svg) {
    throw new Error(`oh no! no optimized SVG content! ${svgData.fileName}`);
  }

  if (svg.includes(`'`)) {
    throw new Error(`oh no! no single quotes allowed! ${svgData.fileName}`);
  }
  if (svg.includes(`\n`) || svg.includes(`\r`)) {
    throw new Error(`oh no! no new lines allowed! ${svgData.fileName}`);
  }
  svg = svg.replace(/"/g, "'");
  return `"data:image/svg+xml;utf8,${svg}"`;
}

async function createDataJson(version: string, srcDir: string, distDir: string, srcSvgData: SvgData[]) {
  const srcDataJsonPath = path.join(srcDir, 'data.json');
  const distDataJsonPath = path.join(distDir, 'ionicons.json');

  const data = await fs.readJson(srcDataJsonPath).catch(() => ({}));
  data.icons = data.icons || [];

  // add new icons
  srcSvgData.forEach((svgData) => {
    if (!data.icons.some((i) => i.name === svgData.iconName)) {
      data.icons.push({
        name: svgData.iconName,
      });
    }
  });

  // remove dead icons
  data.icons = data.icons.filter((dataIcon) => {
    return srcSvgData.some((svgData) => dataIcon.name === svgData.iconName);
  });

  // sort
  data.icons = data.icons.sort((a, b) => {
    if (a.name < b.name) return -1;
    if (a.name > b.name) return 1;
    return 0;
  });
  data.icons.forEach((icon) => {
    icon.tags = icon.tags || icon.name.split('-');
    icon.tags = icon.tags.sort();
  });

  const srcJsonStr = JSON.stringify(data, null, 2) + '\n';
  await fs.writeFile(srcDataJsonPath, srcJsonStr);

  const distJsonData = {
    name: 'ionicons',
    version,
    icons: data.icons,
  };
  const distJsonStr = JSON.stringify(distJsonData, null, 2) + '\n';
  await fs.writeFile(distDataJsonPath, distJsonStr);
}

function camelize(text: string) {
  let words = text.split(/[-_]/g); // ok one simple regexp.
  return words[0].toLowerCase() + words.slice(1).map(upFirst).join('');
}

function upFirst(word: string) {
  return word[0].toUpperCase() + word.toLowerCase().slice(1);
}

function toTitleCase(str: string) {
  const s = str.trim().toLowerCase().split(' ');
  for (var i = 0; i < s.length; i++) {
    s[i] = s[i].charAt(0).toUpperCase() + s[i].slice(1);
  }
  return s.join(' ');
}

// let's do this
build(path.join(__dirname, '..'));


================================================
FILE: scripts/cheatsheet-template.html
================================================
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Ionicons {{version}} Cheatsheet</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
      background: #fff;
    }
    h1 {
      margin: 0;
    }
    .options {
      padding: 15px 0 20px 0;
    }
    label {
      display: inline-block;
      width: 100px;
      font-size: 12px;
    }
    svg {
      width: 32px;
      height: 32px;
    }
    a {
      color: inherit;
      text-decoration: none;
    }
    a:hover {
      opacity: 0.7;
    }
  </style>
</head>
<body>
<h1>Ionicons {{version}} Cheatsheet</h1>
<h3>{{count}} icons</h3>

{{content}}
</body>
</html>


================================================
FILE: scripts/collection-copy.ts
================================================
import fs from 'fs-extra';
import { join } from 'path';

async function collectionCopy(rootDir: string) {
  // move optimized svgs to correct collection location
  const optimizedSrc = join(rootDir, 'dist', 'ionicons', 'svg');
  const collectionDest = join(rootDir, 'dist', 'collection', 'components', 'icon', 'svg');
  await fs.copy(optimizedSrc, collectionDest);

  // we don't to copy the src svgs to collection
  await fs.remove(join(rootDir, 'dist', 'collection', 'svg'));
  // We don't want to copy the test svg assets to collection
  await fs.remove(join(rootDir, 'dist', 'collection', 'components', 'test'));

  const cePackageDir = join(rootDir, 'components');
  const cePackageJsonPath = join(cePackageDir, 'package.json');
  const ceCjsPath = join(cePackageDir, 'index.cjs.js');

  const emptyCjs = `/*empty cjs*/`;
  await fs.writeFile(ceCjsPath, emptyCjs);

  const cePackageJson = {
    name: 'ionicons/components',
    description: 'Ionicons custom element.',
    main: './index.cjs.js',
    module: './index.js',
    types: './index.d.ts',
    private: true,
  };
  await fs.writeFile(cePackageJsonPath, JSON.stringify(cePackageJson, null, 2));

  // this is temporary!!!!
  // removing the `type` from the d.ts export
  // to make it easier for users migrating between
  // of older versions of angular and typescript
  // to the newer verisons, where the `type` keyword
  // is used. This is a megahack, no doubt.
  const typesDist = join(rootDir, 'dist', 'types', 'index.d.ts');
  let types = await fs.readFile(typesDist, 'utf8');
  types = types.replace('export type', 'export');
  await fs.writeFile(typesDist, types);
}

collectionCopy(join(__dirname, '..'));


================================================
FILE: scripts/constants.ts
================================================
// https://mathiasbynens.be/notes/reserved-keywords
export const reservedKeywords = new Set([
  'do',
  'if',
  'in',
  'for',
  'let',
  'new',
  'try',
  'var',
  'case',
  'else',
  'enum',
  'eval',
  'null',
  'this',
  'true',
  'void',
  'with',
  'await',
  'break',
  'catch',
  'class',
  'const',
  'false',
  'super',
  'throw',
  'while',
  'yield',
  'delete',
  'export',
  'import',
  'public',
  'return',
  'static',
  'switch',
  'typeof',
  'default',
  'extends',
  'finally',
  'package',
  'private',
  'continue',
  'debugger',
  'function',
  'arguments',
  'interface',
  'protected',
  'implements',
  'instanceof',
  'constructor',
]);


================================================
FILE: scripts/plugins.ts
================================================
import { PluginConfig } from 'svgo';

const setRootIoniconClass: PluginConfig = {
  name: 'addClassesToSVGElement',
  params: {
    className: 'ionicon',
  },
};

const addFillNoneCss: PluginConfig = {
  name: 'addFillNoneCss',
  fn: () => ({
    element: {
      enter: (element) => {
        if (element.attributes.fill) {
          if (element.attributes.fill === 'none') {
            element.attributes.class = [...(element.attributes.class?.split(' ') || []), 'ionicon-fill-none'].join(' ');
          }
          delete element.attributes.fill;
        }
        if (element.attributes.stroke) {
          delete element.attributes.stroke;
        }
        if (
          element.attributes['stroke-width'] &&
          (element.attributes['stroke-width'] === '32px' || element.attributes['stroke-width'] === '32')
        ) {
          delete element.attributes['stroke-width'];
          element.attributes.class = [...(element.attributes.class?.split(' ') || []), 'ionicon-stroke-width'].join(
            ' ',
          );
        }
      },
    },
  }),
};

const forceCurrentColor: PluginConfig = {
  name: 'forceCurrentColor',
  fn: () => ({
    element: {
      enter: (element) => {
        const attr = element.attributes.stroke || element.attributes.fill;
        const attrName = element.attributes.stroke ? 'stroke' : element.attributes.fill ? 'fill' : undefined;

        if (attrName) {
          if (attr === '#000' || attr === 'currentColor') {
            element.attributes[attrName] = 'currentColor';
          } else if (attr !== 'none') {
            throw new Error(`invalid "${attrName}" value: ${element.attributes[attrName]}`);
          }
        }
      },
    },
  }),
};

const validatePlugin: PluginConfig = {
  name: 'validate',
  fn: () => ({
    element: {
      enter: (element) => {
        if (element.attributes.style) {
          console.warn(
            `Inline style attributed detected: <${element.name} style="${element.attributes.style}">...</${element.name}>`,
          );
        }
        if (element.name === 'style') {
          console.warn('Inline style element detected');
        }
      },
    },
  }),
};

const basePlugins: PluginConfig[] = [
  'removeStyleElement',
  'convertStyleToAttrs',
  'removeScripts',
  'removeDimensions',
  setRootIoniconClass,
  validatePlugin,
];

export const webComponentPassPlugins: PluginConfig[] = [...basePlugins, addFillNoneCss];

export const sourcePassPlugins: PluginConfig[] = [...basePlugins, forceCurrentColor];


================================================
FILE: scripts/readme.md
================================================
# Development and Build Scripts

## Updating Icons

The `src/svg` directory is the single source of truth for svgs. They should not already be optimized and can be the original svg export straight out of an svg editor. A build step before releasing will optimize the source svgs (remove comments, reduce the size, etc) and ensure they'll work within `ion-icon`.

## Build Locally

After an svg has been updated, added or deleted from the `src/svg` directory, run:

```sh
npm run build
```

The build command will optimize all of the icons and generate the files to be distributed. After the build command, all of the optimized svgs are saved in `dist/ionicons/svg`. Additionally the `dist` directory contains the distribution files for the `ion-icon` web component.

## Svg Symbols Cheatsheet

After a build, a new `www/cheatsheet.html` file will be created. This version uses svg symbols rather than `ion-icon`.

## ion-icon Component Preview

To see the `ion-icon` component in action, run:

```sh
npm start
```

## Release Steps

The release script will ask what version to use. After the script completes, double check the `www/cheatsheet.html` to ensure everything is good to go.

Next, update `CHANGELOG.md`, then commit and push your changes Github.

```sh
npm run release
```

Triple check the version number is correct, and choose which tag this should be released as. If it's a pre-release, it should be `dev`.


================================================
FILE: scripts/types.ts
================================================
import { PluginConfig } from 'svgo';

export interface SvgData {
  /**
   * airplane-outline.svg
   */
  fileName: string;

  /**
   * airplane
   */
  title: string;

  /**
   * /src/svg/airplane-outline.svg
   */
  srcFilePath: string;

  /**
   * /dist/ionicons/svg/airplane-outline.svg
   */
  optimizedFilePath: string;

  /**
   * /dist/svg/airplane-outline.svg
   */
  distSvgFilePath: string;

  /**
   * optimized svg content
   */
  optimizedSvgContent?: string;

  /**
   * airplane-outline
   */
  iconName: string;

  /**
   * airplane-outline.mjs
   */
  fileNameMjs: string;

  /**
   * airplane-outline.js
   */
  fileNameCjs: string;

  /**
   * airplaneOutline
   */
  exportName: string;
}


================================================
FILE: src/components/icon/icon.css
================================================
:host {
  display: inline-block;

  width: 1em;
  height: 1em;

  contain: strict;

  fill: currentColor;

  box-sizing: content-box !important;

}

:host .ionicon {
  stroke: currentColor;
}

.ionicon-fill-none {
  fill: none;
}

.ionicon-stroke-width {
  stroke-width: var(--ionicon-stroke-width, 32px);
}

.icon-inner,
.ionicon,
svg {
  display: block;

  height: 100%;
  width: 100%;
}

/* Icon RTL
 * -----------------------------------------------------------
 */

/**
 * Safari <16.4 incorrectly reports
 * that it supports :dir(rtl) when it does not.
 * This @supports statement lets us target
 * WebKit browsers to apply the RTL fallback.
 * -webkit-named-image only exists on WebKit.
 * For WebKit browsers that do support :dir(rtl)
 * (i.e. Safari >= 16.4) then the :dir(rtl)
 * code farther down on the page will take
 * effect and override this fallback.
 */
@supports (background: -webkit-named-image(i)) {
  :host(.icon-rtl) .icon-inner {
    transform: scaleX(-1);
  }
}

/**
 * Fallback for browsers that support
 * neither :host-context nor :dir.
 * The icon will not react to dir
 * changes, but it will at least
 * respect the dir on component load.
 */
@supports not selector(:dir(rtl)) and selector(:host-context([dir='rtl'])) {
  :host(.icon-rtl) .icon-inner {
    transform: scaleX(-1);
  }
}

/* :host-context is supported in chromium; :dir is supported in safari & firefox */
:host(.flip-rtl):host-context([dir='rtl']) .icon-inner {
  transform: scaleX(-1);
}

@supports selector(:dir(rtl)) {
  :host(.flip-rtl:dir(rtl)) .icon-inner {
    transform: scaleX(-1);
  }
  /**
   * This is needed for WebKit otherwise the fallback
   * will always cause the icon to be flipped if the document
   * loads in RTL.
   */
  :host(.flip-rtl:dir(ltr)) .icon-inner {
    transform: scaleX(1);
  }
}

/* Icon Sizes
 * -----------------------------------------------------------
 */

:host(.icon-small) {
  font-size: 1.125rem !important;
}

:host(.icon-large) {
  font-size: 2rem !important;
}

/* Icon Colors
 * -----------------------------------------------------------
 */

:host(.ion-color) {
  color: var(--ion-color-base) !important;
}

:host(.ion-color-primary) {
  --ion-color-base: var(--ion-color-primary, #3880ff);
}

:host(.ion-color-secondary) {
  --ion-color-base: var(--ion-color-secondary, #0cd1e8);
}

:host(.ion-color-tertiary) {
  --ion-color-base: var(--ion-color-tertiary, #f4a942);
}

:host(.ion-color-success) {
  --ion-color-base: var(--ion-color-success, #10dc60);
}

:host(.ion-color-warning) {
  --ion-color-base: var(--ion-color-warning, #ffce00);
}

:host(.ion-color-danger) {
  --ion-color-base: var(--ion-color-danger, #f14141);
}

:host(.ion-color-light) {
  --ion-color-base: var(--ion-color-light, #f4f5f8);
}

:host(.ion-color-medium) {
  --ion-color-base: var(--ion-color-medium, #989aa2);
}

:host(.ion-color-dark) {
  --ion-color-base: var(--ion-color-dark, #222428);
}


================================================
FILE: src/components/icon/icon.tsx
================================================
import { Build, Component, Element, Host, Prop, State, Watch, h } from '@stencil/core';
import { getSvgContent, ioniconContent } from './request';
import { getName, getUrl, inheritAttributes, isRTL } from './utils';

@Component({
  tag: 'ion-icon',
  assetsDirs: ['svg'],
  styleUrl: 'icon.css',
  shadow: true,
})
export class Icon {
  private io?: IntersectionObserver;
  private iconName: string | null = null;
  private inheritedAttributes: { [k: string]: any } = {};
  private didLoadIcon = false;

  @Element() el!: HTMLElement;

  @State() private svgContent?: string;
  @State() private isVisible = false;

  /**
   * The mode determines which platform styles to use.
   */
  @Prop({ mutable: true }) mode = getIonMode();

  /**
   * The color to use for the background of the item.
   */
  @Prop() color?: string;

  /**
   * Specifies which icon to use on `ios` mode.
   */
  @Prop() ios?: string;

  /**
   * Specifies which icon to use on `md` mode.
   */
  @Prop() md?: string;

  /**
   * Specifies whether the icon should horizontally flip when `dir` is `"rtl"`.
   */
  @Prop() flipRtl?: boolean;

  /**
   * Specifies which icon to use from the built-in set of icons.
   */
  @Prop({ reflect: true }) name?: string;

  /**
   * Specifies the exact `src` of an SVG file to use.
   */
  @Prop() src?: string;

  /**
   * A combination of both `name` and `src`. If a `src` url is detected
   * it will set the `src` property. Otherwise it assumes it's a built-in named
   * SVG and set the `name` property.
   */
  @Prop() icon?: any;

  /**
   * The size of the icon.
   * Available options are: `"small"` and `"large"`.
   */
  @Prop() size?: string;

  /**
   * If enabled, ion-icon will be loaded lazily when it's visible in the viewport.
   * Default, `false`.
   */
  @Prop() lazy = false;

  /**
   * When set to `false`, SVG content that is HTTP fetched will not be checked
   * if the response SVG content has any `<script>` elements, or any attributes
   * that start with `on`, such as `onclick`.
   * @default true
   */
  @Prop() sanitize = true;

  componentWillLoad() {
    this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
  }

  connectedCallback() {
    /**
     * purposely do not return the promise here because loading
     * the svg file should not hold up loading the app
     * only load the svg if it's visible
     */
    this.waitUntilVisible(this.el, '50px', () => {
      this.isVisible = true;
      this.loadIcon();
    });
  }

  /**
   * Loads the icon after the component has finished rendering.
   */
  componentDidLoad() {
    /**
     * Addresses an Angular issue where property values are assigned after the 'connectedCallback' but prior to the registration of watchers.
     * This enhancement ensures the loading of an icon when the component has finished rendering and the icon has yet to apply the SVG data.
     * This modification pertains to the usage of Angular's binding syntax:
     * `<ion-icon [name]="myIconName"></ion-icon>`
     */
    if (!this.didLoadIcon) {
      this.loadIcon();
    }
  }

  /**
   * Disconnect the IntersectionObserver.
   */
  disconnectedCallback() {
    if (this.io) {
      this.io.disconnect();
      this.io = undefined;
    }
  }

  /**
   * Wait until the icon is visible in the viewport.
   * @param el - The element to observe.
   * @param rootMargin - The root margin of the observer.
   * @param cb - The callback to call when the element is visible.
   */
  private waitUntilVisible(el: HTMLElement, rootMargin: string, cb: () => void) {
    /**
     * IntersectionObserver is a browser API that allows you to observe
     * the visibility of an element relative to a root element. It is
     * supported in all modern browsers, except IE and when server-side
     * rendering.
     */
    const hasIntersectionObserverSupport = Boolean(
      Build.isBrowser && this.lazy && typeof window !== 'undefined' && window.IntersectionObserver,
    );

    /**
     * browser doesn't support IntersectionObserver
     * so just fallback to always show it
     */
    if (!hasIntersectionObserverSupport) {
      return cb();
    }

    const io = (this.io = new window.IntersectionObserver(
      (data: IntersectionObserverEntry[]) => {
        if (data[0].isIntersecting) {
          io.disconnect();
          this.io = undefined;
          cb();
        }
      },
      { rootMargin },
    ));

    io.observe(el);
  }

  /**
   * Watch for changes to the icon name, src, icon, ios, or md properties.
   * When a change is detected, the icon will be loaded.
   */
  @Watch('name')
  @Watch('src')
  @Watch('icon')
  @Watch('ios')
  @Watch('md')
  loadIcon() {
    if (Build.isBrowser && this.isVisible) {
      const url = getUrl(this);

      if (url) {
        if (ioniconContent.has(url)) {
          // sync if it's already loaded
          this.svgContent = ioniconContent.get(url);
        } else {
          // async if it hasn't been loaded
          getSvgContent(url, this.sanitize).then(() => (this.svgContent = ioniconContent.get(url)));
        }
        this.didLoadIcon = true;
      }
    }

    this.iconName = getName(this.name, this.icon, this.mode, this.ios, this.md);
  }

  render() {
    const { flipRtl, iconName, inheritedAttributes, el } = this;
    const mode = this.mode || 'md';

    /**
     * we have designated that arrows & chevrons should automatically flip (unless flip-rtl
     * is set to false) because "back" is left in ltr and right in rtl, and "forward" is the opposite
     */
    const shouldAutoFlip = iconName
      ? (iconName.includes('arrow') || iconName.includes('chevron')) && flipRtl !== false
      : false;

    /**
     * if shouldBeFlippable is true, the icon should change direction when `dir` changes
     */
    const shouldBeFlippable = flipRtl || shouldAutoFlip;

    return (
      <Host
        role="img"
        class={{
          [mode]: true,
          ...createColorClasses(this.color),
          [`icon-${this.size}`]: !!this.size,
          'flip-rtl': shouldBeFlippable,
          'icon-rtl': shouldBeFlippable && isRTL(el),
        }}
        {...inheritedAttributes}
      >
        {Build.isBrowser && this.svgContent ? (
          <div class="icon-inner" innerHTML={this.svgContent}></div>
        ) : (
          <div class="icon-inner"></div>
        )}
      </Host>
    );
  }
}

/**
 * Get the mode of the document.
 * @returns The mode of the document.
 */
const getIonMode = () =>
  (Build.isBrowser && typeof document !== 'undefined' && document.documentElement.getAttribute('mode')) || 'md';

/**
 * Create color classes for the icon.
 * @param color - The color of the icon.
 * @returns The color classes for the icon.
 */
const createColorClasses = (color: string | undefined) => {
  return color
    ? {
        'ion-color': true,
        [`ion-color-${color}`]: true,
      }
    : null;
};


================================================
FILE: src/components/icon/readme.md
================================================
# ion-icon



<!-- Auto Generated Below -->


## Properties

| Property   | Attribute  | Description                                                                                                                                                                                   | Type                   | Default        |
| ---------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | -------------- |
| `color`    | `color`    | The color to use for the background of the item.                                                                                                                                              | `string \| undefined`  | `undefined`    |
| `flipRtl`  | `flip-rtl` | Specifies whether the icon should horizontally flip when `dir` is `"rtl"`.                                                                                                                    | `boolean \| undefined` | `undefined`    |
| `icon`     | `icon`     | A combination of both `name` and `src`. If a `src` url is detected it will set the `src` property. Otherwise it assumes it's a built-in named SVG and set the `name` property.                | `any`                  | `undefined`    |
| `ios`      | `ios`      | Specifies which icon to use on `ios` mode.                                                                                                                                                    | `string \| undefined`  | `undefined`    |
| `lazy`     | `lazy`     | If enabled, ion-icon will be loaded lazily when it's visible in the viewport. Default, `false`.                                                                                               | `boolean`              | `false`        |
| `md`       | `md`       | Specifies which icon to use on `md` mode.                                                                                                                                                     | `string \| undefined`  | `undefined`    |
| `mode`     | `mode`     | The mode determines which platform styles to use.                                                                                                                                             | `string`               | `getIonMode()` |
| `name`     | `name`     | Specifies which icon to use from the built-in set of icons.                                                                                                                                   | `string \| undefined`  | `undefined`    |
| `sanitize` | `sanitize` | When set to `false`, SVG content that is HTTP fetched will not be checked if the response SVG content has any `<script>` elements, or any attributes that start with `on`, such as `onclick`. | `boolean`              | `true`         |
| `size`     | `size`     | The size of the icon. Available options are: `"small"` and `"large"`.                                                                                                                         | `string \| undefined`  | `undefined`    |
| `src`      | `src`      | Specifies the exact `src` of an SVG file to use.                                                                                                                                              | `string \| undefined`  | `undefined`    |


----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*


================================================
FILE: src/components/icon/request.ts
================================================
import { isEncodedDataUrl, isSvgDataUrl, validateContent } from './validate';

export const ioniconContent = new Map<string, string>();
const requests = new Map<string, Promise<any>>();

let parser: DOMParser;

/**
 * Safely fallback to an empty svg
 */
function safeFallback(url: string) {
  const svg = '';
  ioniconContent.set(url, svg);
  return svg;
}

export const getSvgContent = (url: string, sanitize: boolean): Promise<string> => {
  /**
   * See if we already have a request for this url
   */
  const req = requests.get(url);
  if (req) {
    return req;
  }

  if (typeof fetch !== 'undefined' && typeof document !== 'undefined') {
    /**
     * If the url is a data url of an svg, then try to parse it
     * with the DOMParser. This works with content security policies enabled.
     */
    if (isSvgDataUrl(url) && isEncodedDataUrl(url)) {
      return Promise.resolve(getSvgByUrl(url));
    }

    return fetchSvg(url, sanitize);
  }

  return Promise.resolve(safeFallback(url));
};

function getSvgByUrl(url: string): string {
  if (!parser) {
    /**
     * Create an instance of the DOM parser. This creates a single
     * parser instance for the entire app, which is more efficient.
     */
    parser = new DOMParser();
  }
  const doc = parser.parseFromString(url, 'text/html');
  const svg = doc.querySelector('svg');
  if (svg) {
    ioniconContent.set(url, svg.outerHTML);
    return svg.outerHTML;
  }

  throw new Error(`Could not parse svg from ${url}`);
}

function fetchSvg(url: string, sanitize: boolean): Promise<string> {
  /**
   * We don't already have a request
   */
  const req = fetch(url)
    .then((rsp) => {
      /**
       * When fetching from a file:// URL, some browsers return
       * a 0 status code even when the request succeeds so don't
       * rely on rsp.ok as the only signal of success.
       */
      return rsp
        .text()
        .then((svgContent) => {
          if (svgContent && sanitize !== false) {
            svgContent = validateContent(svgContent);
          }

          const svg = svgContent || '';
          ioniconContent.set(url, svg);
          return svg;
        })
        .catch(() => safeFallback(url));
    })
    .catch(() => safeFallback(url));

  /**
   * Cache for the same requests
   */
  requests.set(url, req);
  return req;
}


================================================
FILE: src/components/icon/svg/.gitignore
================================================
# this gitignore file is used as a placeholder
# for this directory. The directory itself will
# contain files generated during a build step.
!.gitignore

================================================
FILE: src/components/icon/test/icon.e2e.ts
================================================
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';

test.describe('icon: basic', () => {
  test('should not have visual regressions', async ({ page }) => {
    await page.goto(`/`);

    // Wait for all SVGs to be lazily loaded before taking screenshots
    await page.waitForLoadState('networkidle');

    await expect(page).toHaveScreenshot(`icon-diff.png`, { fullPage: true });
  });

  test('some icons should flip when rtl', async ({ page }) => {
    await page.goto(`/`);

    const autoflip = page.locator('.auto-flip-chevrons [name=chevron-forward] .icon-inner');
    const unflip = page.locator('.un-flip-chevrons [name=chevron-forward] .icon-inner');
    await expect(autoflip).not.toHaveCSS('transform', /matrix\(-1/);
    await expect(unflip).not.toHaveCSS('transform', /matrix\(-1/);

    await page.evaluate(() => {
      document.dir = 'rtl';
    });

    await expect(autoflip).toHaveCSS('transform', /matrix\(-1/);
    await expect(unflip).not.toHaveCSS('transform', /matrix\(-1/);

    // Wait for all SVGs to be lazily loaded before taking screenshots
    await page.waitForLoadState('networkidle');

    const rtlTests = page.locator('#rtl-tests');
    await expect(rtlTests).toHaveScreenshot(`icon-rtl-diff.png`);
  });

  test('arrows should flip if dir changes on the element', async ({ page }) => {
    await page.goto(`/`);

    const autoflip = page.locator('.auto-flip-chevrons [name=chevron-forward] .icon-inner');
    const unflip = page.locator('.un-flip-chevrons [name=chevron-forward] .icon-inner');
    await expect(autoflip).not.toHaveCSS('transform', /matrix\(-1/);
    await expect(unflip).not.toHaveCSS('transform', /matrix\(-1/);

    const autoflipEl = await page.$('.auto-flip-chevrons [name=chevron-forward]');
    const unflipEl = await page.$('.un-flip-chevrons [name=chevron-forward]');
    await autoflipEl!.evaluate((node) => node.setAttribute('dir', 'rtl'));
    await unflipEl!.evaluate((node) => node.setAttribute('dir', 'rtl'));

    await expect(autoflip).toHaveCSS('transform', /matrix\(-1/);
    await expect(unflip).not.toHaveCSS('transform', /matrix\(-1/);
  });

  test('icon should reassess flipping when name changes', async ({ page }) => {
    await page.goto(`/`);

    await page.evaluate(() => {
      document.dir = 'rtl';
    });

    const iconLoc = page.locator('.auto-flip-chevrons ion-icon:nth-child(2)');
    await expect(iconLoc).toHaveAttribute('name', 'chevron-forward');
    await expect(iconLoc).toHaveClass(/flip-rtl/);

    const iconEl = await page.$('.auto-flip-chevrons ion-icon:nth-child(2)');
    await iconEl!.evaluate((node) => node.setAttribute('name', 'brush'));

    await expect(iconLoc).toHaveAttribute('name', 'brush');
    await expect(iconLoc).not.toHaveClass(/flip-rtl/);
  });
});


================================================
FILE: src/components/icon/test/icon.spec.ts
================================================
import { newSpecPage } from 'jest-stencil-runner';
import { Icon } from '../icon';

describe('icon', () => {
  it('renders', async () => {
    const { root } = await newSpecPage({
      components: [Icon],
      html: '<ion-icon></ion-icon>',
    });
    expect(root).toEqualHtml(`
      <ion-icon class="md" role="img">
        <mock:shadow-root>
          <div class="icon-inner"></div>
        </mock:shadow-root>
      </ion-icon>
    `);
  });

  it('renders rtl with aria-hidden', async () => {
    const { root } = await newSpecPage({
      components: [Icon],
      direction: 'rtl',
      html: `<ion-icon name="chevron-forward" aria-hidden="true"></ion-icon>`,
    });

    expect(root).toEqualHtml(`
      <ion-icon class="md flip-rtl icon-rtl" name="chevron-forward" role="img" aria-hidden="true">
        <mock:shadow-root>
          <div class="icon-inner"></div>
        </mock:shadow-root>
      </ion-icon>
    `);
  });

  it('renders custom aria-label', async () => {
    const { root } = await newSpecPage({
      components: [Icon],
      html: `<ion-icon name="star" aria-label="custom label"></ion-icon>`,
    });

    expect(root).toEqualHtml(`
      <ion-icon class="md" name="star" role="img" aria-label="custom label">
        <mock:shadow-root>
          <div class="icon-inner"></div>
        </mock:shadow-root>
      </ion-icon>
    `);
  });

  it('renders custom label after changing source', async () => {
    const page = await newSpecPage({
      components: [Icon],
      html: `<ion-icon name="chevron-forward" aria-label="custom label"></ion-icon>`,
    });

    const icon = page.root;

    expect(icon).toEqualHtml(`
      <ion-icon class="flip-rtl md" name="chevron-forward" role="img" aria-label="custom label">
        <mock:shadow-root>
          <div class="icon-inner"></div>
        </mock:shadow-root>
      </ion-icon>
    `);

    if (icon) {
      icon.name = 'trash';
    }
    await page.waitForChanges();

    expect(icon).toEqualHtml(`
      <ion-icon class="md" name="trash" role="img" aria-label="custom label">
        <mock:shadow-root>
          <div class="icon-inner"></div>
        </mock:shadow-root>
      </ion-icon>
    `);
  });
});


================================================
FILE: src/components/icon/test/utils.spec.ts
================================================
import { Icon } from '../icon';
import { addIcons, getIconMap, getName, getSrc, getUrl } from '../utils';

describe('getUrl', () => {
  let i: Icon;

  beforeEach(() => {
    i = new Icon();
  });

  /**
   * Started to fail after upgrading to new jest-stencil-runner
   * @ToDo(@christian-bromann): investigate why this is failing
   */
  it.skip('use icon prop, as name', () => {
    i.icon = 'some-name';
    expect(getUrl(i)).toBe('/svg/some-name.svg');
  });

  it('use icon prop, as url', () => {
    i.icon = './some.svg';
    expect(getUrl(i)).toBe('./some.svg');
  });

  /**
   * Started to fail after upgrading to new jest-stencil-runner
   * @ToDo(@christian-bromann): investigate why this is failing
   */
  it.skip('use name prop', () => {
    i.name = 'some-name';
    expect(getUrl(i)).toBe('/svg/some-name.svg');
  });

  it('use src prop', () => {
    i.src = './some.svg';
    i.name = 'some-name';
    i.icon = 'some-icon';
    expect(getUrl(i)).toBe('./some.svg');
  });
});

describe('getSrc', () => {
  it('both . and /', () => {
    expect(getSrc('./somefile.svg')).toBe('./somefile.svg');
  });

  it('url', () => {
    expect(getSrc('https://ionicons/somefile.svg')).toBe('https://ionicons/somefile.svg');
  });

  it('just a .', () => {
    expect(getSrc('somefile.svg')).toBe('somefile.svg');
  });

  it('just a /', () => {
    expect(getSrc('/somesvg')).toBe('/somesvg');
  });

  it('no . or /', () => {
    expect(getSrc('some-name')).toBe(null);
  });
});

describe('getName', () => {
  it('not allow special chars', () => {
    expect(getName('some\\name', '', 'io', '', '')).toBe(null);
    expect(getName('some$name', '', 'io', '', '')).toBe(null);
    expect(getName('some:name', '', 'io', '', '')).toBe(null);
    expect(getName('some.name', '', 'io', '', '')).toBe(null);
    expect(getName('some/name', '', 'io', '', '')).toBe(null);
  });

  it('use ios mode prefixed', () => {
    expect(getName('ios-some-name', '', '', '', '')).toBe('ios-some-name');
  });

  it('use md mode prefixed', () => {
    expect(getName('md-some-name', '', '', '', '')).toBe('md-some-name');
  });

  it('should not use name if no name, ios or md', () => {
    expect(getName(undefined, undefined, '', '', '')).toBe(null);
  });
});

describe('addIcons', () => {
  it('should add an svg to the icon cache', () => {
    const testData = 'stubbed data';

    expect(getIconMap().get('logo-ionic')).toEqual(undefined);

    addIcons({ 'logo-ionic': 'stubbed data' });

    expect(getIconMap().get('logo-ionic')).toEqual(testData);
  });

  it('should add kebab and camel case names to the icon cache', () => {
    const logoIonitron = 'stubbed data';

    expect(getIconMap().get('logo-ionitron')).toEqual(undefined);
    expect(getIconMap().get('logoIonitron')).toEqual(undefined);

    addIcons({ logoIonitron });

    expect(getIconMap().get('logo-ionitron')).toEqual(logoIonitron);
    expect(getIconMap().get('logoIonitron')).toEqual(logoIonitron);

    const logoIonitron0 = 'stubbed data 0';

    expect(getIconMap().get('logo-ionitron-0')).toEqual(undefined);
    expect(getIconMap().get('logoIonitron0')).toEqual(undefined);

    addIcons({ logoIonitron0 });

    expect(getIconMap().get('logo-ionitron-0')).toEqual(logoIonitron0);
    expect(getIconMap().get('logoIonitron0')).toEqual(logoIonitron0);
  });

  it('should map to a name that does not match the svg', () => {
    const logoIonitron = 'stubbed data';

    expect(getIconMap().get('my-fun-icon')).toEqual(undefined);

    addIcons({ 'my-fun-icon': logoIonitron });

    expect(getIconMap().get('my-fun-icon')).toEqual(logoIonitron);
  });

  it('should map to an explicit camel case name', () => {
    const logoIonitron = 'stubbed data';

    expect(getIconMap().get('myCoolIcon')).toEqual(undefined);

    addIcons({ myCoolIcon: logoIonitron });

    expect(getIconMap().get('myCoolIcon')).toEqual(logoIonitron);
  });

  it('should not warn when mapping the same icon twice', () => {
    const spy = jest.spyOn(console, 'warn');

    const myIcon = 'my-icon';

    expect(spy).not.toHaveBeenCalled();

    addIcons({ myIcon });

    expect(spy).not.toHaveBeenCalled();

    addIcons({ myIcon });

    expect(spy).not.toHaveBeenCalled();
  });

  it('should not overwrite icons', () => {
    const spy = jest.spyOn(console, 'warn');

    const logoA = 'logo a';
    const logoB = 'logo b';

    expect(spy).not.toHaveBeenCalled();

    expect(getIconMap().get('logo-a')).toEqual(undefined);

    addIcons({ 'logo-a': logoB, logoA });

    expect(getIconMap().get('logo-a')).toEqual(logoB);
    expect(getIconMap().get('logoA')).toEqual(logoA);

    expect(spy).toHaveBeenCalled();
  });
});


================================================
FILE: src/components/icon/test/validate.spec.ts
================================================
import { isEncodedDataUrl, isSvgDataUrl, isValid } from '../validate';

describe('isValid', () => {
  it('invalid onload attr', () => {
    const el = {
      nodeType: 1,
      nodeName: 'svg',
      attributes: [{ name: 'onload' }],
      childNodes: [],
    } as any;
    expect(isValid(el)).toBe(false);
  });

  it('invalid onclick attr', () => {
    const el = {
      nodeType: 1,
      nodeName: 'svg',
      attributes: [{ name: 'OnClIcK' }],
      childNodes: [],
    } as any;
    expect(isValid(el)).toBe(false);
  });

  it('invalid child SCRIPT elm', () => {
    const el = {
      nodeType: 1,
      nodeName: 'svg',
      attributes: [],
      childNodes: [{ nodeType: 1, nodeName: 'SCRIPT', attributes: [], childNodes: [] }],
    } as any;
    expect(isValid(el)).toBe(false);
  });

  it('invalid script elm', () => {
    const el = { nodeType: 1, nodeName: 'script', attributes: [], childNodes: [] } as any;
    expect(isValid(el)).toBe(false);
  });

  it('is valid circle elm', () => {
    const el = { nodeType: 1, nodeName: 'circle', attributes: [], childNodes: [] } as any;
    expect(isValid(el)).toBe(true);
  });

  it('is valid SVG elm', () => {
    const el = {
      nodeType: 1,
      nodeName: 'SVG',
      attributes: [],
      childNodes: [{ nodeType: 1, nodeName: 'line', attributes: [], childNodes: [] }],
    } as any;
    expect(isValid(el)).toBe(true);
  });

  it('is valid text node', () => {
    const el = { nodeType: 3, nodeName: '#text' } as any;
    expect(isValid(el)).toBe(true);
  });
});

it('isSvgDataUrl', () => {
  expect(isSvgDataUrl('data:image/svg+xml;base64,xxx')).toBe(true);
  expect(isSvgDataUrl('data:image/svg+xml;utf8,<svg></svg>')).toBe(true);
  expect(isSvgDataUrl('https://example.com/icon.svg')).toBe(false);
  expect(isSvgDataUrl('http://example.com/icon.svg')).toBe(false);
});

it('isEncodedDataUrl', () => {
  expect(isEncodedDataUrl('data:image/svg+xml;base64,xxx')).toBe(false);
  expect(isEncodedDataUrl('data:image/svg+xml;utf8,<svg></svg>')).toBe(true);
  expect(isEncodedDataUrl('https://example.com/icon.svg')).toBe(false);
  expect(isEncodedDataUrl('http://example.com/icon.svg')).toBe(false);
});


================================================
FILE: src/components/icon/utils.ts
================================================
import { getAssetPath } from '@stencil/core';
import { Icon } from './icon';

let CACHED_MAP: Map<string, string>;

export const getIconMap = (): Map<string, string> => {
  if (typeof window === 'undefined') {
    return new Map();
  } else {
    if (!CACHED_MAP) {
      const win = window as any;
      win.Ionicons = win.Ionicons || {};
      CACHED_MAP = win.Ionicons.map = win.Ionicons.map || new Map();
    }
    return CACHED_MAP;
  }
};

export const addIcons = (icons: { [name: string]: string }) => {
  Object.keys(icons).forEach((name) => {
    addToIconMap(name, icons[name]);

    /**
     * Developers can also pass in the SVG object directly
     * and Ionicons can map the object to a kebab case name.
     * Example: addIcons({ addCircleOutline });
     * This will create an "addCircleOutline" entry and
     * an "add-circle-outline" entry.
     * Usage: <ion-icon name="add-circle-outline"></ion-icon>
     * Using name="addCircleOutline" is valid too, but the
     * kebab case naming is preferred.
     */
    const toKebabCase = name.replace(/([a-z0-9]|(?=[A-Z]))([A-Z0-9])/g, '$1-$2').toLowerCase();
    if (name !== toKebabCase) {
      addToIconMap(toKebabCase, icons[name]);
    }
  });
};

const addToIconMap = (name: string, data: any) => {
  const map = getIconMap();

  const existingIcon = map.get(name);

  if (existingIcon === undefined) {
    map.set(name, data);

    /**
     * Importing and defining the same icon reference
     * multiple times should not yield a warning.
     */
  } else if (existingIcon !== data) {
    console.warn(
      `[Ionicons Warning]: Multiple icons were mapped to name "${name}". Ensure that multiple icons are not mapped to the same icon name.`,
    );
  }
};

export const getUrl = (i: Icon) => {
  let url = getSrc(i.src);
  if (url) {
    return url;
  }

  url = getName(i.name, i.icon, i.mode, i.ios, i.md);
  if (url) {
    return getNamedUrl(url, i);
  }

  if (i.icon) {
    url = getSrc(i.icon);
    if (url) {
      return url;
    }

    url = getSrc(i.icon[i.mode]);
    if (url) {
      return url;
    }
  }

  return null;
};

const getNamedUrl = (iconName: string, iconEl: Icon) => {
  const url = getIconMap().get(iconName);
  if (url) {
    return url;
  }
  try {
    return getAssetPath(`svg/${iconName}.svg`);
  } catch (e) {
    console.log('e', e);
    /**
     * In the custom elements build version of ionicons, referencing an icon
     * by name will throw an invalid URL error because the asset path is not defined.
     * This catches that error and logs something that is more developer-friendly.
     * We also include a reference to the ion-icon element so developers can
     * figure out which instance of ion-icon needs to be updated.
     */
    console.warn(
      `[Ionicons Warning]: Could not load icon with name "${iconName}". Ensure that the icon is registered using addIcons or that the icon SVG data is passed directly to the icon component.`,
      iconEl,
    );
  }
};

export const getName = (
  iconName: string | undefined,
  icon: string | undefined,
  mode: string | undefined,
  ios: string | undefined,
  md: string | undefined,
) => {
  // default to "md" if somehow the mode wasn't set
  mode = (mode && toLower(mode)) === 'ios' ? 'ios' : 'md';

  // if an icon was passed in using the ios or md attributes
  // set the iconName to whatever was passed in
  if (ios && mode === 'ios') {
    iconName = toLower(ios);
  } else if (md && mode === 'md') {
    iconName = toLower(md);
  } else {
    if (!iconName && icon && !isSrc(icon)) {
      iconName = icon;
    }
    if (isStr(iconName)) {
      iconName = toLower(iconName);
    }
  }

  if (!isStr(iconName) || iconName.trim() === '') {
    return null;
  }

  // only allow alpha characters and dash
  const invalidChars = iconName.replace(/[a-z]|-|\d/gi, '');
  if (invalidChars !== '') {
    return null;
  }

  return iconName;
};

export const getSrc = (src: string | undefined) => {
  if (isStr(src)) {
    src = src.trim();
    if (isSrc(src)) {
      return src;
    }
  }
  return null;
};

export const isSrc = (str: string) => str.length > 0 && /(\/|\.)/.test(str);

export const isStr = (val: any): val is string => typeof val === 'string';

export const toLower = (val: string) => val.toLowerCase();

/**
 * Elements inside of web components sometimes need to inherit global attributes
 * set on the host. For example, the inner input in `ion-input` should inherit
 * the `title` attribute that developers set directly on `ion-input`. This
 * helper function should be called in componentWillLoad and assigned to a variable
 * that is later used in the render function.
 *
 * This does not need to be reactive as changing attributes on the host element
 * does not trigger a re-render.
 */
export const inheritAttributes = (el: HTMLElement, attributes: string[] = []) => {
  const attributeObject: { [k: string]: any } = {};

  attributes.forEach((attr) => {
    if (el.hasAttribute(attr)) {
      const value = el.getAttribute(attr);
      if (value !== null) {
        attributeObject[attr] = el.getAttribute(attr);
      }
      el.removeAttribute(attr);
    }
  });

  return attributeObject;
};

/**
 * Returns `true` if the document or host element
 * has a `dir` set to `rtl`. The host value will always
 * take priority over the root document value.
 */
export const isRTL = (hostEl?: Pick<HTMLElement, 'dir'>) => {
  if (hostEl) {
    if (hostEl.dir !== '') {
      return hostEl.dir.toLowerCase() === 'rtl';
    }
  }
  return document?.dir.toLowerCase() === 'rtl';
};


================================================
FILE: src/components/icon/validate.ts
================================================
import { isStr } from './utils';

export const validateContent = (svgContent: string) => {
  const div = document.createElement('div');
  div.innerHTML = svgContent;

  // setup this way to ensure it works on our buddy IE
  for (let i = div.childNodes.length - 1; i >= 0; i--) {
    if (div.childNodes[i].nodeName.toLowerCase() !== 'svg') {
      div.removeChild(div.childNodes[i]);
    }
  }

  // must only have 1 root element
  const svgElm = div.firstElementChild;
  if (svgElm && svgElm.nodeName.toLowerCase() === 'svg') {
    const svgClass = svgElm.getAttribute('class') || '';
    svgElm.setAttribute('class', (svgClass + ' s-ion-icon').trim());

    // root element must be an svg
    // lets double check we've got valid elements
    // do not allow scripts
    if (isValid(svgElm as any)) {
      return div.innerHTML;
    }
  }
  return '';
};

export const isValid = (elm: HTMLElement) => {
  if (elm.nodeType === 1) {
    if (elm.nodeName.toLowerCase() === 'script') {
      return false;
    }

    for (let i = 0; i < elm.attributes.length; i++) {
      const name = elm.attributes[i].name;
      if (isStr(name) && name.toLowerCase().indexOf('on') === 0) {
        return false;
      }
    }

    for (let i = 0; i < elm.childNodes.length; i++) {
      if (!isValid(elm.childNodes[i] as any)) {
        return false;
      }
    }
  }
  return true;
};

export const isSvgDataUrl = (url: string) => url.startsWith('data:image/svg+xml');
export const isEncodedDataUrl = (url: string) => url.indexOf(';utf8,') !== -1;


================================================
FILE: src/components/test/csp/icon.e2e.ts
================================================
import { expect } from '@playwright/test';
import { test } from '../../../utils/test/playwright';

test.describe('icon: csp', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/test/csp');
  });

  test('should load svg', async ({ page }) => {
    const svg = page.locator('ion-icon#icon-usage svg');
    await expect(svg).toBeVisible();
  });
});


================================================
FILE: src/components/test/csp/index.html
================================================
<!DOCTYPE html>
<html dir="ltr" lang="en" mode="ios">

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0" />
  <meta http-equiv="Content-Security-Policy"
    content="default-src 'none'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com/*; img-src 'self'; connect-src 'self'; font-src https://fonts.gstatic.com/*'">
  <title>IonIcon - Content Security Policy</title>
  <script type="module" src="../../build/ionicons.esm.js"></script>
  <script nomodule src="../../build/ionicons.js"></script>
  <style>
    body {
      margin: 0;
      padding: 16px;
      font-size: 32px;
      font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
    }

    h1 {
      margin: 15px 0 5px;
      font-size: 25px;
    }

    h2 {
      margin: 15px 0 5px;
      font-size: 18px;
    }

    .custom {
      stroke: red;
      fill: goldenrod;
      color: black;
    }
  </style>
</head>

<body>
  <h1>Ionicons - Test </h1>

  <h2>Default</h2>
  <ion-icon src="/assets/chat.svg"></ion-icon>
  <ion-icon name="add"></ion-icon>

  <ion-icon id="icon-usage"
    icon="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' class='ionicon' viewBox='0 0 512 512'><title>Watch</title><rect x='136' y='136' width='240' height='240' rx='8' ry='8'/><path d='M384 96h-48V16H176v80h-48a32 32 0 00-32 32v256a32 32 0 0032 32h48v80h160v-80h48a32 32 0 0032-32V128a32 32 0 00-32-32zm8 272a24 24 0 01-24 24H144a24 24 0 01-24-24V144a24 24 0 0124-24h224a24 24 0 0124 24z'/></svg>">
  </ion-icon>

  <ion-icon class="custom"
    icon="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' class='ionicon' viewBox='0 0 512 512'><title>Watch</title><rect x='136' y='136' width='240' height='240' rx='8' ry='8'/><path d='M384 96h-48V16H176v80h-48a32 32 0 00-32 32v256a32 32 0 0032 32h48v80h160v-80h48a32 32 0 0032-32V128a32 32 0 00-32-32zm8 272a24 24 0 01-24 24H144a24 24 0 01-24-24V144a24 24 0 0124-24h224a24 24 0 0124 24z'/></svg>">
  </ion-icon>
</body>

</html>

================================================
FILE: src/components/test/dynamic-type/icon.e2e.ts
================================================
import { expect } from '@playwright/test';
import { test } from '../../../utils/test/playwright';

test.describe('icon: dynamic type', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/test/dynamic-type');
  });

  test('should scale text on larger font sizes', async ({ page }) => {
    // Wait for all SVGs to be lazily loaded before taking screenshots
    await page.waitForLoadState('networkidle');

    const icons = page.locator('#icons');

    await expect(icons).toHaveScreenshot(`icon-dynamic-type-diff.png`);
  });
});


================================================
FILE: src/components/test/dynamic-type/index.html
================================================
<!DOCTYPE html>
<html dir="ltr" lang="en" mode="ios">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0" />
    <meta
      http-equiv="Content-Security-Policy"
      content="default-src 'none'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com/*; img-src 'self'; connect-src 'self'; font-src https://fonts.gstatic.com/*'"
    />
    <title>IonIcon - Dynamic Type</title>
    <script type="module" src="../../build/ionicons.esm.js"></script>
    <script nomodule src="../../build/ionicons.js"></script>
    <style>
      html {
        font-size: 28px;
      }
    </style>
  </head>

  <body>
    <div id="icons">
      <ion-icon name="star"></ion-icon>
      <ion-icon name="star" size="small"></ion-icon>
      <ion-icon name="star" size="large"></ion-icon>
    </div>
  </body>
</html>


================================================
FILE: src/components.d.ts
================================================
/* eslint-disable */
/* tslint:disable */
/**
 * This is an autogenerated file created by the Stencil compiler.
 * It contains typing information for all components that exist in this project.
 */
import { HTMLStencilElement, JSXBase } from '@stencil/core/internal';
export namespace Components {
  interface IonIcon {
    /**
     * The color to use for the background of the item.
     */
    color?: string;
    /**
     * Specifies whether the icon should horizontally flip when `dir` is `"rtl"`.
     */
    flipRtl?: boolean;
    /**
     * A combination of both `name` and `src`. If a `src` url is detected it will set the `src` property. Otherwise it assumes it's a built-in named SVG and set the `name` property.
     */
    icon?: any;
    /**
     * Specifies which icon to use on `ios` mode.
     */
    ios?: string;
    /**
     * If enabled, ion-icon will be loaded lazily when it's visible in the viewport. Default, `false`.
     * @default false
     */
    lazy: boolean;
    /**
     * Specifies which icon to use on `md` mode.
     */
    md?: string;
    /**
     * The mode determines which platform styles to use.
     * @default getIonMode()
     */
    mode: string;
    /**
     * Specifies which icon to use from the built-in set of icons.
     */
    name?: string;
    /**
     * When set to `false`, SVG content that is HTTP fetched will not be checked if the response SVG content has any `<script>` elements, or any attributes that start with `on`, such as `onclick`.
     * @default true
     */
    sanitize: boolean;
    /**
     * The size of the icon. Available options are: `"small"` and `"large"`.
     */
    size?: string;
    /**
     * Specifies the exact `src` of an SVG file to use.
     */
    src?: string;
  }
}
declare global {
  interface HTMLIonIconElement extends Components.IonIcon, HTMLStencilElement {}
  var HTMLIonIconElement: {
    prototype: HTMLIonIconElement;
    new (): HTMLIonIconElement;
  };
  interface HTMLElementTagNameMap {
    'ion-icon': HTMLIonIconElement;
  }
}
declare namespace LocalJSX {
  interface IonIcon {
    /**
     * The color to use for the background of the item.
     */
    color?: string;
    /**
     * Specifies whether the icon should horizontally flip when `dir` is `"rtl"`.
     */
    flipRtl?: boolean;
    /**
     * A combination of both `name` and `src`. If a `src` url is detected it will set the `src` property. Otherwise it assumes it's a built-in named SVG and set the `name` property.
     */
    icon?: any;
    /**
     * Specifies which icon to use on `ios` mode.
     */
    ios?: string;
    /**
     * If enabled, ion-icon will be loaded lazily when it's visible in the viewport. Default, `false`.
     * @default false
     */
    lazy?: boolean;
    /**
     * Specifies which icon to use on `md` mode.
     */
    md?: string;
    /**
     * The mode determines which platform styles to use.
     * @default getIonMode()
     */
    mode?: string;
    /**
     * Specifies which icon to use from the built-in set of icons.
     */
    name?: string;
    /**
     * When set to `false`, SVG content that is HTTP fetched will not be checked if the response SVG content has any `<script>` elements, or any attributes that start with `on`, such as `onclick`.
     * @default true
     */
    sanitize?: boolean;
    /**
     * The size of the icon. Available options are: `"small"` and `"large"`.
     */
    size?: string;
    /**
     * Specifies the exact `src` of an SVG file to use.
     */
    src?: string;
  }
  interface IntrinsicElements {
    'ion-icon': IonIcon;
  }
}
export { LocalJSX as JSX };
declare module '@stencil/core' {
  export namespace JSX {
    interface IntrinsicElements {
      'ion-icon': LocalJSX.IonIcon & JSXBase.HTMLAttributes<HTMLIonIconElement>;
    }
  }
}


================================================
FILE: src/data.json
================================================
{
  "icons": [
    {
      "name": "accessibility",
      "tags": [
        "accessibility"
      ]
    },
    {
      "name": "accessibility-outline",
      "tags": [
        "accessibility",
        "outline"
      ]
    },
    {
      "name": "accessibility-sharp",
      "tags": [
        "accessibility",
        "sharp"
      ]
    },
    {
      "name": "add",
      "tags": [
        "add",
        "circle",
        "include",
        "invite",
        "plus"
      ]
    },
    {
      "name": "add-circle",
      "tags": [
        "add",
        "circle",
        "include",
        "invite",
        "plus"
      ]
    },
    {
      "name": "add-circle-outline",
      "tags": [
        "add",
        "circle",
        "include",
        "invite",
        "outline",
        "plus"
      ]
    },
    {
      "name": "add-circle-sharp",
      "tags": [
        "add",
        "circle",
        "include",
        "invite",
        "plus",
        "sharp"
      ]
    },
    {
      "name": "add-outline",
      "tags": [
        "add",
        "outline"
      ]
    },
    {
      "name": "add-sharp",
      "tags": [
        "add",
        "circle",
        "include",
        "invite",
        "plus",
        "sharp"
      ]
    },
    {
      "name": "airplane",
      "tags": [
        "airplane",
        "plane"
      ]
    },
    {
      "name": "airplane-outline",
      "tags": [
        "airplane",
        "outline",
        "plane"
      ]
    },
    {
      "name": "airplane-sharp",
      "tags": [
        "airplane",
        "plane",
        "sharp"
      ]
    },
    {
      "name": "alarm",
      "tags": [
        "alarm",
        "clock",
        "time"
      ]
    },
    {
      "name": "alarm-outline",
      "tags": [
        "alarm",
        "clock",
        "outline",
        "time"
      ]
    },
    {
      "name": "alarm-sharp",
      "tags": [
        "alarm",
        "clock",
        "sharp",
        "time"
      ]
    },
    {
      "name": "albums",
      "tags": [
        "albums",
        "boxes",
        "slides",
        "square"
      ]
    },
    {
      "name": "albums-outline",
      "tags": [
        "albums",
        "boxes",
        "outline",
        "slides",
        "square"
      ]
    },
    {
      "name": "albums-sharp",
      "tags": [
        "albums",
        "boxes",
        "sharp",
        "slides",
        "square"
      ]
    },
    {
      "name": "alert",
      "tags": [
        "!",
        "alert",
        "attention",
        "exclamation",
        "notice",
        "warning"
      ]
    },
    {
      "name": "alert-circle",
      "tags": [
        "!",
        "alert",
        "attention",
        "circle",
        "exclamation",
        "notice",
        "warning"
      ]
    },
    {
      "name": "alert-circle-outline",
      "tags": [
        "!",
        "alert",
        "attention",
        "circle",
        "exclamation",
        "notice",
        "outline",
        "warning"
      ]
    },
    {
      "name": "alert-circle-sharp",
      "tags": [
        "!",
        "alert",
        "attention",
        "circle",
        "exclamation",
        "notice",
        "sharp",
        "warning"
      ]
    },
    {
      "name": "alert-outline",
      "tags": [
        "alert",
        "outline"
      ]
    },
    {
      "name": "alert-sharp",
      "tags": [
        "!",
        "alert",
        "attention",
        "exclamation",
        "notice",
        "sharp",
        "warning"
      ]
    },
    {
      "name": "american-football",
      "tags": [
        "american",
        "football"
      ]
    },
    {
      "name": "american-football-outline",
      "tags": [
        "american",
        "football",
        "outline"
      ]
    },
    {
      "name": "american-football-sharp",
      "tags": [
        "american",
        "football",
        "sharp"
      ]
    },
    {
      "name": "analytics",
      "tags": [
        "analytics",
        "data",
        "metrics",
        "track"
      ]
    },
    {
      "name": "analytics-outline",
      "tags": [
        "analytics",
        "data",
        "metrics",
        "outline",
        "track"
      ]
    },
    {
      "name": "analytics-sharp",
      "tags": [
        "analytics",
        "data",
        "metrics",
        "sharp",
        "track"
      ]
    },
    {
      "name": "aperture",
      "tags": [
        "aperture",
        "dark",
        "images",
        "levels",
        "light",
        "settings"
      ]
    },
    {
      "name": "aperture-outline",
      "tags": [
        "aperture",
        "dark",
        "images",
        "levels",
        "light",
        "outline",
        "settings"
      ]
    },
    {
      "name": "aperture-sharp",
      "tags": [
        "aperture",
        "dark",
        "images",
        "levels",
        "light",
        "settings",
        "sharp"
      ]
    },
    {
      "name": "apps",
      "tags": [
        "applications",
        "apps"
      ]
    },
    {
      "name": "apps-outline",
      "tags": [
        "applications",
        "apps",
        "outline"
      ]
    },
    {
      "name": "apps-sharp",
      "tags": [
        "applications",
        "apps",
        "sharp"
      ]
    },
    {
      "name": "archive",
      "tags": [
        "archive",
        "email"
      ]
    },
    {
      "name": "archive-outline",
      "tags": [
        "archive",
        "email",
        "outline"
      ]
    },
    {
      "name": "archive-sharp",
      "tags": [
        "archive",
        "email",
        "sharp"
      ]
    },
    {
      "name": "arrow-back",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "left",
        "navigation"
      ]
    },
    {
      "name": "arrow-back-circle",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "circle",
        "left",
        "navigation"
      ]
    },
    {
      "name": "arrow-back-circle-outline",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "circle",
        "left",
        "navigation",
        "outline"
      ]
    },
    {
      "name": "arrow-back-circle-sharp",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "circle",
        "navigation",
        "sharp"
      ]
    },
    {
      "name": "arrow-back-outline",
      "tags": [
        "arrow",
        "back",
        "left",
        "outline"
      ]
    },
    {
      "name": "arrow-back-sharp",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "left",
        "navigation",
        "sharp"
      ]
    },
    {
      "name": "arrow-down",
      "tags": [
        "arrow",
        "chevron",
        "down"
      ]
    },
    {
      "name": "arrow-down-circle",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "down"
      ]
    },
    {
      "name": "arrow-down-circle-outline",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "down",
        "outline"
      ]
    },
    {
      "name": "arrow-down-circle-sharp",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "down",
        "sharp"
      ]
    },
    {
      "name": "arrow-down-left-box",
      "tags": [
        "arrow",
        "box",
        "down",
        "left"
      ]
    },
    {
      "name": "arrow-down-left-box-outline",
      "tags": [
        "arrow",
        "box",
        "down",
        "left",
        "outline"
      ]
    },
    {
      "name": "arrow-down-left-box-sharp",
      "tags": [
        "arrow",
        "box",
        "down",
        "left",
        "sharp"
      ]
    },
    {
      "name": "arrow-down-outline",
      "tags": [
        "arrow",
        "down",
        "outline"
      ]
    },
    {
      "name": "arrow-down-right-box",
      "tags": [
        "arrow",
        "box",
        "down",
        "right"
      ]
    },
    {
      "name": "arrow-down-right-box-outline",
      "tags": [
        "arrow",
        "box",
        "down",
        "outline",
        "right"
      ]
    },
    {
      "name": "arrow-down-right-box-sharp",
      "tags": [
        "arrow",
        "box",
        "down",
        "right",
        "sharp"
      ]
    },
    {
      "name": "arrow-down-sharp",
      "tags": [
        "arrow",
        "chevron",
        "down",
        "sharp"
      ]
    },
    {
      "name": "arrow-forward",
      "tags": [
        "arrow",
        "chevron",
        "forward",
        "navigation",
        "right"
      ]
    },
    {
      "name": "arrow-forward-circle",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "forward",
        "navigation",
        "right"
      ]
    },
    {
      "name": "arrow-forward-circle-outline",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "forward",
        "navigation",
        "outline",
        "right"
      ]
    },
    {
      "name": "arrow-forward-circle-sharp",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "forward",
        "navigation",
        "right",
        "sharp"
      ]
    },
    {
      "name": "arrow-forward-outline",
      "tags": [
        "arrow",
        "forward",
        "outline",
        "right"
      ]
    },
    {
      "name": "arrow-forward-sharp",
      "tags": [
        "arrow",
        "chevron",
        "forward",
        "navigation",
        "right",
        "sharp"
      ]
    },
    {
      "name": "arrow-redo",
      "tags": [
        "arrow",
        "redo"
      ]
    },
    {
      "name": "arrow-redo-circle",
      "tags": [
        "arrow",
        "circle",
        "redo"
      ]
    },
    {
      "name": "arrow-redo-circle-outline",
      "tags": [
        "arrow",
        "circle",
        "outline",
        "redo"
      ]
    },
    {
      "name": "arrow-redo-circle-sharp",
      "tags": [
        "arrow",
        "circle",
        "redo",
        "sharp"
      ]
    },
    {
      "name": "arrow-redo-outline",
      "tags": [
        "arrow",
        "outline",
        "redo"
      ]
    },
    {
      "name": "arrow-redo-sharp",
      "tags": [
        "arrow",
        "redo",
        "sharp"
      ]
    },
    {
      "name": "arrow-undo",
      "tags": [
        "arrow",
        "undo"
      ]
    },
    {
      "name": "arrow-undo-circle",
      "tags": [
        "arrow",
        "circle",
        "undo"
      ]
    },
    {
      "name": "arrow-undo-circle-outline",
      "tags": [
        "arrow",
        "circle",
        "outline",
        "undo"
      ]
    },
    {
      "name": "arrow-undo-circle-sharp",
      "tags": [
        "arrow",
        "circle",
        "sharp",
        "undo"
      ]
    },
    {
      "name": "arrow-undo-outline",
      "tags": [
        "arrow",
        "outline",
        "undo"
      ]
    },
    {
      "name": "arrow-undo-sharp",
      "tags": [
        "arrow",
        "sharp",
        "undo"
      ]
    },
    {
      "name": "arrow-up",
      "tags": [
        "arrow",
        "chevron",
        "up"
      ]
    },
    {
      "name": "arrow-up-circle",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "up"
      ]
    },
    {
      "name": "arrow-up-circle-outline",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "outline",
        "up"
      ]
    },
    {
      "name": "arrow-up-circle-sharp",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "sharp",
        "up"
      ]
    },
    {
      "name": "arrow-up-left-box",
      "tags": [
        "arrow",
        "box",
        "left",
        "up"
      ]
    },
    {
      "name": "arrow-up-left-box-outline",
      "tags": [
        "arrow",
        "box",
        "left",
        "outline",
        "up"
      ]
    },
    {
      "name": "arrow-up-left-box-sharp",
      "tags": [
        "arrow",
        "box",
        "left",
        "sharp",
        "up"
      ]
    },
    {
      "name": "arrow-up-outline",
      "tags": [
        "arrow",
        "outline",
        "up"
      ]
    },
    {
      "name": "arrow-up-right-box",
      "tags": [
        "arrow",
        "box",
        "right",
        "up"
      ]
    },
    {
      "name": "arrow-up-right-box-outline",
      "tags": [
        "arrow",
        "box",
        "outline",
        "right",
        "up"
      ]
    },
    {
      "name": "arrow-up-right-box-sharp",
      "tags": [
        "arrow",
        "box",
        "right",
        "sharp",
        "up"
      ]
    },
    {
      "name": "arrow-up-sharp",
      "tags": [
        "arrow",
        "chevron",
        "sharp",
        "up"
      ]
    },
    {
      "name": "at",
      "tags": [
        "@",
        "at"
      ]
    },
    {
      "name": "at-circle",
      "tags": [
        "@",
        "at",
        "circle"
      ]
    },
    {
      "name": "at-circle-outline",
      "tags": [
        "@",
        "at",
        "circle",
        "outline"
      ]
    },
    {
      "name": "at-circle-sharp",
      "tags": [
        "@",
        "at",
        "circle",
        "sharp"
      ]
    },
    {
      "name": "at-outline",
      "tags": [
        "at",
        "outline"
      ]
    },
    {
      "name": "at-sharp",
      "tags": [
        "@",
        "at",
        "sharp"
      ]
    },
    {
      "name": "attach",
      "tags": [
        "attach"
      ]
    },
    {
      "name": "attach-outline",
      "tags": [
        "attach",
        "outline"
      ]
    },
    {
      "name": "attach-sharp",
      "tags": [
        "attach",
        "sharp"
      ]
    },
    {
      "name": "backspace",
      "tags": [
        "backspace"
      ]
    },
    {
      "name": "backspace-outline",
      "tags": [
        "backspace",
        "outline"
      ]
    },
    {
      "name": "backspace-sharp",
      "tags": [
        "backspace",
        "sharp"
      ]
    },
    {
      "name": "bag",
      "tags": [
        "bag"
      ]
    },
    {
      "name": "bag-add",
      "tags": [
        "add",
        "bag"
      ]
    },
    {
      "name": "bag-add-outline",
      "tags": [
        "add",
        "bag",
        "outline"
      ]
    },
    {
      "name": "bag-add-sharp",
      "tags": [
        "add",
        "bag",
        "sharp"
      ]
    },
    {
      "name": "bag-check",
      "tags": [
        "bag",
        "check"
      ]
    },
    {
      "name": "bag-check-outline",
      "tags": [
        "bag",
        "check",
        "outline"
      ]
    },
    {
      "name": "bag-check-sharp",
      "tags": [
        "bag",
        "check",
        "sharp"
      ]
    },
    {
      "name": "bag-handle",
      "tags": [
        "bag",
        "handle"
      ]
    },
    {
      "name": "bag-handle-outline",
      "tags": [
        "bag",
        "handle",
        "outline"
      ]
    },
    {
      "name": "bag-handle-sharp",
      "tags": [
        "bag",
        "handle",
        "sharp"
      ]
    },
    {
      "name": "bag-outline",
      "tags": [
        "bag",
        "outline"
      ]
    },
    {
      "name": "bag-remove",
      "tags": [
        "bag",
        "remove"
      ]
    },
    {
      "name": "bag-remove-outline",
      "tags": [
        "bag",
        "outline",
        "remove"
      ]
    },
    {
      "name": "bag-remove-sharp",
      "tags": [
        "bag",
        "remove",
        "sharp"
      ]
    },
    {
      "name": "bag-sharp",
      "tags": [
        "bag",
        "sharp"
      ]
    },
    {
      "name": "balloon",
      "tags": [
        "balloon"
      ]
    },
    {
      "name": "balloon-outline",
      "tags": [
        "balloon",
        "outline"
      ]
    },
    {
      "name": "balloon-sharp",
      "tags": [
        "balloon",
        "sharp"
      ]
    },
    {
      "name": "ban",
      "tags": [
        "ban"
      ]
    },
    {
      "name": "ban-outline",
      "tags": [
        "ban",
        "outline"
      ]
    },
    {
      "name": "ban-sharp",
      "tags": [
        "ban",
        "sharp"
      ]
    },
    {
      "name": "bandage",
      "tags": [
        "bandage"
      ]
    },
    {
      "name": "bandage-outline",
      "tags": [
        "bandage",
        "outline"
      ]
    },
    {
      "name": "bandage-sharp",
      "tags": [
        "bandage",
        "sharp"
      ]
    },
    {
      "name": "bar-chart",
      "tags": [
        "bar",
        "chart"
      ]
    },
    {
      "name": "bar-chart-outline",
      "tags": [
        "bar",
        "chart",
        "outline"
      ]
    },
    {
      "name": "bar-chart-sharp",
      "tags": [
        "bar",
        "chart",
        "sharp"
      ]
    },
    {
      "name": "barbell",
      "tags": [
        "barbell",
        "exercise",
        "lifting",
        "weight"
      ]
    },
    {
      "name": "barbell-outline",
      "tags": [
        "barbell",
        "exercise",
        "lifting",
        "outline",
        "weight"
      ]
    },
    {
      "name": "barbell-sharp",
      "tags": [
        "barbell",
        "exercise",
        "lifting",
        "sharp",
        "weight"
      ]
    },
    {
      "name": "barcode",
      "tags": [
        "barcode",
        "camera",
        "reader"
      ]
    },
    {
      "name": "barcode-outline",
      "tags": [
        "barcode",
        "camera",
        "outline",
        "reader"
      ]
    },
    {
      "name": "barcode-sharp",
      "tags": [
        "barcode",
        "camera",
        "reader",
        "sharp"
      ]
    },
    {
      "name": "baseball",
      "tags": [
        "baseball"
      ]
    },
    {
      "name": "baseball-outline",
      "tags": [
        "baseball",
        "outline"
      ]
    },
    {
      "name": "baseball-sharp",
      "tags": [
        "baseball",
        "sharp"
      ]
    },
    {
      "name": "basket",
      "tags": [
        "basket"
      ]
    },
    {
      "name": "basket-outline",
      "tags": [
        "basket",
        "outline"
      ]
    },
    {
      "name": "basket-sharp",
      "tags": [
        "basket",
        "sharp"
      ]
    },
    {
      "name": "basketball",
      "tags": [
        "basketball"
      ]
    },
    {
      "name": "basketball-outline",
      "tags": [
        "basketball",
        "outline"
      ]
    },
    {
      "name": "basketball-sharp",
      "tags": [
        "basketball",
        "sharp"
      ]
    },
    {
      "name": "battery-charging",
      "tags": [
        "battery",
        "charging"
      ]
    },
    {
      "name": "battery-charging-outline",
      "tags": [
        "battery",
        "charging",
        "outline"
      ]
    },
    {
      "name": "battery-charging-sharp",
      "tags": [
        "battery",
        "charging",
        "sharp"
      ]
    },
    {
      "name": "battery-dead",
      "tags": [
        "battery",
        "dead"
      ]
    },
    {
      "name": "battery-dead-outline",
      "tags": [
        "battery",
        "dead",
        "outline"
      ]
    },
    {
      "name": "battery-dead-sharp",
      "tags": [
        "battery",
        "dead",
        "sharp"
      ]
    },
    {
      "name": "battery-full",
      "tags": [
        "battery",
        "full"
      ]
    },
    {
      "name": "battery-full-outline",
      "tags": [
        "battery",
        "full",
        "outline"
      ]
    },
    {
      "name": "battery-full-sharp",
      "tags": [
        "battery",
        "full",
        "sharp"
      ]
    },
    {
      "name": "battery-half",
      "tags": [
        "battery",
        "half"
      ]
    },
    {
      "name": "battery-half-outline",
      "tags": [
        "battery",
        "half",
        "outline"
      ]
    },
    {
      "name": "battery-half-sharp",
      "tags": [
        "battery",
        "half",
        "sharp"
      ]
    },
    {
      "name": "beaker",
      "tags": [
        "beaker",
        "flask",
        "mixture",
        "potion"
      ]
    },
    {
      "name": "beaker-outline",
      "tags": [
        "beaker",
        "flask",
        "mixture",
        "outline",
        "potion"
      ]
    },
    {
      "name": "beaker-sharp",
      "tags": [
        "beaker",
        "flask",
        "mixture",
        "potion",
        "sharp"
      ]
    },
    {
      "name": "bed",
      "tags": [
        "bed",
        "hotel",
        "loveseat",
        "sleep"
      ]
    },
    {
      "name": "bed-outline",
      "tags": [
        "bed",
        "hotel",
        "loveseat",
        "outline",
        "sleep"
      ]
    },
    {
      "name": "bed-sharp",
      "tags": [
        "bed",
        "hotel",
        "loveseat",
        "sharp",
        "sleep"
      ]
    },
    {
      "name": "beer",
      "tags": [
        "beer",
        "drink",
        "eat",
        "food"
      ]
    },
    {
      "name": "beer-outline",
      "tags": [
        "beer",
        "drink",
        "eat",
        "food",
        "outline"
      ]
    },
    {
      "name": "beer-sharp",
      "tags": [
        "beer",
        "drink",
        "eat",
        "food",
        "sharp"
      ]
    },
    {
      "name": "bicycle",
      "tags": [
        "bicycle",
        "bike",
        "exercise"
      ]
    },
    {
      "name": "bicycle-outline",
      "tags": [
        "bicycle",
        "bike",
        "exercise",
        "outline"
      ]
    },
    {
      "name": "bicycle-sharp",
      "tags": [
        "bicycle",
        "bike",
        "exercise",
        "sharp"
      ]
    },
    {
      "name": "binoculars",
      "tags": [
        "binoculars"
      ]
    },
    {
      "name": "binoculars-outline",
      "tags": [
        "binoculars",
        "outline"
      ]
    },
    {
      "name": "binoculars-sharp",
      "tags": [
        "binoculars",
        "sharp"
      ]
    },
    {
      "name": "bluetooth",
      "tags": [
        "bluetooth",
        "cloud",
        "connection"
      ]
    },
    {
      "name": "bluetooth-outline",
      "tags": [
        "bluetooth",
        "cloud",
        "connection",
        "outline"
      ]
    },
    {
      "name": "bluetooth-sharp",
      "tags": [
        "bluetooth",
        "cloud",
        "connection",
        "sharp"
      ]
    },
    {
      "name": "boat",
      "tags": [
        "boat"
      ]
    },
    {
      "name": "boat-outline",
      "tags": [
        "boat",
        "outline"
      ]
    },
    {
      "name": "boat-sharp",
      "tags": [
        "boat",
        "sharp"
      ]
    },
    {
      "name": "body",
      "tags": [
        "body"
      ]
    },
    {
      "name": "body-outline",
      "tags": [
        "body",
        "outline"
      ]
    },
    {
      "name": "body-sharp",
      "tags": [
        "body",
        "sharp"
      ]
    },
    {
      "name": "bonfire",
      "tags": [
        "bonfire",
        "heat",
        "hot"
      ]
    },
    {
      "name": "bonfire-outline",
      "tags": [
        "bonfire",
        "heat",
        "hot",
        "outline"
      ]
    },
    {
      "name": "bonfire-sharp",
      "tags": [
        "bonfire",
        "heat",
        "hot",
        "sharp"
      ]
    },
    {
      "name": "book",
      "tags": [
        "book",
        "read"
      ]
    },
    {
      "name": "book-outline",
      "tags": [
        "book",
        "outline",
        "read"
      ]
    },
    {
      "name": "book-sharp",
      "tags": [
        "book",
        "read",
        "sharp"
      ]
    },
    {
      "name": "bookmark",
      "tags": [
        "bookmark",
        "favorite",
        "save",
        "tag"
      ]
    },
    {
      "name": "bookmark-outline",
      "tags": [
        "bookmark",
        "favorite",
        "outline",
        "save",
        "tag"
      ]
    },
    {
      "name": "bookmark-sharp",
      "tags": [
        "bookmark",
        "favorite",
        "save",
        "sharp",
        "tag"
      ]
    },
    {
      "name": "bookmarks",
      "tags": [
        "bookmarks",
        "favorite"
      ]
    },
    {
      "name": "bookmarks-outline",
      "tags": [
        "bookmarks",
        "favorite",
        "outline"
      ]
    },
    {
      "name": "bookmarks-sharp",
      "tags": [
        "bookmarks",
        "favorite",
        "sharp"
      ]
    },
    {
      "name": "bowling-ball",
      "tags": [
        "ball",
        "bowling"
      ]
    },
    {
      "name": "bowling-ball-outline",
      "tags": [
        "ball",
        "bowling",
        "outline"
      ]
    },
    {
      "name": "bowling-ball-sharp",
      "tags": [
        "ball",
        "bowling",
        "sharp"
      ]
    },
    {
      "name": "briefcase",
      "tags": [
        "briefcase",
        "folder",
        "organize"
      ]
    },
    {
      "name": "briefcase-outline",
      "tags": [
        "briefcase",
        "folder",
        "organize",
        "outline"
      ]
    },
    {
      "name": "briefcase-sharp",
      "tags": [
        "briefcase",
        "folder",
        "organize",
        "sharp"
      ]
    },
    {
      "name": "browsers",
      "tags": [
        "browsers",
        "square"
      ]
    },
    {
      "name": "browsers-outline",
      "tags": [
        "browsers",
        "outline",
        "square"
      ]
    },
    {
      "name": "browsers-sharp",
      "tags": [
        "browsers",
        "sharp",
        "square"
      ]
    },
    {
      "name": "brush",
      "tags": [
        "brush"
      ]
    },
    {
      "name": "brush-outline",
      "tags": [
        "brush",
        "outline"
      ]
    },
    {
      "name": "brush-sharp",
      "tags": [
        "brush",
        "sharp"
      ]
    },
    {
      "name": "bug",
      "tags": [
        "bug",
        "develop",
        "error",
        "hacker",
        "program"
      ]
    },
    {
      "name": "bug-outline",
      "tags": [
        "bug",
        "develop",
        "error",
        "hacker",
        "outline",
        "program"
      ]
    },
    {
      "name": "bug-sharp",
      "tags": [
        "bug",
        "develop",
        "error",
        "hacker",
        "program",
        "sharp"
      ]
    },
    {
      "name": "build",
      "tags": [
        "build"
      ]
    },
    {
      "name": "build-outline",
      "tags": [
        "build",
        "outline"
      ]
    },
    {
      "name": "build-sharp",
      "tags": [
        "build",
        "sharp"
      ]
    },
    {
      "name": "bulb",
      "tags": [
        "bulb"
      ]
    },
    {
      "name": "bulb-outline",
      "tags": [
        "bulb",
        "outline"
      ]
    },
    {
      "name": "bulb-sharp",
      "tags": [
        "bulb",
        "sharp"
      ]
    },
    {
      "name": "bus",
      "tags": [
        "bus"
      ]
    },
    {
      "name": "bus-outline",
      "tags": [
        "bus",
        "outline"
      ]
    },
    {
      "name": "bus-sharp",
      "tags": [
        "bus",
        "sharp"
      ]
    },
    {
      "name": "business",
      "tags": [
        "business"
      ]
    },
    {
      "name": "business-outline",
      "tags": [
        "business",
        "outline"
      ]
    },
    {
      "name": "business-sharp",
      "tags": [
        "business",
        "sharp"
      ]
    },
    {
      "name": "cafe",
      "tags": [
        "cafe",
        "coffee",
        "cup"
      ]
    },
    {
      "name": "cafe-outline",
      "tags": [
        "cafe",
        "coffee",
        "cup",
        "outline"
      ]
    },
    {
      "name": "cafe-sharp",
      "tags": [
        "cafe",
        "coffee",
        "cup",
        "sharp"
      ]
    },
    {
      "name": "calculator",
      "tags": [
        "arithmetic",
        "calculator",
        "math"
      ]
    },
    {
      "name": "calculator-outline",
      "tags": [
        "arithmetic",
        "calculator",
        "math",
        "outline"
      ]
    },
    {
      "name": "calculator-sharp",
      "tags": [
        "arithmetic",
        "calculator",
        "math",
        "sharp"
      ]
    },
    {
      "name": "calendar",
      "tags": [
        "calendar",
        "date",
        "month",
        "week"
      ]
    },
    {
      "name": "calendar-clear",
      "tags": [
        "calendar",
        "clear"
      ]
    },
    {
      "name": "calendar-clear-outline",
      "tags": [
        "calendar",
        "clear",
        "outline"
      ]
    },
    {
      "name": "calendar-clear-sharp",
      "tags": [
        "calendar",
        "clear",
        "sharp"
      ]
    },
    {
      "name": "calendar-number",
      "tags": [
        "calendar",
        "number"
      ]
    },
    {
      "name": "calendar-number-outline",
      "tags": [
        "calendar",
        "number",
        "outline"
      ]
    },
    {
      "name": "calendar-number-sharp",
      "tags": [
        "calendar",
        "number",
        "sharp"
      ]
    },
    {
      "name": "calendar-outline",
      "tags": [
        "calendar",
        "date",
        "month",
        "outline",
        "week"
      ]
    },
    {
      "name": "calendar-sharp",
      "tags": [
        "calendar",
        "date",
        "month",
        "sharp",
        "week"
      ]
    },
    {
      "name": "call",
      "tags": [
        "call",
        "telephone"
      ]
    },
    {
      "name": "call-outline",
      "tags": [
        "call",
        "outline",
        "telephone"
      ]
    },
    {
      "name": "call-sharp",
      "tags": [
        "call",
        "sharp",
        "telephone"
      ]
    },
    {
      "name": "camera",
      "tags": [
        "camera",
        "image",
        "photo"
      ]
    },
    {
      "name": "camera-outline",
      "tags": [
        "camera",
        "image",
        "outline",
        "photo"
      ]
    },
    {
      "name": "camera-reverse",
      "tags": [
        "camera",
        "reverse"
      ]
    },
    {
      "name": "camera-reverse-outline",
      "tags": [
        "camera",
        "outline",
        "reverse"
      ]
    },
    {
      "name": "camera-reverse-sharp",
      "tags": [
        "camera",
        "reverse",
        "sharp"
      ]
    },
    {
      "name": "camera-sharp",
      "tags": [
        "camera",
        "image",
        "photo",
        "sharp"
      ]
    },
    {
      "name": "car",
      "tags": [
        "car"
      ]
    },
    {
      "name": "car-outline",
      "tags": [
        "car",
        "outline"
      ]
    },
    {
      "name": "car-sharp",
      "tags": [
        "car",
        "sharp"
      ]
    },
    {
      "name": "car-sport",
      "tags": [
        "car",
        "sport"
      ]
    },
    {
      "name": "car-sport-outline",
      "tags": [
        "car",
        "outline",
        "sport"
      ]
    },
    {
      "name": "car-sport-sharp",
      "tags": [
        "car",
        "sharp",
        "sport"
      ]
    },
    {
      "name": "card",
      "tags": [
        "$",
        "card",
        "cash",
        "credit",
        "debit",
        "dollars",
        "money",
        "price",
        "shopping"
      ]
    },
    {
      "name": "card-outline",
      "tags": [
        "$",
        "card",
        "cash",
        "credit",
        "debit",
        "dollars",
        "money",
        "outline",
        "price",
        "shopping"
      ]
    },
    {
      "name": "card-sharp",
      "tags": [
        "$",
        "card",
        "cash",
        "credit",
        "debit",
        "dollars",
        "money",
        "price",
        "sharp",
        "shopping"
      ]
    },
    {
      "name": "caret-back",
      "tags": [
        "arrow",
        "back",
        "caret"
      ]
    },
    {
      "name": "caret-back-circle",
      "tags": [
        "arrow",
        "back",
        "caret",
        "circle"
      ]
    },
    {
      "name": "caret-back-circle-outline",
      "tags": [
        "arrow",
        "back",
        "caret",
        "circle",
        "outline"
      ]
    },
    {
      "name": "caret-back-circle-sharp",
      "tags": [
        "arrow",
        "back",
        "caret",
        "circle",
        "left",
        "sharp"
      ]
    },
    {
      "name": "caret-back-outline",
      "tags": [
        "arrow",
        "back",
        "caret",
        "left",
        "outline"
      ]
    },
    {
      "name": "caret-back-sharp",
      "tags": [
        "arrow",
        "back",
        "caret",
        "left",
        "sharp"
      ]
    },
    {
      "name": "caret-down",
      "tags": [
        "arrow",
        "caret",
        "down"
      ]
    },
    {
      "name": "caret-down-circle",
      "tags": [
        "arrow",
        "caret",
        "circle",
        "down"
      ]
    },
    {
      "name": "caret-down-circle-outline",
      "tags": [
        "arrow",
        "caret",
        "circle",
        "down",
        "outline"
      ]
    },
    {
      "name": "caret-down-circle-sharp",
      "tags": [
        "arrow",
        "caret",
        "circle",
        "down",
        "sharp"
      ]
    },
    {
      "name": "caret-down-outline",
      "tags": [
        "arrow",
        "caret",
        "down",
        "outline"
      ]
    },
    {
      "name": "caret-down-sharp",
      "tags": [
        "arrow",
        "caret",
        "down",
        "sharp"
      ]
    },
    {
      "name": "caret-forward",
      "tags": [
        "arrow",
        "caret",
        "forward",
        "right"
      ]
    },
    {
      "name": "caret-forward-circle",
      "tags": [
        "arrow",
        "caret",
        "circle",
        "forward",
        "right"
      ]
    },
    {
      "name": "caret-forward-circle-outline",
      "tags": [
        "arrow",
        "caret",
        "circle",
        "forward",
        "outline",
        "right"
      ]
    },
    {
      "name": "caret-forward-circle-sharp",
      "tags": [
        "arrow",
        "caret",
        "circle",
        "forward",
        "right",
        "sharp"
      ]
    },
    {
      "name": "caret-forward-outline",
      "tags": [
        "arrow",
        "caret",
        "forward",
        "outline",
        "right"
      ]
    },
    {
      "name": "caret-forward-sharp",
      "tags": [
        "arrow",
        "caret",
        "forward",
        "right",
        "sharp"
      ]
    },
    {
      "name": "caret-up",
      "tags": [
        "arrow",
        "caret",
        "up"
      ]
    },
    {
      "name": "caret-up-circle",
      "tags": [
        "arrow",
        "caret",
        "circle",
        "up"
      ]
    },
    {
      "name": "caret-up-circle-outline",
      "tags": [
        "arrow",
        "caret",
        "circle",
        "outline",
        "up"
      ]
    },
    {
      "name": "caret-up-circle-sharp",
      "tags": [
        "arrow",
        "caret",
        "circle",
        "sharp",
        "up"
      ]
    },
    {
      "name": "caret-up-outline",
      "tags": [
        "arrow",
        "caret",
        "outline",
        "up"
      ]
    },
    {
      "name": "caret-up-sharp",
      "tags": [
        "arrow",
        "caret",
        "sharp",
        "up"
      ]
    },
    {
      "name": "cart",
      "tags": [
        "cart"
      ]
    },
    {
      "name": "cart-outline",
      "tags": [
        "cart",
        "outline"
      ]
    },
    {
      "name": "cart-sharp",
      "tags": [
        "cart",
        "sharp"
      ]
    },
    {
      "name": "cash",
      "tags": [
        "$",
        "cash",
        "credit",
        "debit",
        "dollars",
        "money",
        "price",
        "shopping"
      ]
    },
    {
      "name": "cash-outline",
      "tags": [
        "$",
        "cash",
        "credit",
        "debit",
        "dollars",
        "money",
        "outline",
        "price",
        "shopping"
      ]
    },
    {
      "name": "cash-sharp",
      "tags": [
        "$",
        "cash",
        "credit",
        "debit",
        "dollars",
        "money",
        "price",
        "sharp",
        "shopping"
      ]
    },
    {
      "name": "cellular",
      "tags": [
        "cellular"
      ]
    },
    {
      "name": "cellular-outline",
      "tags": [
        "cellular",
        "outline"
      ]
    },
    {
      "name": "cellular-sharp",
      "tags": [
        "cellular",
        "sharp"
      ]
    },
    {
      "name": "chatbox",
      "tags": [
        "chatbox"
      ]
    },
    {
      "name": "chatbox-ellipses",
      "tags": [
        "chatbox",
        "ellipses"
      ]
    },
    {
      "name": "chatbox-ellipses-outline",
      "tags": [
        "chatbox",
        "ellipses",
        "outline"
      ]
    },
    {
      "name": "chatbox-ellipses-sharp",
      "tags": [
        "chatbox",
        "ellipses",
        "sharp"
      ]
    },
    {
      "name": "chatbox-outline",
      "tags": [
        "chatbox",
        "outline"
      ]
    },
    {
      "name": "chatbox-sharp",
      "tags": [
        "chatbox",
        "sharp"
      ]
    },
    {
      "name": "chatbubble",
      "tags": [
        "chatbubble"
      ]
    },
    {
      "name": "chatbubble-ellipses",
      "tags": [
        "chatbubble",
        "ellipses"
      ]
    },
    {
      "name": "chatbubble-ellipses-outline",
      "tags": [
        "chatbubble",
        "ellipses",
        "outline"
      ]
    },
    {
      "name": "chatbubble-ellipses-sharp",
      "tags": [
        "chatbubble",
        "ellipses",
        "sharp"
      ]
    },
    {
      "name": "chatbubble-outline",
      "tags": [
        "chatbubble",
        "outline"
      ]
    },
    {
      "name": "chatbubble-sharp",
      "tags": [
        "chatbubble",
        "sharp"
      ]
    },
    {
      "name": "chatbubbles",
      "tags": [
        "chatbubbles",
        "talk"
      ]
    },
    {
      "name": "chatbubbles-outline",
      "tags": [
        "chatbubbles",
        "outline",
        "talk"
      ]
    },
    {
      "name": "chatbubbles-sharp",
      "tags": [
        "chatbubbles",
        "sharp",
        "talk"
      ]
    },
    {
      "name": "checkbox",
      "tags": [
        "checkbox"
      ]
    },
    {
      "name": "checkbox-outline",
      "tags": [
        "checkbox",
        "outline"
      ]
    },
    {
      "name": "checkbox-sharp",
      "tags": [
        "checkbox",
        "sharp"
      ]
    },
    {
      "name": "checkmark",
      "tags": [
        "checkmark",
        "circle"
      ]
    },
    {
      "name": "checkmark-circle",
      "tags": [
        "checkmark",
        "circle"
      ]
    },
    {
      "name": "checkmark-circle-outline",
      "tags": [
        "checkmark",
        "circle",
        "outline"
      ]
    },
    {
      "name": "checkmark-circle-sharp",
      "tags": [
        "checkmark",
        "circle",
        "sharp"
      ]
    },
    {
      "name": "checkmark-done",
      "tags": [
        "checkmark",
        "done"
      ]
    },
    {
      "name": "checkmark-done-circle",
      "tags": [
        "checkmark",
        "circle",
        "done"
      ]
    },
    {
      "name": "checkmark-done-circle-outline",
      "tags": [
        "checkmark",
        "circle",
        "done",
        "outline"
      ]
    },
    {
      "name": "checkmark-done-circle-sharp",
      "tags": [
        "checkmark",
        "circle",
        "done",
        "sharp"
      ]
    },
    {
      "name": "checkmark-done-outline",
      "tags": [
        "checkmark",
        "done",
        "outline"
      ]
    },
    {
      "name": "checkmark-done-sharp",
      "tags": [
        "checkmark",
        "done",
        "sharp"
      ]
    },
    {
      "name": "checkmark-outline",
      "tags": [
        "checkmark",
        "outline"
      ]
    },
    {
      "name": "checkmark-sharp",
      "tags": [
        "checkmark",
        "circle",
        "sharp"
      ]
    },
    {
      "name": "chevron-back",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "left"
      ]
    },
    {
      "name": "chevron-back-circle",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "circle",
        "left"
      ]
    },
    {
      "name": "chevron-back-circle-outline",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "circle",
        "left",
        "outline"
      ]
    },
    {
      "name": "chevron-back-circle-sharp",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "circle",
        "left",
        "sharp"
      ]
    },
    {
      "name": "chevron-back-outline",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "left",
        "outline"
      ]
    },
    {
      "name": "chevron-back-sharp",
      "tags": [
        "arrow",
        "back",
        "chevron",
        "left",
        "sharp"
      ]
    },
    {
      "name": "chevron-collapse",
      "tags": [
        "chevron",
        "collapse"
      ]
    },
    {
      "name": "chevron-collapse-outline",
      "tags": [
        "chevron",
        "collapse",
        "outline"
      ]
    },
    {
      "name": "chevron-collapse-sharp",
      "tags": [
        "chevron",
        "collapse",
        "sharp"
      ]
    },
    {
      "name": "chevron-down",
      "tags": [
        "arrow",
        "chevron",
        "down"
      ]
    },
    {
      "name": "chevron-down-circle",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "down"
      ]
    },
    {
      "name": "chevron-down-circle-outline",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "down",
        "outline"
      ]
    },
    {
      "name": "chevron-down-circle-sharp",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "down",
        "sharp"
      ]
    },
    {
      "name": "chevron-down-outline",
      "tags": [
        "arrow",
        "chevron",
        "down",
        "outline"
      ]
    },
    {
      "name": "chevron-down-sharp",
      "tags": [
        "arrow",
        "chevron",
        "down",
        "sharp"
      ]
    },
    {
      "name": "chevron-expand",
      "tags": [
        "chevron",
        "expand"
      ]
    },
    {
      "name": "chevron-expand-outline",
      "tags": [
        "chevron",
        "expand",
        "outline"
      ]
    },
    {
      "name": "chevron-expand-sharp",
      "tags": [
        "chevron",
        "expand",
        "sharp"
      ]
    },
    {
      "name": "chevron-forward",
      "tags": [
        "arrow",
        "chevron",
        "forward",
        "right"
      ]
    },
    {
      "name": "chevron-forward-circle",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "forward",
        "right"
      ]
    },
    {
      "name": "chevron-forward-circle-outline",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "forward",
        "outline",
        "right"
      ]
    },
    {
      "name": "chevron-forward-circle-sharp",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "forward",
        "right",
        "sharp"
      ]
    },
    {
      "name": "chevron-forward-outline",
      "tags": [
        "arrow",
        "chevron",
        "forward",
        "outline",
        "right"
      ]
    },
    {
      "name": "chevron-forward-sharp",
      "tags": [
        "arrow",
        "chevron",
        "forward",
        "right",
        "sharp"
      ]
    },
    {
      "name": "chevron-up",
      "tags": [
        "arrow",
        "chevron",
        "up"
      ]
    },
    {
      "name": "chevron-up-circle",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "up"
      ]
    },
    {
      "name": "chevron-up-circle-outline",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "outline",
        "up"
      ]
    },
    {
      "name": "chevron-up-circle-sharp",
      "tags": [
        "arrow",
        "chevron",
        "circle",
        "sharp",
        "up"
      ]
    },
    {
      "name": "chevron-up-outline",
      "tags": [
        "arrow",
        "chevron",
        "outline",
        "up"
      ]
    },
    {
      "name": "chevron-up-sharp",
      "tags": [
        "arrow",
        "chevron",
        "sharp",
        "up"
      ]
    },
    {
      "name": "clipboard",
      "tags": [
        "clipboard",
        "copy",
        "paste",
        "write"
      ]
    },
    {
      "name": "clipboard-outline",
      "tags": [
        "clipboard",
        "copy",
        "outline",
        "paste",
        "write"
      ]
    },
    {
      "name": "clipboard-sharp",
      "tags": [
        "clipboard",
        "copy",
        "paste",
        "sharp",
        "write"
      ]
    },
    {
      "name": "close",
      "tags": [
        "circle",
        "close",
        "delete",
        "remove"
      ]
    },
    {
      "name": "close-circle",
      "tags": [
        "circle",
        "close",
        "delete",
        "remove"
      ]
    },
    {
      "name": "close-circle-outline",
      "tags": [
        "circle",
        "close",
        "delete",
        "outline",
        "remove"
      ]
    },
    {
      "name": "close-circle-sharp",
      "tags": [
        "circle",
        "close",
        "delete",
        "remove",
        "sharp"
      ]
    },
    {
      "name": "close-outline",
      "tags": [
        "circle",
        "close",
        "delete",
        "outline",
        "remove"
      ]
    },
    {
      "name": "close-sharp",
      "tags": [
        "circle",
        "close",
        "delete",
        "remove",
        "sharp"
      ]
    },
    {
      "name": "cloud",
      "tags": [
        "circle",
        "cloud",
        "storage",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloud-circle",
      "tags": [
        "circle",
        "cloud",
        "storage",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloud-circle-outline",
      "tags": [
        "circle",
        "cloud",
        "outline",
        "storage",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloud-circle-sharp",
      "tags": [
        "circle",
        "cloud",
        "sharp",
        "storage",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloud-done",
      "tags": [
        "cloud",
        "done"
      ]
    },
    {
      "name": "cloud-done-outline",
      "tags": [
        "cloud",
        "done",
        "outline"
      ]
    },
    {
      "name": "cloud-done-sharp",
      "tags": [
        "cloud",
        "done",
        "sharp"
      ]
    },
    {
      "name": "cloud-download",
      "tags": [
        "cloud",
        "download",
        "storage"
      ]
    },
    {
      "name": "cloud-download-outline",
      "tags": [
        "cloud",
        "download",
        "outline",
        "storage"
      ]
    },
    {
      "name": "cloud-download-sharp",
      "tags": [
        "cloud",
        "download",
        "sharp",
        "storage"
      ]
    },
    {
      "name": "cloud-offline",
      "tags": [
        "cloud",
        "offline"
      ]
    },
    {
      "name": "cloud-offline-outline",
      "tags": [
        "cloud",
        "offline",
        "outline"
      ]
    },
    {
      "name": "cloud-offline-sharp",
      "tags": [
        "cloud",
        "offline",
        "sharp"
      ]
    },
    {
      "name": "cloud-outline",
      "tags": [
        "circle",
        "cloud",
        "outline",
        "storage",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloud-sharp",
      "tags": [
        "circle",
        "cloud",
        "sharp",
        "storage",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloud-upload",
      "tags": [
        "cloud",
        "storage",
        "upload"
      ]
    },
    {
      "name": "cloud-upload-outline",
      "tags": [
        "cloud",
        "outline",
        "storage",
        "upload"
      ]
    },
    {
      "name": "cloud-upload-sharp",
      "tags": [
        "cloud",
        "sharp",
        "storage",
        "upload"
      ]
    },
    {
      "name": "cloudy",
      "tags": [
        "cloudy",
        "overcast",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloudy-night",
      "tags": [
        "cloudy",
        "night",
        "overcast",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloudy-night-outline",
      "tags": [
        "cloudy",
        "night",
        "outline",
        "overcast",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloudy-night-sharp",
      "tags": [
        "cloudy",
        "night",
        "overcast",
        "sharp",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloudy-outline",
      "tags": [
        "cloudy",
        "outline",
        "overcast",
        "weather",
        "whether"
      ]
    },
    {
      "name": "cloudy-sharp",
      "tags": [
        "cloudy",
        "overcast",
        "sharp",
        "weather",
        "whether"
      ]
    },
    {
      "name": "code",
      "tags": [
        "code",
        "develop",
        "hacker",
        "program"
      ]
    },
    {
      "name": "code-download",
      "tags": [
        "code",
        "develop",
        "download",
        "hacker",
        "program"
      ]
    },
    {
      "name": "code-download-outline",
      "tags": [
        "code",
        "develop",
        "download",
        "hacker",
        "outline",
        "program"
      ]
    },
    {
      "name": "code-download-sharp",
      "tags": [
        "code",
        "develop",
        "download",
        "hacker",
        "program",
        "sharp"
      ]
    },
    {
      "name": "code-outline",
      "tags": [
        "code",
        "develop",
        "hacker",
        "outline",
        "program"
      ]
    },
    {
      "name": "code-sharp",
      "tags": [
        "code",
        "develop",
        "hacker",
        "program",
        "sharp"
      ]
    },
    {
      "name": "code-slash",
      "tags": [
        "code",
        "slash"
      ]
    },
    {
      "name": "code-slash-outline",
      "tags": [
        "code",
        "outline",
        "slash"
      ]
    },
    {
      "name": "code-slash-sharp",
      "tags": [
        "code",
        "sharp",
        "slash"
      ]
    },
    {
      "name": "code-working",
      "tags": [
        "code",
        "develop",
        "hacker",
        "program",
        "working"
      ]
    },
    {
      "name": "code-working-outline",
      "tags": [
        "code",
        "develop",
        "hacker",
        "outline",
        "program",
        "working"
      ]
    },
    {
      "name": "code-working-sharp",
      "tags": [
        "code",
        "develop",
        "hacker",
        "program",
        "sharp",
        "working"
      ]
    },
    {
      "name": "cog",
      "tags": [
        "cog",
        "gear",
        "options",
        "settings"
      ]
    },
    {
      "name": "cog-outline",
      "tags": [
        "cog",
        "gear",
        "options",
        "outline",
        "settings"
      ]
    },
    {
      "name": "cog-sharp",
      "tags": [
        "cog",
        "gear",
        "options",
        "settings",
        "sharp"
      ]
    },
    {
      "name": "color-fill",
      "tags": [
        "color",
        "fill"
      ]
    },
    {
      "name": "color-fill-outline",
      "tags": [
        "color",
        "fill",
        "outline"
      ]
    },
    {
      "name": "color-fill-sharp",
      "tags": [
        "color",
        "fill",
        "sharp"
      ]
    },
    {
      "name": "color-filter",
      "tags": [
        "color",
        "filter"
      ]
    },
    {
      "name": "color-filter-outline",
      "tags": [
        "color",
        "filter",
        "outline"
      ]
    },
    {
      "name": "color-filter-sharp",
      "tags": [
        "color",
        "filter",
        "sharp"
      ]
    },
    {
      "name": "color-palette",
      "tags": [
        "color",
        "palette"
      ]
    },
    {
      "name": "color-palette-outline",
      "tags": [
        "color",
        "outline",
        "palette"
      ]
    },
    {
      "name": "color-palette-sharp",
      "tags": [
        "color",
        "palette",
        "sharp"
      ]
    },
    {
      "name": "color-wand",
      "tags": [
        "color",
        "wand"
      ]
    },
    {
      "name": "color-wand-outline",
      "tags": [
        "color",
        "outline",
        "wand"
      ]
    },
    {
      "name": "color-wand-sharp",
      "tags": [
        "color",
        "sharp",
        "wand"
      ]
    },
    {
      "name": "compass",
      "tags": [
        "compass",
        "directions",
        "location",
        "navigation"
      ]
    },
    {
      "name": "compass-outline",
      "tags": [
        "compass",
        "directions",
        "location",
        "navigation",
        "outline"
      ]
    },
    {
      "name": "compass-sharp",
      "tags": [
        "compass",
        "directions",
        "location",
        "navigation",
        "sharp"
      ]
    },
    {
      "name": "construct",
      "tags": [
        "construct"
      ]
    },
    {
      "name": "construct-outline",
      "tags": [
        "construct",
        "outline"
      ]
    },
    {
      "name": "construct-sharp",
      "tags": [
        "construct",
        "sharp"
      ]
    },
    {
      "name": "contract",
      "tags": [
        "contract"
      ]
    },
    {
      "name": "contract-outline",
      "tags": [
        "contract",
        "outline"
      ]
    },
    {
      "name": "contract-sharp",
      "tags": [
        "contract",
        "sharp"
      ]
    },
    {
      "name": "contrast",
      "tags": [
        "contrast",
        "dark",
        "images",
        "levels",
        "light",
        "settings"
      ]
    },
    {
      "name": "contrast-outline",
      "tags": [
        "contrast",
        "dark",
        "images",
        "levels",
        "light",
        "outline",
        "settings"
      ]
    },
    {
      "name": "contrast-sharp",
      "tags": [
        "contrast",
        "dark",
        "images",
        "levels",
        "light",
        "settings",
        "sharp"
      ]
    },
    {
      "name": "copy",
      "tags": [
        "copy",
        "duplicate",
        "paper"
      ]
    },
    {
      "name": "copy-outline",
      "tags": [
        "copy",
        "duplicate",
        "outline",
        "paper"
      ]
    },
    {
      "name": "copy-sharp",
      "tags": [
        "copy",
        "duplicate",
        "paper",
        "sharp"
      ]
    },
    {
      "name": "create",
      "tags": [
        "create",
        "edit"
      ]
    },
    {
      "name": "create-outline",
      "tags": [
        "create",
        "edit",
        "outline"
      ]
    },
    {
      "name": "create-sharp",
      "tags": [
        "create",
        "edit",
        "sharp"
      ]
    },
    {
      "name": "crop",
      "tags": [
        "crop"
      ]
    },
    {
      "name": "crop-outline",
      "tags": [
        "crop",
        "outline"
      ]
    },
    {
      "name": "crop-sharp",
      "tags": [
        "crop",
        "sharp"
      ]
    },
    {
      "name": "cube",
      "tags": [
        "box",
        "container",
        "cube",
        "square"
      ]
    },
    {
      "name": "cube-outline",
      "tags": [
        "box",
        "container",
        "cube",
        "outline",
        "square"
      ]
    },
    {
      "name": "cube-sharp",
      "tags": [
        "box",
        "container",
        "cube",
        "sharp",
        "square"
      ]
    },
    {
      "name": "cut",
      "tags": [
        "cut"
      ]
    },
    {
      "name": "cut-outline",
      "tags": [
        "cut",
        "outline"
      ]
    },
    {
      "name": "cut-sharp",
      "tags": [
        "cut",
        "sharp"
      ]
    },
    {
      "name": "desktop",
      "tags": [
        "desktop"
      ]
    },
    {
      "name": "desktop-outline",
      "tags": [
        "desktop",
        "outline"
      ]
    },
    {
      "name": "desktop-sharp",
      "tags": [
        "desktop",
        "sharp"
      ]
    },
    {
      "name": "diamond",
      "tags": [
        "diamond"
      ]
    },
    {
      "name": "diamond-outline",
      "tags": [
        "diamond",
        "outline"
      ]
    },
    {
      "name": "diamond-sharp",
      "tags": [
        "diamond",
        "sharp"
      ]
    },
    {
      "name": "dice",
      "tags": [
        "dice"
      ]
    },
    {
      "name": "dice-outline",
      "tags": [
        "dice",
        "outline"
      ]
    },
    {
      "name": "dice-sharp",
      "tags": [
        "dice",
        "sharp"
      ]
    },
    {
      "name": "disc",
      "tags": [
        "cd",
        "disc",
        "vinyl"
      ]
    },
    {
      "name": "disc-outline",
      "tags": [
        "cd",
        "disc",
        "outline",
        "vinyl"
      ]
    },
    {
      "name": "disc-sharp",
      "tags": [
        "cd",
        "disc",
        "sharp",
        "vinyl"
      ]
    },
    {
      "name": "document",
      "tags": [
        "document",
        "file",
        "paper"
      ]
    },
    {
      "name": "document-attach",
      "tags": [
        "attach",
        "document"
      ]
    },
    {
      "name": "document-attach-outline",
      "tags": [
        "attach",
        "document",
        "outline"
      ]
    },
    {
      "name": "document-attach-sharp",
      "tags": [
        "attach",
        "document",
        "sharp"
      ]
    },
    {
      "name": "document-lock",
      "tags": [
        "document",
        "lock"
      ]
    },
    {
      "name": "document-lock-outline",
      "tags": [
        "document",
        "lock",
        "outline"
      ]
    },
    {
      "name": "document-lock-sharp",
      "tags": [
        "document",
        "lock",
        "sharp"
      ]
    },
    {
      "name": "document-outline",
      "tags": [
        "document",
        "file",
        "outline",
        "paper"
      ]
    },
    {
      "name": "document-sharp",
      "tags": [
        "document",
        "file",
        "paper",
        "sharp"
      ]
    },
    {
      "name": "document-text",
      "tags": [
        "document",
        "text"
      ]
    },
    {
      "name": "document-text-outline",
      "tags": [
        "document",
        "outline",
        "text"
      ]
    },
    {
      "name": "document-text-sharp",
      "tags": [
        "document",
        "sharp",
        "text"
      ]
    },
    {
      "name": "documents",
      "tags": [
        "documents"
      ]
    },
    {
      "name": "documents-outline",
      "tags": [
        "documents",
        "outline"
      ]
    },
    {
      "name": "documents-sharp",
      "tags": [
        "documents",
        "sharp"
      ]
    },
    {
      "name": "download",
      "tags": [
        "download",
        "export"
      ]
    },
    {
      "name": "download-outline",
      "tags": [
        "download",
        "export",
        "outline"
      ]
    },
    {
      "name": "download-sharp",
      "tags": [
        "download",
        "export",
        "sharp"
      ]
    },
    {
      "name": "duplicate",
      "tags": [
        "duplicate"
      ]
    },
    {
      "name": "duplicate-outline",
      "tags": [
        "duplicate",
        "outline"
      ]
    },
    {
      "name": "duplicate-sharp",
      "tags": [
        "duplicate",
        "sharp"
      ]
    },
    {
      "name": "ear",
      "tags": [
        "ear"
      ]
    },
    {
      "name": "ear-outline",
      "tags": [
        "ear",
        "outline"
      ]
    },
    {
      "name": "ear-sharp",
      "tags": [
        "ear",
        "sharp"
      ]
    },
    {
      "name": "earth",
      "tags": [
        "earth",
        "globe"
      ]
    },
    {
      "name": "earth-outline",
      "tags": [
        "earth",
        "globe",
        "outline"
      ]
    },
    {
      "name": "earth-sharp",
      "tags": [
        "earth",
        "globe",
        "sharp"
      ]
    },
    {
      "name": "easel",
      "tags": [
        "easel"
      ]
    },
    {
      "name": "easel-outline",
      "tags": [
        "easel",
        "outline"
      ]
    },
    {
      "name": "easel-sharp",
      "tags": [
        "easel",
        "sharp"
      ]
    },
    {
      "name": "egg",
      "tags": [
        "baby",
        "bird",
        "birth",
        "egg",
        "twitter"
      ]
    },
    {
      "name": "egg-outline",
      "tags": [
        "baby",
        "bird",
        "birth",
        "egg",
        "outline",
        "twitter"
      ]
    },
    {
      "name": "egg-sharp",
      "tags": [
        "baby",
        "bird",
        "birth",
        "egg",
        "sharp",
        "twitter"
      ]
    },
    {
      "name": "ellipse",
      "tags": [
        "circle",
        "ellipse"
      ]
    },
    {
      "name": "ellipse-outline",
      "tags": [
        "circle",
        "ellipse",
        "outline"
      ]
    },
    {
      "name": "ellipse-sharp",
      "tags": [
        "circle",
        "ellipse",
        "sharp"
      ]
    },
    {
      "name": "ellipsis-horizontal",
      "tags": [
        "ellipsis",
        "horizontal"
      ]
    },
    {
      "name": "ellipsis-horizontal-circle",
      "tags": [
        "circle",
        "ellipsis",
        "horizontal"
      ]
    },
    {
      "name": "ellipsis-horizontal-circle-outline",
      "tags": [
        "circle",
        "ellipsis",
        "horizontal",
        "outline"
      ]
    },
    {
      "name": "ellipsis-horizontal-circle-sharp",
      "tags": [
        "circle",
        "ellipsis",
        "horizontal",
        "sharp"
      ]
    },
    {
      "name": "ellipsis-horizontal-outline",
      "tags": [
        "ellipsis",
        "horizontal",
        "outline"
      ]
    },
    {
      "name": "ellipsis-horizontal-sharp",
      "tags": [
        "ellipsis",
        "horizontal",
        "sharp"
      ]
    },
    {
      "name": "ellipsis-vertical",
      "tags": [
        "ellipsis",
        "vertical"
      ]
    },
    {
      "name": "ellipsis-vertical-circle",
      "tags": [
        "circle",
        "ellipsis",
        "vertical"
      ]
    },
    {
      "name": "ellipsis-vertical-circle-outline",
      "tags": [
        "circle",
        "ellipsis",
        "outline",
        "vertical"
      ]
    },
    {
      "name": "ellipsis-vertical-circle-sharp",
      "tags": [
        "circle",
        "ellipsis",
        "sharp",
        "vertical"
      ]
    },
    {
      "name": "ellipsis-vertical-outline",
      "tags": [
        "ellipsis",
        "outline",
        "vertical"
      ]
    },
    {
      "name": "ellipsis-vertical-sharp",
      "tags": [
        "ellipsis",
        "sharp",
        "vertical"
      ]
    },
    {
      "name": "enter",
      "tags": [
        "enter"
      ]
    },
    {
      "name": "enter-outline",
      "tags": [
        "enter",
        "outline"
      ]
    },
    {
      "name": "enter-sharp",
      "tags": [
        "enter",
        "sharp"
      ]
    },
    {
      "name": "exit",
      "tags": [
        "exit"
      ]
    },
    {
      "name": "exit-outline",
      "tags": [
        "exit",
        "outline"
      ]
    },
    {
      "name": "exit-sharp",
      "tags": [
        "exit",
        "sharp"
      ]
    },
    {
      "name": "expand",
      "tags": [
        "expand",
        "resize"
      ]
    },
    {
      "name": "expand-outline",
      "tags": [
        "expand",
        "outline"
      ]
    },
    {
      "name": "expand-sharp",
      "tags": [
        "expand",
        "resize",
        "sharp"
      ]
    },
    {
      "name": "extension-puzzle",
      "tags": [
        "extension",
        "puzzle"
      ]
    },
    {
      "name": "extension-puzzle-outline",
      "tags": [
        "extension",
        "outline",
        "puzzle"
      ]
    },
    {
      "name": "extension-puzzle-sharp",
      "tags": [
        "extension",
        "puzzle",
        "sharp"
      ]
    },
    {
      "name": "eye",
      "tags": [
        "exposed",
        "eye",
        "look",
        "see",
        "view"
      ]
    },
    {
      "name": "eye-off",
      "tags": [
        "eye",
        "off"
      ]
    },
    {
      "name": "eye-off-outline",
      "tags": [
        "eye",
        "off",
        "outline"
      ]
    },
    {
      "name": "eye-off-sharp",
      "tags": [
        "eye",
        "off",
        "sharp"
      ]
    },
    {
      "name": "eye-outline",
      "tags": [
        "exposed",
        "eye",
        "look",
        "outline",
        "see",
        "view"
      ]
    },
    {
      "name": "eye-sharp",
      "tags": [
        "exposed",
        "eye",
        "look",
        "see",
        "sharp",
        "view"
      ]
    },
    {
      "name": "eyedrop",
      "tags": [
        "eyedrop"
      ]
    },
    {
      "name": "eyedrop-outline",
      "tags": [
        "eyedrop",
        "outline"
      ]
    },
    {
      "name": "eyedrop-sharp",
      "tags": [
        "eyedrop",
        "sharp"
      ]
    },
    {
      "name": "fast-food",
      "tags": [
        "fast",
        "food"
      ]
    },
    {
      "name": "fast-food-outline",
      "tags": [
        "fast",
        "food",
        "outline"
      ]
    },
    {
      "name": "fast-food-sharp",
      "tags": [
        "fast",
        "food",
        "sharp"
      ]
    },
    {
      "name": "female",
      "tags": [
        "dudette",
        "female",
        "girl",
        "lady",
        "woman"
      ]
    },
    {
      "name": "female-outline",
      "tags": [
        "dudette",
        "female",
        "girl",
        "lady",
        "outline",
        "woman"
      ]
    },
    {
      "name": "female-sharp",
      "tags": [
        "dudette",
        "female",
        "girl",
        "lady",
        "sharp",
        "woman"
      ]
    },
    {
      "name": "file-tray",
      "tags": [
        "file",
        "tray"
      ]
    },
    {
      "name": "file-tray-full",
      "tags": [
        "file",
        "full",
        "tray"
      ]
    },
    {
      "name": "file-tray-full-outline",
      "tags": [
        "file",
        "full",
        "outline",
        "tray"
      ]
    },
    {
      "name": "file-tray-full-sharp",
      "tags": [
        "file",
        "full",
        "sharp",
        "tray"
      ]
    },
    {
      "name": "file-tray-outline",
      "tags": [
        "file",
        "outline",
        "tray"
      ]
    },
    {
      "name": "file-tray-sharp",
      "tags": [
        "file",
        "sharp",
        "tray"
      ]
    },
    {
      "name": "file-tray-stacked",
      "tags": [
        "file",
        "stacked",
        "tray"
      ]
    },
    {
      "name": "file-tray-stacked-outline",
      "tags": [
        "file",
        "outline",
        "stacked",
        "tray"
      ]
    },
    {
      "name": "file-tray-stacked-sharp",
      "tags": [
        "file",
        "sharp",
        "stacked",
        "tray"
      ]
    },
    {
      "name": "film",
      "tags": [
        "film"
      ]
    },
    {
      "name": "film-outline",
      "tags": [
        "film",
        "outline"
      ]
    },
    {
      "name": "film-sharp",
      "tags": [
        "film",
        "sharp"
      ]
    },
    {
      "name": "filter",
      "tags": [
        "filter"
      ]
    },
    {
      "name": "filter-circle",
      "tags": [
        "circle",
        "filter"
      ]
    },
    {
      "name": "filter-circle-outline",
      "tags": [
        "circle",
        "filter",
        "outline"
      ]
    },
    {
      "name": "filter-circle-sharp",
      "tags": [
        "circle",
        "filter",
        "sharp"
      ]
    },
    {
      "name": "filter-outline",
      "tags": [
        "filter",
        "outline"
      ]
    },
    {
      "name": "filter-sharp",
      "tags": [
        "filter",
        "sharp"
      ]
    },
    {
      "name": "finger-print",
      "tags": [
        "finger",
        "print"
      ]
    },
    {
      "name": "finger-print-outline",
      "tags": [
        "finger",
        "outline",
        "print"
      ]
    },
    {
      "name": "finger-print-sharp",
      "tags": [
        "finger",
        "print",
        "sharp"
      ]
    },
    {
      "name": "fish",
      "tags": [
        "fish"
      ]
    },
    {
      "name": "fish-outline",
      "tags": [
        "fish",
        "outline"
      ]
    },
    {
      "name": "fish-sharp",
      "tags": [
        "fish",
        "sharp"
      ]
    },
    {
      "name": "fitness",
      "tags": [
        "fitness"
      ]
    },
    {
      "name": "fitness-outline",
      "tags": [
        "fitness",
        "outline"
      ]
    },
    {
      "name": "fitness-sharp",
      "tags": [
        "fitness",
        "sharp"
      ]
    },
    {
      "name": "flag",
      "tags": [
        "favorite",
        "flag",
        "marker"
      ]
    },
    {
      "name": "flag-outline",
      "tags": [
        "favorite",
        "flag",
        "marker",
        "outline"
      ]
    },
    {
      "name": "flag-sharp",
      "tags": [
        "favorite",
        "flag",
        "marker",
        "sharp"
      ]
    },
    {
      "name": "flame",
      "tags": [
        "fire",
        "flame",
        "heat",
        "hot"
      ]
    },
    {
      "name": "flame-outline",
      "tags": [
        "fire",
        "flame",
        "heat",
        "hot",
        "outline"
      ]
    },
    {
      "name": "flame-sharp",
      "tags": [
        "fire",
        "flame",
        "heat",
        "hot",
        "sharp"
      ]
    },
    {
      "name": "flash",
      "tags": [
        "flash",
        "lightning",
        "weather",
        "whether"
      ]
    },
    {
      "name": "flash-off",
      "tags": [
        "flash",
        "off"
      ]
    },
    {
      "name": "flash-off-outline",
      "tags": [
        "flash",
        "off",
        "outline"
      ]
    },
    {
      "name": "flash-off-sharp",
      "tags": [
        "flash",
        "off",
        "sharp"
      ]
    },
    {
      "name": "flash-outline",
      "tags": [
        "flash",
        "lightning",
        "outline",
        "weather",
        "whether"
      ]
    },
    {
      "name": "flash-sharp",
      "tags": [
        "flash",
        "lightning",
        "sharp",
        "weather",
        "whether"
      ]
    },
    {
      "name": "flashlight",
      "tags": [
        "flashlight"
      ]
    },
    {
      "name": "flashlight-outline",
      "tags": [
        "flashlight",
        "outline"
      ]
    },
    {
      "name": "flashlight-sharp",
      "tags": [
        "flashlight",
        "sharp"
      ]
    },
    {
      "name": "flask",
      "tags": [
        "bubbles",
        "flask",
        "mixture",
        "potion"
      ]
    },
    {
      "name": "flask-outline",
      "tags": [
        "bubbles",
        "flask",
        "mixture",
        "outline",
        "potion"
      ]
    },
    {
      "name": "flask-sharp",
      "tags": [
        "bubbles",
        "flask",
        "mixture",
        "potion",
        "sharp"
      ]
    },
    {
      "name": "flower",
      "tags": [
        "flower"
      ]
    },
    {
      "name": "flower-outline",
      "tags": [
        "flower",
        "outline"
      ]
    },
    {
      "name": "flower-sharp",
      "tags": [
        "flower",
        "sharp"
      ]
    },
    {
      "name": "folder",
      "tags": [
        "file",
        "folder"
      ]
    },
    {
      "name": "folder-open",
      "tags": [
        "folder",
        "open"
      ]
    },
    {
      "name": "folder-open-outline",
      "tags": [
        "folder",
        "open",
        "outline"
      ]
    },
    {
      "name": "folder-open-sharp",
      "tags": [
        "folder",
        "open",
        "sharp"
      ]
    },
    {
      "name": "folder-outline",
      "tags": [
        "file",
        "folder",
        "outline"
      ]
    },
    {
      "name": "folder-sharp",
      "tags": [
        "file",
        "folder",
        "sharp"
      ]
    },
    {
      "name": "football",
      "tags": [
        "football",
        "soccer"
      ]
    },
    {
      "name": "football-outline",
      "tags": [
        "football",
        "outline",
        "soccer"
      ]
    },
    {
      "name": "football-sharp",
      "tags": [
        "football",
        "sharp",
        "soccer"
      ]
    },
    {
      "name": "footsteps",
      "tags": [
        "footsteps"
      ]
    },
    {
      "name": "footsteps-outline",
      "tags": [
        "footsteps",
        "outline"
      ]
    },
    {
      "name": "footsteps-sharp",
      "tags": [
        "footsteps",
        "sharp"
      ]
    },
    {
      "name": "funnel",
      "tags": [
        "funnel",
        "sort"
      ]
    },
    {
      "name": "funnel-outline",
      "tags": [
        "funnel",
        "outline",
        "sort"
      ]
    },
    {
      "name": "funnel-sharp",
      "tags": [
        "funnel",
        "sharp",
        "sort"
      ]
    },
    {
      "name": "game-controller",
      "tags": [
        "controller",
        "game"
      ]
    },
    {
      "name": "game-controller-outline",
      "tags": [
        "controller",
        "game",
        "outline"
      ]
    },
    {
      "name": "game-controller-sharp",
      "tags": [
        "controller",
        "game",
        "sharp"
      ]
    },
    {
      "name": "gift",
      "tags": [
        "gift"
      ]
    },
    {
      "name": "gift-outline",
      "tags": [
        "gift",
        "outline"
      ]
    },
    {
      "name": "gift-sharp",
      "tags": [
        "gift",
        "sharp"
      ]
    },
    {
      "name": "git-branch",
      "tags": [
        "branch",
        "git"
      ]
    },
    {
      "name": "git-branch-outline",
      "tags": [
        "branch",
        "git",
        "outline"
      ]
    },
    {
      "name": "git-branch-sharp",
      "tags": [
        "branch",
        "git",
        "sharp"
      ]
    },
    {
      "name": "git-commit",
      "tags": [
        "commit",
        "git"
      ]
    },
    {
      "name": "git-commit-outline",
      "tags": [
        "commit",
        "git",
        "outline"
      ]
    },
    {
      "name": "git-commit-sharp",
      "tags": [
        "commit",
        "git",
        "sharp"
      ]
    },
    {
      "name": "git-compare",
      "tags": [
        "compare",
        "git"
      ]
    },
    {
      "name": "git-compare-outline",
      "tags": [
        "compare",
        "git",
        "outline"
      ]
    },
    {
      "name": "git-compare-sharp",
      "tags": [
        "compare",
        "git",
        "sharp"
      ]
    },
    {
      "name": "git-merge",
      "tags": [
        "git",
        "merge"
      ]
    },
    {
      "name": "git-merge-outline",
      "tags": [
        "git",
        "merge",
        "outline"
      ]
    },
    {
      "name": "git-merge-sharp",
      "tags": [
        "git",
        "merge",
        "sharp"
      ]
    },
    {
      "name": "git-network",
      "tags": [
        "git",
        "network"
      ]
    },
    {
      "name": "git-network-outline",
      "tags": [
        "git",
        "network",
        "outline"
      ]
    },
    {
      "name": "git-network-sharp",
      "tags": [
        "git",
        "network",
        "sharp"
      ]
    },
    {
      "name": "git-pull-request",
      "tags": [
        "git",
        "pull",
        "request"
      ]
    },
    {
      "name": "git-pull-request-outline",
      "tags": [
        "git",
        "outline",
        "pull",
        "request"
      ]
    },
    {
      "name": "git-pull-request-sharp",
      "tags": [
        "git",
        "pull",
        "request",
        "sharp"
      ]
    },
    {
      "name": "glasses",
      "tags": [
        "glasses",
        "look",
        "reading",
        "see",
        "steve"
      ]
    },
    {
      "name": "glasses-outline",
      "tags": [
        "glasses",
        "look",
        "outline",
        "reading",
        "see",
        "steve"
      ]
    },
    {
      "name": "glasses-sharp",
      "tags": [
        "glasses",
        "look",
        "reading",
        "see",
        "sharp",
        "steve"
      ]
    },
    {
      "name": "globe",
      "tags": [
        "globe",
        "internet",
        "world"
      ]
    },
    {
      "name": "globe-outline",
      "tags": [
        "globe",
        "internet",
        "outline",
        "world"
      ]
    },
    {
      "name": "globe-sharp",
      "tags": [
        "globe",
        "internet",
        "sharp",
        "world"
      ]
    },
    {
      "name": "golf",
      "tags": [
        "golf"
      ]
    },
    {
      "name": "golf-outline",
      "tags": [
        "golf",
        "outline"
      ]
    },
    {
      "name": "golf-sharp",
      "tags": [
        "golf",
        "sharp"
      ]
    },
    {
      "name": "grid",
      "tags": [
        "grid",
        "menu"
      ]
    },
    {
      "name": "grid-outline",
      "tags": [
        "grid",
        "menu",
        "outline"
      ]
    },
    {
      "name": "grid-sharp",
      "tags": [
        "grid",
        "menu",
        "sharp"
      ]
    },
    {
      "name": "hammer",
      "tags": [
        "hammer",
        "options",
        "settings",
        "tools"
      ]
    },
    {
      "name": "hammer-outline",
      "tags": [
        "hammer",
        "options",
        "outline",
        "settings",
        "tools"
      ]
    },
    {
      "name": "hammer-sharp",
      "tags": [
        "hammer",
        "options",
        "settings",
        "sharp",
        "tools"
      ]
    },
    {
      "name": "hand-left",
      "tags": [
        "hand",
        "left"
      ]
    },
    {
      "name": "hand-left-outline",
      "tags": [
        "hand",
        "left",
        "outline"
      ]
    },
    {
      "name": "hand-left-sharp",
      "tags": [
        "hand",
        "left",
        "sharp"
      ]
    },
    {
      "name": "hand-right",
      "tags": [
        "hand",
        "right"
      ]
    },
    {
      "name": "hand-right-outline",
      "tags": [
        "hand",
        "outline",
        "right"
      ]
    },
    {
      "name": "hand-right-sharp",
      "tags": [
        "hand",
        "right",
        "sharp"
      ]
    },
    {
      "name": "happy",
      "tags": [
        "fun",
        "good",
        "happy",
        "like",
        "smile",
        "yes"
      ]
    },
    {
      "name": "happy-outline",
      "tags": [
        "fun",
        "good",
        "happy",
        "like",
        "outline",
        "smile",
        "yes"
      ]
    },
    {
      "name": "happy-sharp",
      "tags": [
        "fun",
        "good",
        "happy",
        "like",
        "sharp",
        "smile",
        "yes"
      ]
    },
    {
      "name": "hardware-chip",
      "tags": [
        "chip",
        "hardware"
      ]
    },
    {
      "name": "hardware-chip-outline",
      "tags": [
        "chip",
        "hardware",
        "outline"
      ]
    },
    {
      "name": "hardware-chip-sharp",
      "tags": [
        "chip",
        "hardware",
        "sharp"
      ]
    },
    {
      "name": "headset",
      "tags": [
        "headset"
      ]
    },
    {
      "name": "headset-outline",
      "tags": [
        "headset",
        "outline"
      ]
    },
    {
      "name": "headset-sharp",
      "tags": [
        "headset",
        "sharp"
      ]
    },
    {
      "name": "heart",
      "tags": [
        "heart",
        "love"
      ]
    },
    {
      "name": "heart-circle",
      "tags": [
        "circle",
        "heart",
        "love"
      ]
    },
    {
      "name": "heart-circle-outline",
      "tags": [
        "circle",
        "heart",
        "love",
        "outline"
      ]
    },
    {
      "name": "heart-circle-sharp",
      "tags": [
        "circle",
        "heart",
        "love",
        "sharp"
      ]
    },
    {
      "name": "heart-dislike",
      "tags": [
        "dislike",
        "heart",
        "love"
      ]
    },
    {
      "name": "heart-dislike-circle",
      "tags": [
        "circle",
        "dislike",
        "heart",
        "love"
      ]
    },
    {
      "name": "heart-dislike-circle-outline",
      "tags": [
        "circle",
        "dislike",
        "heart",
        "love",
        "outline"
      ]
    },
    {
      "name": "heart-dislike-circle-sharp",
      "tags": [
        "circle",
        "dislike",
        "heart",
        "love",
        "sharp"
      ]
    },
    {
      "name": "heart-dislike-outline",
      "tags": [
        "dislike",
        "heart",
        "love",
        "outline"
      ]
    },
    {
      "name": "heart-dislike-sharp",
      "tags": [
        "dislike",
        "heart",
        "love",
        "sharp"
      ]
    },
    {
      "name": "heart-half",
      "tags": [
        "half",
        "heart",
        "love"
      ]
    },
    {
      "name": "heart-half-outline",
      "tags": [
        "half",
        "heart",
        "outline"
      ]
    },
    {
      "name": "heart-half-sharp",
      "tags": [
        "half",
        "heart",
        "love",
        "sharp"
      ]
    },
    {
      "name": "heart-outline",
      "tags": [
        "heart",
        "love",
        "outline"
      ]
    },
    {
      "name": "heart-sharp",
      "tags": [
        "heart",
        "love",
        "sharp"
      ]
    },
    {
      "name": "help",
      "tags": [
        "?",
        "circle",
        "help",
        "information",
        "question"
      ]
    },
    {
      "name": "help-buoy",
      "tags": [
        "?",
        "buoy",
        "help",
        "question"
      ]
    },
    {
      "name": "help-buoy-outline",
      "tags": [
        "?",
        "buoy",
        "help",
        "outline",
        "question"
      ]
    },
    {
      "name": "help-buoy-sharp",
      "tags": [
        "?",
        "buoy",
        "help",
        "question",
        "sharp"
      ]
    },
    {
      "name": "help-circle",
      "tags": [
        "?",
        "circle",
        "help",
        "information",
        "question"
      ]
    },
    {
      "name": "help-circle-outline",
      "tags": [
        "?",
        "circle",
        "help",
        "information",
        "outline",
        "question"
      ]
    },
    {
      "name": "help-circle-sharp",
      "tags": [
        "?",
        "circle",
        "help",
        "information",
        "question",
        "sharp"
      ]
    },
    {
      "name": "help-outline",
      "tags": [
        "help",
        "outline"
      ]
    },
    {
      "name": "help-sharp",
      "tags": [
        "?",
        "circle",
        "help",
        "information",
        "question",
        "sharp"
      ]
    },
    {
      "name": "home",
      "tags": [
        "home",
        "house"
      ]
    },
    {
      "name": "home-outline",
      "tags": [
        "home",
        "house",
        "outline"
      ]
    },
    {
      "name": "home-sharp",
      "tags": [
        "home",
        "house",
        "sharp"
      ]
    },
    {
      "name": "hourglass",
      "tags": [
        "hourglass",
        "time"
      ]
    },
    {
      "name": "hourglass-outline",
      "tags": [
        "hourglass",
        "outline",
        "time"
      ]
    },
    {
      "name": "hourglass-sharp",
      "tags": [
        "hourglass",
        "sharp",
        "time"
      ]
    },
    {
      "name": "ice-cream",
      "tags": [
        "cream",
        "ice"
      ]
    },
    {
      "name": "ice-cream-outline",
      "tags": [
        "cream",
        "ice",
        "outline"
      ]
    },
    {
      "name": "ice-cream-sharp",
      "tags": [
        "cream",
        "ice",
        "sharp"
      ]
    },
    {
      "name": "id-card",
      "tags": [
        "card",
        "id"
      ]
    },
    {
      "name": "id-card-outline",
      "tags": [
        "card",
        "id",
        "outline"
      ]
    },
    {
      "name": "id-card-sharp",
      "tags": [
        "card",
        "id",
        "sharp"
      ]
    },
    {
      "name": "image",
      "tags": [
        "camera",
        "image",
        "photo"
      ]
    },
    {
      "name": "image-outline",
      "tags": [
        "camera",
        "image",
        "outline",
        "photo"
      ]
    },
    {
      "name": "image-sharp",
      "tags": [
        "camera",
        "image",
        "photo",
        "sharp"
      ]
    },
    {
      "name": "images",
      "tags": [
        "images",
        "photo"
      ]
    },
    {
      "name": "images-outline",
      "tags": [
        "images",
        "outline",
        "photo"
      ]
    },
    {
      "name": "images-sharp",
      "tags": [
        "images",
        "photo",
        "sharp"
      ]
    },
    {
      "name": "infinite",
      "tags": [
        "forever",
        "infinite",
        "loop"
      ]
    },
    {
      "name": "infinite-outline",
      "tags": [
        "forever",
        "infinite",
        "loop",
        "outline"
      ]
    },
    {
      "name": "infinite-sharp",
      "tags": [
        "forever",
        "infinite",
        "loop",
        "sharp"
      ]
    },
    {
      "name": "information",
      "tags": [
        "circle",
        "help",
        "information",
        "knowledge"
      ]
    },
    {
      "name": "information-circle",
      "tags": [
        "circle",
        "help",
        "information",
        "knowledge"
      ]
    },
    {
      "name": "information-circle-outline",
      "tags": [
        "circle",
        "help",
        "information",
        "knowledge",
        "outline"
      ]
    },
    {
      "name": "information-circle-sharp",
      "tags": [
        "circle",
        "help",
        "information",
        
Download .txt
gitextract_m0sxkfw_/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   ├── feature_request.yml
│   │   ├── icon_request.yml
│   │   └── incorrect_icon.yml
│   ├── ionic-issue-bot.yml
│   └── workflows/
│       ├── actions/
│       │   ├── build-core/
│       │   │   └── action.yml
│       │   ├── download-archive/
│       │   │   └── action.yml
│       │   ├── publish-npm/
│       │   │   └── action.yml
│       │   ├── test-e2e/
│       │   │   └── action.yml
│       │   ├── test-spec/
│       │   │   └── action.yml
│       │   ├── update-reference-screenshots/
│       │   │   └── action.yml
│       │   └── upload-archive/
│       │       └── action.yml
│       ├── dev-release.yml
│       ├── production-release.yml
│       ├── release-orchestrator.yml
│       ├── update-screenshots.yml
│       └── validation.yml
├── .gitignore
├── .prettierrc.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── jest.config.mjs
├── package.json
├── playwright.config.ts
├── readme.md
├── scripts/
│   ├── build.ts
│   ├── cheatsheet-template.html
│   ├── collection-copy.ts
│   ├── constants.ts
│   ├── plugins.ts
│   ├── readme.md
│   └── types.ts
├── src/
│   ├── components/
│   │   ├── icon/
│   │   │   ├── icon.css
│   │   │   ├── icon.tsx
│   │   │   ├── readme.md
│   │   │   ├── request.ts
│   │   │   ├── svg/
│   │   │   │   └── .gitignore
│   │   │   ├── test/
│   │   │   │   ├── icon.e2e.ts
│   │   │   │   ├── icon.spec.ts
│   │   │   │   ├── utils.spec.ts
│   │   │   │   └── validate.spec.ts
│   │   │   ├── utils.ts
│   │   │   └── validate.ts
│   │   └── test/
│   │       ├── csp/
│   │       │   ├── icon.e2e.ts
│   │       │   └── index.html
│   │       └── dynamic-type/
│   │           ├── icon.e2e.ts
│   │           └── index.html
│   ├── components.d.ts
│   ├── data.json
│   ├── index.html
│   ├── index.ts
│   ├── ionicons.web-types.json
│   └── utils/
│       └── test/
│           └── playwright/
│               ├── index.ts
│               ├── page/
│               │   └── utils/
│               │       ├── goto.ts
│               │       └── index.ts
│               ├── playwright-declarations.ts
│               └── playwright-page.ts
├── stencil.config.ts
├── tsconfig.json
└── tsconfig.spec.json
Download .txt
SYMBOL INDEX (41 symbols across 9 files)

FILE: scripts/build.ts
  function build (line 11) | async function build(rootDir: string) {
  function optimizeSvgs (line 63) | async function optimizeSvgs(srcSvgData: SvgData[]) {
  function optimizeSvg (line 71) | async function optimizeSvg(svgData: SvgData) {
  function copyToTesting (line 97) | async function copyToTesting(rootDir: string, distDir: string, srcSvgDat...
  function createSvgSymbols (line 119) | async function createSvgSymbols(version: string, distDir: string, srcSvg...
  function createCheatsheet (line 160) | async function createCheatsheet(
  function createWebTypes (line 185) | async function createWebTypes(version: string, rootDir: string, distDir:...
  function getSvgs (line 204) | async function getSvgs(srcSvgDir: string, distSvgDir: string, optimizedS...
  function createIconPackage (line 273) | async function createIconPackage(version: string, iconDir: string, srcSv...
  function createEsmIcons (line 281) | async function createEsmIcons(version: string, iconDir: string, srcSvgDa...
  function createCjsIcons (line 293) | async function createCjsIcons(version: string, iconDir: string, srcSvgDa...
  function createDtsIcons (line 305) | async function createDtsIcons(version: string, iconDir: string, srcSvgDa...
  function getDataUrl (line 317) | function getDataUrl(svgData: SvgData) {
  function createDataJson (line 334) | async function createDataJson(version: string, srcDir: string, distDir: ...
  function camelize (line 378) | function camelize(text: string) {
  function upFirst (line 383) | function upFirst(word: string) {
  function toTitleCase (line 387) | function toTitleCase(str: string) {

FILE: scripts/collection-copy.ts
  function collectionCopy (line 4) | async function collectionCopy(rootDir: string) {

FILE: scripts/types.ts
  type SvgData (line 3) | interface SvgData {

FILE: src/components.d.ts
  type IonIcon (line 9) | interface IonIcon {
  type HTMLIonIconElement (line 60) | interface HTMLIonIconElement extends Components.IonIcon, HTMLStencilElem...
  type HTMLElementTagNameMap (line 65) | interface HTMLElementTagNameMap {
  type IonIcon (line 70) | interface IonIcon {
  type IntrinsicElements (line 119) | interface IntrinsicElements {
  type IntrinsicElements (line 126) | interface IntrinsicElements {

FILE: src/components/icon/icon.tsx
  class Icon (line 11) | class Icon {
    method componentWillLoad (line 84) | componentWillLoad() {
    method connectedCallback (line 88) | connectedCallback() {
    method componentDidLoad (line 103) | componentDidLoad() {
    method disconnectedCallback (line 118) | disconnectedCallback() {
    method waitUntilVisible (line 131) | private waitUntilVisible(el: HTMLElement, rootMargin: string, cb: () =...
    method loadIcon (line 173) | loadIcon() {
    method render (line 192) | render() {

FILE: src/components/icon/request.ts
  function safeFallback (line 11) | function safeFallback(url: string) {
  function getSvgByUrl (line 41) | function getSvgByUrl(url: string): string {
  function fetchSvg (line 59) | function fetchSvg(url: string, sanitize: boolean): Promise<string> {

FILE: src/components/icon/utils.ts
  constant CACHED_MAP (line 4) | let CACHED_MAP: Map<string, string>;

FILE: src/utils/test/playwright/playwright-declarations.ts
  type E2EPage (line 3) | interface E2EPage extends Page {

FILE: src/utils/test/playwright/playwright-page.ts
  type CustomTestArgs (line 13) | type CustomTestArgs = PlaywrightTestArgs &
  type CustomFixtures (line 20) | type CustomFixtures = {
  function extendPageFixture (line 30) | async function extendPageFixture(page: E2EPage, testInfo: TestInfo) {
Condensed preview — 62 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (332K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "chars": 1353,
    "preview": "name: 🐛 Bug Report\ndescription: Report a bug in the ion-icon component. Incorrect icons should use the \"Incorrect Icon\" "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "chars": 903,
    "preview": "name: 💡 Feature Request\ndescription: Suggest a new feature for the ion-icon component. Icon requests should use the \"Ico"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/icon_request.yml",
    "chars": 589,
    "preview": "name: 🚀 Icon Request\ndescription: Request a new icon\nlabels: ['triage']\ntitle: 'icon request: '\nbody:\n  - type: textarea"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/incorrect_icon.yml",
    "chars": 548,
    "preview": "name: 😒 Incorrect Icon\ndescription: Report an incorrect icon\nlabels: ['triage']\ntitle: 'incorrect icon: '\nbody:\n  - type"
  },
  {
    "path": ".github/ionic-issue-bot.yml",
    "chars": 3858,
    "preview": "triage:\n  label: triage\n  dryRun: false\n\ncloseAndLock:\n  labels:\n    - label: 'ionitron: support'\n      message: >\n     "
  },
  {
    "path": ".github/workflows/actions/build-core/action.yml",
    "chars": 972,
    "preview": "name: 'Build Ionicons'\ndescription: 'Build Ionicons'\nruns:\n  using: 'composite'\n  steps:\n    - uses: actions/checkout@v4"
  },
  {
    "path": ".github/workflows/actions/download-archive/action.yml",
    "chars": 504,
    "preview": "name: 'Archive Download'\ndescription: 'Downloads and decompresses an archive from a previous job'\ninputs:\n  path:\n    de"
  },
  {
    "path": ".github/workflows/actions/publish-npm/action.yml",
    "chars": 1981,
    "preview": "name: 'Release'\ndescription: 'Releases a package'\ninputs:\n  version:\n    description: 'The type of version to release.'\n"
  },
  {
    "path": ".github/workflows/actions/test-e2e/action.yml",
    "chars": 3284,
    "preview": "name: 'Test E2E'\ndescription: 'Test E2E'\ninputs:\n  shard:\n    description: 'Playwright Test Shard (ex: 2)'\n  totalShards"
  },
  {
    "path": ".github/workflows/actions/test-spec/action.yml",
    "chars": 582,
    "preview": "name: 'Test Spec'\ndescription: 'Test Spec'\nruns:\n  using: 'composite'\n  steps:\n    - uses: actions/setup-node@v4\n\n    - "
  },
  {
    "path": ".github/workflows/actions/update-reference-screenshots/action.yml",
    "chars": 1261,
    "preview": "name: 'Update Reference Screenshots'\ndescription: 'Update Reference Screenshots'\n\non:\n  workflow_dispatch:\n\nruns:\n  usin"
  },
  {
    "path": ".github/workflows/actions/upload-archive/action.yml",
    "chars": 522,
    "preview": "name: 'Archive Upload'\ndescription: 'Compresses and uploads an archive to be reused across jobs'\ninputs:\n  paths:\n    de"
  },
  {
    "path": ".github/workflows/dev-release.yml",
    "chars": 1161,
    "preview": "name: 'Dev Release'\n\non:\n  workflow_call:\n\njobs:\n  create-dev-hash:\n    runs-on: ubuntu-latest\n    outputs:\n      dev-ha"
  },
  {
    "path": ".github/workflows/production-release.yml",
    "chars": 674,
    "preview": "name: 'Production Release'\n\non:\n  workflow_call:\n    inputs:\n      version:\n        required: false\n        type: string"
  },
  {
    "path": ".github/workflows/release-orchestrator.yml",
    "chars": 778,
    "preview": "name: 'Release Orchestrator'\n\non:\n  workflow_dispatch:\n    inputs:\n      release-type:\n        description: 'Release typ"
  },
  {
    "path": ".github/workflows/update-screenshots.yml",
    "chars": 1551,
    "preview": "name: 'Update Reference Screenshots'\n\non:\n  workflow_dispatch:\n\njobs:\n  build-core:\n    runs-on: ubuntu-latest\n    steps"
  },
  {
    "path": ".github/workflows/validation.yml",
    "chars": 2115,
    "preview": "name: 'Validation'\n\non:\n  pull_request:\n    branches: ['**']\n  push:\n    branches: ['main']\n\n# When pushing a new commit"
  },
  {
    "path": ".gitignore",
    "chars": 297,
    "preview": "*~\n*.sw[mnpcod]\n*.log\n*.lock\n*.tmp\n*.tmp.*\nlog.txt\n*.sublime-project\n*.sublime-workspace\n.idea/\n.versions/\n.vscode/\n/com"
  },
  {
    "path": ".prettierrc.json",
    "chars": 267,
    "preview": "{\n  \"arrowParens\": \"always\",\n  \"bracketSpacing\": true,\n  \"jsxBracketSameLine\": false,\n  \"jsxSingleQuote\": false,\n  \"quot"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 72,
    "preview": "# Change Log\n\nPlease see https://github.com/ionic-team/ionicons/releases"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 1142,
    "preview": "# Contributor Code of Conduct\n\nAs contributors and maintainers of the Ionicons project, we pledge to respect everyone wh"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 5537,
    "preview": "# Contributing to Ionicons\n\nThank you for your interest in contributing to Ionicons! :tada:\n\nThis document outlines the "
  },
  {
    "path": "LICENSE",
    "chars": 1099,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015-present Ionic (http://ionic.io/)\n\nPermission is hereby granted, free of charge"
  },
  {
    "path": "jest.config.mjs",
    "chars": 466,
    "preview": "import path from 'path';\nimport url from 'url';\n\nimport { createJestStencilPreset } from 'jest-stencil-runner';\n\nconst _"
  },
  {
    "path": "package.json",
    "chars": 3289,
    "preview": "{\n  \"name\": \"ionicons\",\n  \"version\": \"8.0.13\",\n  \"description\": \"Premium icons for Ionic.\",\n  \"files\": [\n    \"components"
  },
  {
    "path": "playwright.config.ts",
    "chars": 2858,
    "preview": "import type { PlaywrightTestConfig } from '@playwright/test';\nimport { devices, expect } from '@playwright/test';\n\nconst"
  },
  {
    "path": "readme.md",
    "chars": 5668,
    "preview": "# Ionicons\n\n[Ionicons](http://ionicons.com/) is a completely open-source icon set with 1,300 icons crafted for web, iOS,"
  },
  {
    "path": "scripts/build.ts",
    "chars": 12398,
    "preview": "import path from 'node:path';\n\nimport fs from 'fs-extra';\nimport { optimize } from 'svgo';\n\nimport { webComponentPassPlu"
  },
  {
    "path": "scripts/cheatsheet-template.html",
    "chars": 753,
    "preview": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>Ionicons {{version}} Cheatsheet</title>\n  <style>\n    bo"
  },
  {
    "path": "scripts/collection-copy.ts",
    "chars": 1682,
    "preview": "import fs from 'fs-extra';\nimport { join } from 'path';\n\nasync function collectionCopy(rootDir: string) {\n  // move opti"
  },
  {
    "path": "scripts/constants.ts",
    "chars": 664,
    "preview": "// https://mathiasbynens.be/notes/reserved-keywords\nexport const reservedKeywords = new Set([\n  'do',\n  'if',\n  'in',\n  "
  },
  {
    "path": "scripts/plugins.ts",
    "chars": 2520,
    "preview": "import { PluginConfig } from 'svgo';\n\nconst setRootIoniconClass: PluginConfig = {\n  name: 'addClassesToSVGElement',\n  pa"
  },
  {
    "path": "scripts/readme.md",
    "chars": 1421,
    "preview": "# Development and Build Scripts\n\n## Updating Icons\n\nThe `src/svg` directory is the single source of truth for svgs. They"
  },
  {
    "path": "scripts/types.ts",
    "chars": 709,
    "preview": "import { PluginConfig } from 'svgo';\n\nexport interface SvgData {\n  /**\n   * airplane-outline.svg\n   */\n  fileName: strin"
  },
  {
    "path": "src/components/icon/icon.css",
    "chars": 2922,
    "preview": ":host {\n  display: inline-block;\n\n  width: 1em;\n  height: 1em;\n\n  contain: strict;\n\n  fill: currentColor;\n\n  box-sizing:"
  },
  {
    "path": "src/components/icon/icon.tsx",
    "chars": 6900,
    "preview": "import { Build, Component, Element, Host, Prop, State, Watch, h } from '@stencil/core';\nimport { getSvgContent, ioniconC"
  },
  {
    "path": "src/components/icon/readme.md",
    "chars": 3566,
    "preview": "# ion-icon\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property   | Attribute  | Description                    "
  },
  {
    "path": "src/components/icon/request.ts",
    "chars": 2325,
    "preview": "import { isEncodedDataUrl, isSvgDataUrl, validateContent } from './validate';\n\nexport const ioniconContent = new Map<str"
  },
  {
    "path": "src/components/icon/svg/.gitignore",
    "chars": 153,
    "preview": "# this gitignore file is used as a placeholder\n# for this directory. The directory itself will\n# contain files generated"
  },
  {
    "path": "src/components/icon/test/icon.e2e.ts",
    "chars": 2813,
    "preview": "import { expect } from '@playwright/test';\nimport { test } from '@utils/test/playwright';\n\ntest.describe('icon: basic', "
  },
  {
    "path": "src/components/icon/test/icon.spec.ts",
    "chars": 2202,
    "preview": "import { newSpecPage } from 'jest-stencil-runner';\nimport { Icon } from '../icon';\n\ndescribe('icon', () => {\n  it('rende"
  },
  {
    "path": "src/components/icon/test/utils.spec.ts",
    "chars": 4683,
    "preview": "import { Icon } from '../icon';\nimport { addIcons, getIconMap, getName, getSrc, getUrl } from '../utils';\n\ndescribe('get"
  },
  {
    "path": "src/components/icon/test/validate.spec.ts",
    "chars": 2177,
    "preview": "import { isEncodedDataUrl, isSvgDataUrl, isValid } from '../validate';\n\ndescribe('isValid', () => {\n  it('invalid onload"
  },
  {
    "path": "src/components/icon/utils.ts",
    "chars": 5570,
    "preview": "import { getAssetPath } from '@stencil/core';\nimport { Icon } from './icon';\n\nlet CACHED_MAP: Map<string, string>;\n\nexpo"
  },
  {
    "path": "src/components/icon/validate.ts",
    "chars": 1534,
    "preview": "import { isStr } from './utils';\n\nexport const validateContent = (svgContent: string) => {\n  const div = document.create"
  },
  {
    "path": "src/components/test/csp/icon.e2e.ts",
    "chars": 367,
    "preview": "import { expect } from '@playwright/test';\nimport { test } from '../../../utils/test/playwright';\n\ntest.describe('icon: "
  },
  {
    "path": "src/components/test/csp/index.html",
    "chars": 2092,
    "preview": "<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\" mode=\"ios\">\n\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content"
  },
  {
    "path": "src/components/test/dynamic-type/icon.e2e.ts",
    "chars": 549,
    "preview": "import { expect } from '@playwright/test';\nimport { test } from '../../../utils/test/playwright';\n\ntest.describe('icon: "
  },
  {
    "path": "src/components/test/dynamic-type/index.html",
    "chars": 935,
    "preview": "<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\" mode=\"ios\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" co"
  },
  {
    "path": "src/components.d.ts",
    "chars": 3803,
    "preview": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It co"
  },
  {
    "path": "src/data.json",
    "chars": 170692,
    "preview": "{\n  \"icons\": [\n    {\n      \"name\": \"accessibility\",\n      \"tags\": [\n        \"accessibility\"\n      ]\n    },\n    {\n      \""
  },
  {
    "path": "src/index.html",
    "chars": 6942,
    "preview": "<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\" mode=\"ios\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" co"
  },
  {
    "path": "src/index.ts",
    "chars": 152,
    "preview": "export { setAssetPath } from '@stencil/core';\n\nexport { addIcons } from './components/icon/utils';\nexport type { Compone"
  },
  {
    "path": "src/ionicons.web-types.json",
    "chars": 3418,
    "preview": "{\n  \"$schema\": \"http://json.schemastore.org/web-types\",\n  \"name\": \"ionicons\",\n  \"version\": \"0.0.0\",\n  \"description-marku"
  },
  {
    "path": "src/utils/test/playwright/index.ts",
    "chars": 78,
    "preview": "export * from './playwright-page';\nexport * from './playwright-declarations';\n"
  },
  {
    "path": "src/utils/test/playwright/page/utils/goto.ts",
    "chars": 607,
    "preview": "import type { Page, TestInfo } from '@playwright/test';\n\n/**\n * This is an extended version of Playwright's\n * page.goto"
  },
  {
    "path": "src/utils/test/playwright/page/utils/index.ts",
    "chars": 24,
    "preview": "export * from './goto';\n"
  },
  {
    "path": "src/utils/test/playwright/playwright-declarations.ts",
    "chars": 3448,
    "preview": "import type { Page, Response } from '@playwright/test';\n\nexport interface E2EPage extends Page {\n  /**\n   * Returns the "
  },
  {
    "path": "src/utils/test/playwright/playwright-page.ts",
    "chars": 1525,
    "preview": "import type {\n  PlaywrightTestArgs,\n  PlaywrightTestOptions,\n  PlaywrightWorkerArgs,\n  PlaywrightWorkerOptions,\n  TestIn"
  },
  {
    "path": "stencil.config.ts",
    "chars": 738,
    "preview": "import { Config } from '@stencil/core';\n\nexport const config: Config = {\n  namespace: 'ionicons',\n  sourceMap: false,\n  "
  },
  {
    "path": "tsconfig.json",
    "chars": 552,
    "preview": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"strict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnr"
  },
  {
    "path": "tsconfig.spec.json",
    "chars": 64,
    "preview": "{\n  \"extends\": \"tsconfig.json\",\n  \"exclude\": [\"node_modules\"]\n}\n"
  }
]

About this extraction

This page contains the full source code of the ionic-team/ionicons GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 62 files (287.4 KB), approximately 79.3k tokens, and a symbol index with 41 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!