Frameworks

Icons in Preact

Preact führt die React-Komponenten von glyphfox über preact/compat ohne Codeänderungen aus. Wenn Ihre App compat nicht lädt, funktioniert die Web Component glyph-fox in reinem Preact.

Installation

Installieren Sie glyphfox neben Preact. preact/compat ist Teil des Pakets preact, eine zweite Abhängigkeit ist also nicht nötig.

terminal
npm install glyphfox

Es gibt zwei Wege, Icons zu rendern, und beide nutzen dieselbe Rendering-Engine und dieselben Props:

  • Die Komponenten aus glyphfox/react, von Preact über compat ausgeführt. Am besten geeignet, wenn Ihre App React bereits per Alias umleitet oder andere React-Pakete nutzt.
  • Die Web Component <glyph-fox>, die ganz ohne compat auskommt. Am besten geeignet, wenn Sie Preact schlank halten und nur Icons brauchen.

So laufen die Komponenten unter Preact

Der React-Einstiegspunkt importiert genau sechs Dinge aus react: createElement, forwardRef, useState, useEffect, useMemo und useRef. compat implementiert sie alle. Sobald der Bundler react zu preact/compat auflöst, rendern die Komponenten daher mit dem eigenen Renderer von Preact, im selben Baum und mit denselben Hooks wie der Rest Ihrer App.

Die SVG-Attribute werden mit React-Namen wie strokeWidth und strokeLinecap erzeugt, und compat wandelt sie am Element wieder in stroke-width und stroke-linecap um. Die Animationen der lebendigen Zustände sind ein <style>-Element innerhalb des SVG, gesetzt über dangerouslySetInnerHTML, das Preact ebenfalls unterstützt.

Vite

Das offizielle Preact-Preset für Vite leitet react, react-dom und die JSX-Runtime bereits per Alias auf compat um. Mehr ist nicht nötig:

vite.config.js
import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';

export default defineConfig({
  plugins: [preact()],
});

webpack und esbuild

Fügen Sie bei webpack die Aliase zu resolve.alias hinzu. glyphfox braucht nur react, aber wenn Sie den ganzen Satz per Alias umleiten, bleiben alle anderen React-Pakete in Ihrer App auf derselben Preact-Instanz:

webpack.config.js
module.exports = {
  resolve: {
    alias: {
      react: 'preact/compat',
      'react-dom/test-utils': 'preact/test-utils',
      'react-dom': 'preact/compat',
      'react/jsx-runtime': 'preact/jsx-runtime',
    },
  },
};

esbuild bietet dieselbe Option. Aktivieren Sie gleichzeitig Code-Splitting, sonst bettet esbuild jedes Icon-Modul ein, das der On-Demand-Loader erreichen kann (warum, erklärt der Leitfaden zum Tree-Shaking):

build.mjs
import * as esbuild from 'esbuild';

await esbuild.build({
  entryPoints: ['src/main.jsx'],
  bundle: true,
  splitting: true,
  format: 'esm',
  outdir: 'dist',
  jsx: 'automatic',
  jsxImportSource: 'preact',
  alias: { react: 'preact/compat', 'react-dom': 'preact/compat' },
});

TypeScript

Die Deklarationen von glyphfox/react sind gegen die React-Typen geschrieben (ForwardRefExoticComponent, SVGProps). Bilden Sie react in paths auf compat ab, damit sie zu den Typen von Preact aufgelöst werden. Meldet der Typprüfer weiterhin Probleme in den Deklarationsdateien von Abhängigkeiten, lassen Sie skipLibCheck aktiviert, wie es die meisten Preact-Templates tun:

tsconfig.json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact",
    "skipLibCheck": true,
    "paths": {
      "react": ["./node_modules/preact/compat/"],
      "react-dom": ["./node_modules/preact/compat/"]
    }
  }
}

Die Komponenten verwenden

Importieren Sie Icons nach Namen und kombinieren Sie sie wie gewohnt mit Preact-Hooks. Alles aus dem React-Leitfaden gilt auch hier: Icon mit der Namenssyntax, Fusion, MorphIcon, useMorph, Modifier und Refs.

