Skip to content

new: favicon package for Solid 2.0#1001

Open
davedbase wants to merge 11 commits into
solidjs-community:nextfrom
davedbase:v2/create-favicon
Open

new: favicon package for Solid 2.0#1001
davedbase wants to merge 11 commits into
solidjs-community:nextfrom
davedbase:v2/create-favicon

Conversation

@davedbase

@davedbase davedbase commented Jul 27, 2026

Copy link
Copy Markdown
Member

Primitives for controlling the document favicon, built for Solid 2.0 (beta.24).

What's in it

  • makeFavicon / createFavicon — the base primitive: swap the favicon <link> href, restore the previous one on cleanup.
  • makeFaviconAnimation / createFaviconAnimation — cycle a sequence of hrefs on an interval (build-status spinners, "recording" pulses), auto-pausing while the tab is hidden.
  • makeFaviconBadge / createFaviconBadge — composite a notification count/dot onto a base icon via canvas.
  • makeFaviconScheme / createFaviconScheme — swap between a light/dark icon to track prefers-color-scheme.
  • makeFaviconProgress / createFaviconProgress — composite a progress ring onto a base icon, for upload/download-style indicators.
  • FaviconLink — a Solid component that renders the favicon <link> directly, so its href is part of the server-rendered HTML rather than only applied post-hydration; composes automatically with any of the reactive primitives above via a shared "reuse existing link" lookup.

Each capability is a small, focused make*/create* pair rather than one kitchen-sink createAdvancedFavicon — consistent with this repo's existing layered-primitive packages (e.g. video). Full reasoning in DESIGN.md.

Notes

  • All primitives are SSR-safe (isServer-guarded) and integrate with <Loading>/hydration the normal way; FaviconLink closes the remaining gap by letting the initial favicon ship in the server-rendered HTML itself — see the README for SolidStart/Astro integration examples.
  • 57 browser + 13 SSR tests, tsc/lint/build all clean.

Summary by CodeRabbit

  • New Features

    • Added the new @solid-primitives/favicon package.
    • Supports favicon swapping, animation, notification badges, progress rings, and light/dark scheme switching.
    • Added SSR-compatible FaviconLink support for initial document head rendering.
    • Includes reactive and non-reactive APIs with automatic cleanup and visibility-aware animation behavior.
  • Documentation

    • Added comprehensive usage documentation, examples, Storybook demonstrations, and licensing information.

@davedbase davedbase added this to the Solid 2.0 Migration milestone Jul 27, 2026
@davedbase davedbase added the enhancement New feature or request label Jul 27, 2026
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2565fcb4-4090-4df6-b3e8-3b9e45e1b1e6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@changeset-bot

changeset-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 853a439

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solid-primitives/favicon Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@davedbase davedbase changed the title new: favicon package for Solid 2 new: favicon package for Solid 2.0 Jul 27, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (1)
packages/favicon/src/canvas.ts (1)

8-15: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider img.crossOrigin = "anonymous" for remote icons.

Without it, a cross-origin base icon taints the canvas and toDataURL throws SecurityError later in renderBadgeIcon/renderProgressIcon. Setting it opt-in (or via an option) lets CORS-enabled hosts work; combined with the rejection handling suggested below, non-CORS hosts degrade to the plain href.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/favicon/src/canvas.ts` around lines 8 - 15, Update loadImage to set
the created image element’s crossOrigin property to "anonymous" before assigning
img.src, enabling CORS for remote icons while preserving the existing load and
rejection behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/favicon/src/animation.ts`:
- Around line 182-191: Update the frames effect callback to resume playback when
the list grows from zero or one frame to multiple frames and autoplay is
enabled, while preserving the existing pause behavior when shrinking to one or
fewer frames. Use the existing playing state and play/pause controls in the
createEffect handler around setFrame and favicon.setHref.

In `@packages/favicon/src/badge.ts`:
- Around line 106-108: Update makeFavicon in packages/favicon/src/badge.ts at
lines 106-108 and makeFaviconProgress in packages/favicon/src/progress.ts at
lines 82-84 to guard asynchronous render completion: preserve the base href on
rejection, prevent setHref after disposal, and return a wrapped controller whose
dispose marks it disposed. Prefer extracting this shared guard into a helper in
packages/favicon/src/canvas.ts alongside createCanvasFavicon.

In `@packages/favicon/src/canvas.ts`:
- Around line 72-94: Update redraw to handle rejected render promises by
catching failures without producing unhandled rejections, and invalidate pending
renders during onCleanup so settled draws cannot call favicon.setHref or
setCurrent after disposal. Reuse the existing requestId guard by advancing or
otherwise invalidating requestId in cleanup before calling favicon.dispose.

