UNPKG

alouette

Version:

A modern, customizable design system built on top of NativeWind v5 with configurable defaults

197 lines (145 loc) 5.7 kB
--- name: alouette-icons description: > Use Phosphor icons with alouette. Each icon is imported from its own module (alouette-icons/phosphor-icons/IconName) so only what is used is bundled, and is then either rendered through the Icon component or handed as an element to a component that takes one (Button, IconButton, Message). Its color comes from a text-* token class rather than from the SVG, so an icon follows the theme and the accent around it. Load when adding icons to alouette UI. type: composition library: alouette requires: - alouette-theming sources: - "christophehurpeau/alouette:packages/alouette/src/ui/primitives/Icon.tsx" - "christophehurpeau/alouette:packages/alouette/src/ui/primitives/InteractiveIcon.tsx" - "christophehurpeau/alouette:packages/alouette/src/ui/actions/Button.stories.tsx" - "christophehurpeau/alouette:CLAUDE.md" --- This skill builds on alouette-theming. Read it first for color tokens. # alouette + alouette-icons Icons come from the `alouette-icons` package (auto-generated Phosphor icons). Import each icon individually, then render it through alouette's `Icon` component or pass the element to a component's `icon` prop. `Icon` resolves a `text-*` className to a concrete color token and applies it as the SVG color. ## Setup ```tsx import { Icon } from "alouette"; import { HeartRegularIcon } from "alouette-icons/phosphor-icons/HeartRegularIcon"; <Icon icon={<HeartRegularIcon />} size={24} className="text-accent" />; ``` ## Core Patterns ### Icons inside alouette components `Button`, `IconButton` and `Message` take an `icon` element directly — they size and tint it for you. ```tsx import { Button, IconButton } from "alouette"; import { ArrowLeftRegularIcon } from "alouette-icons/phosphor-icons/ArrowLeftRegularIcon"; import { XRegularIcon } from "alouette-icons/phosphor-icons/XRegularIcon"; <Button text="Back" icon={<ArrowLeftRegularIcon />} /> <IconButton icon={<XRegularIcon />} aria-label="Close" onPress={close} /> ``` ### Duotone on interaction `activeIcon` is the interaction twin of `icon`: it replaces it while the pressable is hovered, focused or pressed, and stays for as long as the item is selected (`NavBarItem` on the current page, the selected `Tab`, the checked `RadioButton`). The duotone weight of the same glyph is the intended pairing. Available on `Button`, `IconButton`, `MenuItem`, `NavBarItem`, `Tab` and `RadioButton`; a disabled control never swaps. ```tsx import { HouseDuotoneIcon } from "alouette-icons/phosphor-icons/HouseDuotoneIcon"; import { HouseRegularIcon } from "alouette-icons/phosphor-icons/HouseRegularIcon"; <NavBarItem href="/home" label="Home" icon={<HouseRegularIcon />} activeIcon={<HouseDuotoneIcon />} />; ``` `NavBarItem`, `Tab` and `RadioButton` also take `activeAccent`, tinting the swapped-in glyph with an accent of its own so it changes color as well as weight. It reaches the icon through `text-accent`, the only token an accent theme redeclares for a foreground glyph — an accent scope around an icon that keeps its base tint (`text-sharp`, `text-muted`) does nothing. ```tsx <NavBarItem href="/archive" label="Archive" icon={<TrashRegularIcon />} activeIcon={<TrashDuotoneIcon />} activeAccent="danger" /> ``` `InteractiveIcon` is the exported primitive behind both, for a pressable you build yourself out of `PressableBox` — it cross-fades the two layers off the pressable's `group`, so it only works inside one. ### Tinting Tint follows the current accent when you use `text-accent`: ```tsx <Icon icon={<HeartRegularIcon />} className="text-muted" /> <Box accent="danger"> <Icon icon={<HeartRegularIcon />} className="text-accent" /> </Box> ``` ## Common Mistakes ### MEDIUM Barrel-importing the icon set Wrong: ```tsx import { ArrowLeftRegularIcon } from "alouette-icons"; ``` Correct: ```tsx import { ArrowLeftRegularIcon } from "alouette-icons/phosphor-icons/ArrowLeftRegularIcon"; ``` Icons are individually importable modules; a barrel import pulls in the entire generated set and bloats the bundle. Source: packages/alouette/src/ui/actions/Button.stories.tsx; CLAUDE.md (Icons) ### MEDIUM Tinting an icon with a color prop Wrong: ```tsx <Icon icon={<InfoRegularIcon />} color="#888" /> ``` Correct: ```tsx <Icon icon={<InfoRegularIcon />} className="text-muted" /> ``` `Icon` resolves a `text-*` className to a `--color-*` token and passes it as the SVG color; a raw `color` bypasses theming and breaks mode/accent adaptation. Source: packages/alouette/src/ui/primitives/Icon.tsx ### MEDIUM Sizing an icon with width/height classes Wrong: ```tsx <Icon icon={<InfoRegularIcon />} className="w-6 h-6" /> ``` Correct: ```tsx <Icon icon={<InfoRegularIcon />} size={24} /> ``` `Icon` takes a numeric `size` prop (px) applied as the SVG width/height; `w-*` / `h-*` classes are not how alouette sizes icons. Source: packages/alouette/src/ui/primitives/Icon.tsx ### MEDIUM Swapping the icon weight with local hover state Wrong: ```tsx const [hovered, setHovered] = useState(false); <Button icon={hovered ? <HouseDuotoneIcon /> : <HouseRegularIcon />} onHoverIn={() => setHovered(true)} onHoverOut={() => setHovered(false)} text="Home" />; ``` Correct: ```tsx <Button icon={<HouseRegularIcon />} activeIcon={<HouseDuotoneIcon />} text="Home" /> ``` `activeIcon` cross-fades the two glyphs in CSS off the pressable's `group`, so it covers focus and press as well as hover and never re-renders the row. A JS hover state covers hover only, re-renders on every pointer move in and out, and has no keyboard equivalent. Source: packages/alouette/src/ui/primitives/InteractiveIcon.tsx