Card.jsx
import { useState } from 'preact/hooks';
import { HeartIcon, MorphIcon, Fusion } from 'glyphfox/react';

export function Card() {
  const [liked, setLiked] = useState(false);
  return (
    <article className="card">
      <button type="button" onClick={() => setLiked(!liked)} aria-pressed={liked}>
        <HeartIcon animate="pop" trigger="state" active={liked} variant={liked ? 'solid' : 'outline'} />
        Like
      </button>
      <MorphIcon name={liked ? 'check' : 'plus'} duration={250} />
      <Fusion icons={['user', 'shield']} layout="badge" />
    </article>
  );
}

Refs laufen über das forwardRef von compat, daher zeigt ref an einem Icon auf das gerenderte <svg>-Element, bereit für getBoundingClientRect() oder die Web Animations API. Event-Handler wie onClick und Attribute wie data-* gehen direkt an das Element, genau wie in React.

Übergeben Sie bei Signals den Wert statt des Signals. Preact entpackt Signals, die an DOM-Attribute gebunden sind, aber eine Icon-Komponente erhält das Signal-Objekt selbst und liest ihre Props als einfache Werte. Sie würde also weder den richtigen Wert lesen noch aktualisiert werden, wenn sich das Signal ändert:

Status.jsx
import { signal } from '@preact/signals';
import { CloudIcon } from 'glyphfox/react';

const syncing = signal(false);

export function Status() {
  return <CloudIcon modifier={syncing.value ? 'sync' : undefined} />;
}

Ohne compat: die Web Component

Das Custom Element <glyph-fox> rendert dieselben Icons mit denselben Props als Attribute in kebab-case. Importieren Sie glyphfox/web einmal, um es mit allen Icons zu definieren, oder definieren Sie es selbst und registrieren Sie nur die Icons, die Sie verwenden:

icons.js
import { defineGlyphFox } from 'glyphfox/web/element';
import { registerIcons } from 'glyphfox/core';
import { iconHome, iconSearch, iconMenu, iconX } from 'glyphfox';

registerIcons([iconHome, iconSearch, iconMenu, iconX]);
defineGlyphFox();
Header.jsx
import { useState } from 'preact/hooks';
import './icons.js';

export function Header() {
  const [open, setOpen] = useState(false);
  return (
    <header>
      <glyph-fox name="home" size="20"></glyph-fox>
      <glyph-fox name="search" weight="1.5" title="Search"></glyph-fox>
      <button type="button" onClick={() => setOpen(!open)} aria-expanded={open} aria-label="Menu">
        <glyph-fox name={open ? 'x' : 'menu'} morph></glyph-fox>
      </button>
    </header>
  );
}

Preact setzt unbekannte Props an Custom Elements als Attribute, und genau auf diese reagiert das Element. Dynamische Werte wie name={open ? 'x' : 'menu'} funktionieren daher, und das Attribut morph animiert jede Änderung. Fügen Sie in TypeScript glyph-fox in einer Deklarationsdatei zu den JSX.IntrinsicElements von Preact hinzu, so wie es die Preact-Dokumentation für jedes Custom Element beschreibt.

Attribute, die Größensteuerung im Shadow DOM und das serverseitige Rendering des Elements behandelt der Leitfaden zu Web Components.

Welcher Weg ist schlanker?

Beide Wege liefern dieselbe Engine (Rendering, Achsen, Modifier, Fusion und Morph), daher kosten die Icons in beiden Fällen etwa gleich viel. Der eigentliche Unterschied ist compat: Lädt Ihre App es bereits für andere Pakete, bringen die Komponenten nichts Neues hinzu; lädt sie es nicht, umgeht die Web Component es. Importieren Sie in beiden Fällen nur die Icons, die Sie verwenden, wie oben gezeigt.

Props

Die Komponenten akzeptieren diese Props. Bei <glyph-fox> sind dieselben Props Attribute in kebab-case (secondary-color, flip-x, morph-to), dazu kommen name, layout, gap und morph.