In `@packages/favicon/src/link.ts`:
- Line 26: Update the previousHref capture in the link reuse logic to read the
raw href attribute rather than HTMLLinkElement.href, preserving undefined when
the attribute is absent. Ensure the restoration logic around previousHref does
not write an empty string back, so reused attribute-less link elements remain
without an href.

In `@packages/favicon/test/badge.test.ts`:
- Around line 101-109: Update the test around createFaviconBadge to retain and
invoke the createRoot disposal callback after asserting the initial badge, then
verify href is restored to baseHref. Ensure cleanup runs within the test so the
reactive root does not leak.

In `@packages/favicon/test/progress.test.ts`:
- Around line 95-103: Update the “applies the initial progress and restores on
cleanup” test to retain the disposer returned by createRoot and invoke it after
asserting the initial favicon progress, then flush pending microtasks and assert
the cleanup restoration behavior. Ensure the root is explicitly disposed so the
registered onCleanup handler executes.

In `@packages/favicon/test/setup.ts`:
- Around line 98-115: Register the favicon test setup module in the shared jsdom
Vitest setupFiles configuration so it runs before source-module imports and
activates window.matchMedia early. Update the setup around the
HTMLImageElement.prototype src mock to assert that the fake matchMedia and
synthetic image-load state are installed successfully.

In `@patches/storybook-solidjs-vite`@10.5.2.patch:
- Around line 10-24: Correct the TypeScript module import paths in the Storybook
SolidJS Vite patch: change both the static `ts` import and the dynamic import
inside `getOrCreateSolidComponentMetaManager` from four parent traversals to
three, targeting the stable `typescript@6.0.3` store path.

In `@template/stories/tsconfig.json`:
- Line 2: Update the extends path in the template/stories tsconfig to reference
the repository’s .storybook/tsconfig.json from the template/stories directory,
removing the extra parent traversal. Preserve the existing Storybook
configuration target.

---

Nitpick comments:
In `@packages/favicon/src/canvas.ts`:
- Around line 8-15: Update loadImage to set the created image element’s
crossOrigin property to "anonymous" before assigning img.src, enabling CORS for
remote icons while preserving the existing load and rejection behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 473766a4-bead-47f9-b082-fd27098f8c1d

📥 Commits

Reviewing files that changed from the base of the PR and between a68e67c and 63b3375.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (32)
  • .changeset/favicon-initial.md
  • packages/favicon/LICENSE
  • packages/favicon/README.md
  • packages/favicon/package.json
  • packages/favicon/src/animation.ts
  • packages/favicon/src/badge.ts
  • packages/favicon/src/canvas.ts
  • packages/favicon/src/components.tsx
  • packages/favicon/src/favicon.ts
  • packages/favicon/src/index.ts
  • packages/favicon/src/link.ts
  • packages/favicon/src/progress.ts
  • packages/favicon/src/scheme.ts
  • packages/favicon/stories/_helpers.tsx
  • packages/favicon/stories/createFavicon.stories.tsx
  • packages/favicon/stories/createFaviconAnimation.stories.tsx
  • packages/favicon/stories/createFaviconBadge.stories.tsx
  • packages/favicon/stories/createFaviconProgress.stories.tsx
  • packages/favicon/stories/createFaviconScheme.stories.tsx
  • packages/favicon/stories/tsconfig.json
  • packages/favicon/test/animation.test.ts
  • packages/favicon/test/badge.test.ts
  • packages/favicon/test/components.test.tsx
  • packages/favicon/test/favicon.test.ts
  • packages/favicon/test/progress.test.ts
  • packages/favicon/test/scheme.test.ts
  • packages/favicon/test/server.test.tsx
  • packages/favicon/test/setup.ts
  • packages/favicon/tsconfig.json
  • patches/storybook-solidjs-vite@10.5.2.patch
  • pnpm-workspace.yaml
  • template/stories/tsconfig.json

Comment thread packages/favicon/src/animation.ts
Comment thread packages/favicon/src/badge.ts Outdated
Comment thread packages/favicon/src/canvas.ts Outdated
Comment thread packages/favicon/src/link.ts Outdated
Comment thread packages/favicon/test/badge.test.ts
Comment thread packages/favicon/test/progress.test.ts
Comment thread packages/favicon/test/setup.ts Outdated
Comment thread patches/storybook-solidjs-vite@10.5.2.patch
Comment thread template/stories/tsconfig.json Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant