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 `
```
you can replace `latest` to pick any version of Ionicon, e.g.:
```html
```
### Basic usage
To use a built-in icon from the Ionicons package, populate the `name` attribute on the ion-icon component:
```html
```
### 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 `` 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
```
#### 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 "/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
```
## 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
```
### 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
```
## Size
To specify the icon size, you can use the size attribute for our pre-defined font sizes.
```html
```
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
```
```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 = [
`