diff --git a/jest.config.mjs b/jest.config.mjs index 5776c48a4..e30b3937f 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -6,8 +6,9 @@ import { createJestStencilPreset } from 'jest-stencil-runner'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); export default createJestStencilPreset({ - rootDir: __dirname, + rootDir: __dirname, // Add any additional Jest configuration here + setupFilesAfterEnv: ['/jest.setup.js'], collectCoverageFrom: [ 'src/**/*.{ts,tsx}', '!src/**/*.d.ts', diff --git a/jest.setup.js b/jest.setup.js new file mode 100644 index 000000000..5eed6c10a --- /dev/null +++ b/jest.setup.js @@ -0,0 +1,2 @@ +const Stencil = require('@stencil/core'); +Stencil.Build.isBrowser = true; diff --git a/scripts/readme.md b/scripts/readme.md index d63ba9898..042c3f9b7 100644 --- a/scripts/readme.md +++ b/scripts/readme.md @@ -28,12 +28,11 @@ 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`. +Releases are automated via GitHub Actions. To trigger a release: + +1. Go to the [Release Orchestrator](https://github.com/ionic-team/ionicons/actions/workflows/release-orchestrator.yml) workflow +2. Click "Run workflow" +3. Select the release type: + - **dev** — Creates a pre-release with a timestamp-based version (e.g., `8.0.14-dev.11784821417.1c794397`) + - **production** — Creates a semver release; select `patch`, `minor`, or `major` +4. The workflow will build, publish to NPM, and create a GitHub release (for production releases) diff --git a/src/components/icon/icon.css b/src/components/icon/icon.css index 4c22da6e9..233ebe89a 100644 --- a/src/components/icon/icon.css +++ b/src/components/icon/icon.css @@ -4,12 +4,13 @@ width: 1em; height: 1em; - contain: strict; + font-size: 1em; + + contain: layout style; fill: currentColor; box-sizing: content-box !important; - } :host .ionicon { @@ -24,7 +25,16 @@ stroke-width: var(--ionicon-stroke-width, 32px); } -.icon-inner, +.icon-inner { + display: flex; + + align-items: center; + justify-content: center; + + width: 100%; + height: 100%; +} + .ionicon, svg { display: block; @@ -33,6 +43,14 @@ svg { width: 100%; } +/* Slotted Content + * ----------------------------------------------------------- + */ + +::slotted(*) { + font-size: inherit !important; +} + /* Icon RTL * ----------------------------------------------------------- */ diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx index 2fb162c94..84e4a9622 100755 --- a/src/components/icon/icon.tsx +++ b/src/components/icon/icon.tsx @@ -221,7 +221,9 @@ export class Icon { {Build.isBrowser && this.svgContent ? (
) : ( -
+
+ +
)} ); diff --git a/src/components/icon/test/a11y/index.html b/src/components/icon/test/a11y/index.html index 8e5792982..0b8c7a357 100644 --- a/src/components/icon/test/a11y/index.html +++ b/src/components/icon/test/a11y/index.html @@ -8,6 +8,9 @@ + + + @@ -16,16 +19,41 @@

Icon - Accessibility

-

Icon with aria-label

+

SVG icon with aria-label

-

Button with aria-label

+

Button with aria-label and SVG icon

-

Icon with aria-hidden

+

SVG icon with aria-hidden

+ +
+ +

Font icon with aria-label

+ + + + +

Button with aria-label and font icon

+ + +

Font icon with aria-hidden

+
+ + diff --git a/src/components/icon/test/basic/index.html b/src/components/icon/test/basic/index.html index 260bae789..8e476689a 100644 --- a/src/components/icon/test/basic/index.html +++ b/src/components/icon/test/basic/index.html @@ -88,6 +88,10 @@

Custom CSS

diff --git a/src/components/icon/test/sanitization/index.html b/src/components/icon/test/sanitization/index.html index e867e1451..8d10703e4 100644 --- a/src/components/icon/test/sanitization/index.html +++ b/src/components/icon/test/sanitization/index.html @@ -27,5 +27,11 @@

Base64 URL

src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSJub25lIiBkPSJNMCAwaDI0djI0SDBWMHoiLz48cGF0aCBkPSJNMjAgMkg0Yy0xLjEgMC0yIC45LTIgMnYxOGw0LTRoMTRjMS4xIDAgMi0uOSAyLTJWNGMwLTEuMS0uOS0yLTItMnptMCAxNEg2bC0yIDJWNGgxNnYxMnoiLz48L3N2Zz4=" > + + diff --git a/src/components/icon/test/size/icon.e2e.ts b/src/components/icon/test/size/icon.e2e.ts new file mode 100644 index 000000000..5abd86db2 --- /dev/null +++ b/src/components/icon/test/size/icon.e2e.ts @@ -0,0 +1,40 @@ +import { expect } from '@playwright/test'; +import { test } from '@utils/test/playwright'; + +test.describe('icon: size', () => { + test.beforeEach(async ({ page }) => { + await page.goto(`/icon/test/size/`); + }); + + test('should scale the icon based on the size property', async ({ page }) => { + // Wait for all SVGs to be lazily loaded before taking screenshots + await page.waitForLoadState('networkidle'); + + const main = page.locator('main'); + await expect(main).toHaveScreenshot(`icon-size.png`); + }); + + test('size prop should apply correct font-size to SVG icons', async ({ page }) => { + // Wait for all SVGs to be lazily loaded + await page.waitForLoadState('networkidle'); + + const icons = page.locator('ion-icon[name="heart"]'); + + // Default size is 16px, small is 18px, large is 32px + expect(await icons.nth(0).evaluate((el) => window.getComputedStyle(el).fontSize)).toBe('16px'); + expect(await icons.nth(1).evaluate((el) => window.getComputedStyle(el).fontSize)).toBe('18px'); + expect(await icons.nth(2).evaluate((el) => window.getComputedStyle(el).fontSize)).toBe('32px'); + }); + + test('size prop should apply correct font-size to font icons', async ({ page }) => { + // Wait for document fonts to be ready + await page.evaluate(() => document.fonts.ready); + + const icons = page.locator('ion-icon:not([name])'); + + // Default size is 16px, small is 18px, large is 32px + expect(await icons.nth(0).evaluate((el) => window.getComputedStyle(el).fontSize)).toBe('16px'); + expect(await icons.nth(1).evaluate((el) => window.getComputedStyle(el).fontSize)).toBe('18px'); + expect(await icons.nth(2).evaluate((el) => window.getComputedStyle(el).fontSize)).toBe('32px'); + }); +}); diff --git a/src/components/icon/test/size/icon.e2e.ts-snapshots/icon-size-Mobile-Chrome-linux.png b/src/components/icon/test/size/icon.e2e.ts-snapshots/icon-size-Mobile-Chrome-linux.png new file mode 100644 index 000000000..cd93dbe5e Binary files /dev/null and b/src/components/icon/test/size/icon.e2e.ts-snapshots/icon-size-Mobile-Chrome-linux.png differ diff --git a/src/components/icon/test/size/icon.e2e.ts-snapshots/icon-size-Mobile-Firefox-linux.png b/src/components/icon/test/size/icon.e2e.ts-snapshots/icon-size-Mobile-Firefox-linux.png new file mode 100644 index 000000000..28be0a403 Binary files /dev/null and b/src/components/icon/test/size/icon.e2e.ts-snapshots/icon-size-Mobile-Firefox-linux.png differ diff --git a/src/components/icon/test/size/icon.e2e.ts-snapshots/icon-size-Mobile-Safari-linux.png b/src/components/icon/test/size/icon.e2e.ts-snapshots/icon-size-Mobile-Safari-linux.png new file mode 100644 index 000000000..8189a2527 Binary files /dev/null and b/src/components/icon/test/size/icon.e2e.ts-snapshots/icon-size-Mobile-Safari-linux.png differ diff --git a/src/components/icon/test/size/index.html b/src/components/icon/test/size/index.html new file mode 100644 index 000000000..f2ad57481 --- /dev/null +++ b/src/components/icon/test/size/index.html @@ -0,0 +1,39 @@ + + + + + + Icon - Size + + + + + + + + + + + + +
+