PropTypStandardBeschreibung
sizenumber, string24Breite und Höhe; Zahlen sind Pixel.
colorstringcurrentColorHauptfarbe.
secondaryColorstringcolorFarbe der Duotone-Ebene und der Solid-Füllung.
secondaryOpacitynumber0.3 / 1Deckkraft der Duotone-Ebene oder der Solid-Füllung.
weightnumber2Strichstärke von 1 bis 3 im 24er-Raster, unter 24 px optisch ausgeglichen.
absoluteWeightbooleanfalseHält den Strich bei jeder Größe auf weight Pixeln.
cornersround, sharproundAbgerundete oder spitze Verbindungen und Enden.
variantoutline, duotone, solidoutlineStilachse; solid entsteht aus den geschlossenen Formen.
rotatenumber0Drehung in Grad.
flipXbooleanfalseHorizontal spiegeln.
flipYbooleanfalseVertikal spiegeln.
mirrorRtlbooleanfalseIn Layouts von rechts nach links spiegeln.
animatedraw, pop, wiggle, spin, pulse, bounce, shakekeinerVoreinstellung für den lebendigen Zustand.
triggermount, hover, click, statemountWann die Animation oder der Morph abläuft.
activebooleanfalseDer Zustand für den Auslöser state.
durationnumber (ms)je nach VoreinstellungDauer der Animation oder des Morphs.
delaynumber (ms)0Verzögerung der Animation oder des Morphs.
loopboolean, numberfalseEndlos oder eine bestimmte Anzahl von Malen wiederholen (spin und pulse laufen standardmäßig in Schleife).
modifierplus, minus, check, x, alert, lock, clock, sync, arrow-up, arrow-down, dotkeinerBadge mit automatischer Aussparung.
modifierCornertop-left, top-right, bottom-left, bottom-rightbottom-rightEcke des Badges.
morphToname, datakeinerZiel des Morphs; der Auslöser bestimmt, wann es erscheint.
titlestringkeinerZugänglicher Name: title, role img und aria-label.
decorativebooleantrue ohne titleVerbirgt das Icon vor assistiven Technologien.

Stolperfallen

Ein fehlender Alias
Ohne den Alias löst der Bundler react zum echten React-Paket auf (oder findet es gar nicht). Die Icons rufen dann Hooks aus einem anderen Renderer auf, was sich in Fehlern wegen ungültiger Hook-Aufrufe („Invalid hook call“) oder in Icons äußert, die sich nie aktualisieren. Prüfen Sie, ob react zu preact/compat aufgelöst wird.
class statt className
Die Komponenten führen className mit ihren eigenen Klassen glyphfox glyphfox-NAME zusammen. Eine class-Prop wird nicht zusammengeführt und kann von diesen Klassen ersetzt werden. Verwenden Sie an Icon-Komponenten daher className.
Zwei Kopien von Preact
compat muss zum selben preact aufgelöst werden wie Ihre App. Eine doppelte Kopie in node_modules legt Hooks genauso lahm wie ein fehlender Alias; deduplizieren Sie sie mit Ihrem Paketmanager.
Signals als Props
Übergeben Sie signal.value an Icon-Komponenten. Das Signal-Objekt selbst wird für Komponenten nicht entpackt.
Leere Elemente vor der Definition
<glyph-fox> zeichnet erst, nachdem defineGlyphFox() im Browser gelaufen ist. Geben Sie dem Element bei vorgerendertem HTML per CSS eine Größe, damit sich das Layout nicht verschiebt, während das Skript lädt.

Häufige Fragen

Brauche ich preact/compat, um glyphfox zu nutzen?

Nur für die Komponenten aus glyphfox/react. Das Element <glyph-fox> und toSvg aus glyphfox funktionieren auch ohne compat in reinem Preact.

Rendern die Komponenten mit preact-render-to-string?

Ja. Über compat rendern sie auf dem Server wie jede React-Komponente, und das SVG steht im HTML. Bei Icons, die per Name mit Icon gerendert werden, müssen die Daten zuerst registriert werden, wie im Leitfaden zum serverseitigen Rendering beschrieben.

Icons in diesem Leitfaden