Icon - Size

+ +

Default Icons

+ + + + +

Font Icons

+ + + + + + + + + +
+ + diff --git a/src/components/icon/test/slotted/icon.e2e.ts b/src/components/icon/test/slotted/icon.e2e.ts new file mode 100644 index 000000000..43f333c4e --- /dev/null +++ b/src/components/icon/test/slotted/icon.e2e.ts @@ -0,0 +1,13 @@ +import { expect } from '@playwright/test'; +import { test } from '@utils/test/playwright'; + +test.describe('icon: slotted', () => { + test('should not have visual regressions', async ({ page }) => { + await page.goto(`/icon/test/slotted/`); + + // Wait for all SVGs to be lazily loaded before taking screenshots + await page.waitForLoadState('networkidle'); + + await expect(page).toHaveScreenshot(`icon-slotted.png`, { fullPage: true }); + }); +}); diff --git a/src/components/icon/test/slotted/icon.e2e.ts-snapshots/icon-slotted-Mobile-Chrome-linux.png b/src/components/icon/test/slotted/icon.e2e.ts-snapshots/icon-slotted-Mobile-Chrome-linux.png new file mode 100644 index 000000000..89988fd48 Binary files /dev/null and b/src/components/icon/test/slotted/icon.e2e.ts-snapshots/icon-slotted-Mobile-Chrome-linux.png differ diff --git a/src/components/icon/test/slotted/icon.e2e.ts-snapshots/icon-slotted-Mobile-Firefox-linux.png b/src/components/icon/test/slotted/icon.e2e.ts-snapshots/icon-slotted-Mobile-Firefox-linux.png new file mode 100644 index 000000000..c9ad3cab0 Binary files /dev/null and b/src/components/icon/test/slotted/icon.e2e.ts-snapshots/icon-slotted-Mobile-Firefox-linux.png differ diff --git a/src/components/icon/test/slotted/icon.e2e.ts-snapshots/icon-slotted-Mobile-Safari-linux.png b/src/components/icon/test/slotted/icon.e2e.ts-snapshots/icon-slotted-Mobile-Safari-linux.png new file mode 100644 index 000000000..4d021ebc1 Binary files /dev/null and b/src/components/icon/test/slotted/icon.e2e.ts-snapshots/icon-slotted-Mobile-Safari-linux.png differ diff --git a/src/components/icon/test/slotted/index.html b/src/components/icon/test/slotted/index.html new file mode 100644 index 000000000..74149402b --- /dev/null +++ b/src/components/icon/test/slotted/index.html @@ -0,0 +1,310 @@ + + + + + + Icon - Slotted Content + + + + + + + + + + + + + + + + + + +
+

Icon - Slotted Content

+ +
+
+

Material Icons

+ + home + + + favorite + + + star + + + person + + + settings + + +
+ + + home + + + favorite + + + star + + + warning + + + delete + + +
+ + + home + + + favorite + + + star + +
+ +
+

Phosphor Icons

+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ +
+

Font Awesome Icons

+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ +
+

Bootstrap Icons

+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ +
+

Custom Slotted SVG

+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+
+
+ + + + diff --git a/src/components/icon/test/styles.css b/src/components/icon/test/styles.css index a0a1ff2cf..ab895062f 100644 --- a/src/components/icon/test/styles.css +++ b/src/components/icon/test/styles.css @@ -18,10 +18,6 @@ main { padding: 16px; } -ion-icon { - font-size: 32px; -} - h1 { margin-bottom: 10px; font-size: 28px;