UNPKG

alouette

Version:

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

296 lines (213 loc) 9.17 kB
--- name: alouette-feedback description: > Tell the user what happened, in place. Message is the semantic bannerInfoMessage, ConfirmationMessage, WarningMessage and ErrorMessage are its ready-made meaningsoptionally dismissible, and flattened when it sits inside an already-raised surface. ConnectionState is the banner pinned at the top of the screen reporting the network, and LinearProgress and CircularProgress show how far a determinate operation has got. A failure coming out of a button or a form is already rendered by that component, so reach for these for status the screen itself has to state. Load when showing inline status, alerts, dismissible notices, connection status, or progress. type: core library: alouette library_version: "22.11.0" requires: - alouette-theming sources: - "christophehurpeau/alouette:packages/alouette/src/ui/feedback/Message.tsx" - "christophehurpeau/alouette:packages/alouette/src/ui/feedback/Message.stories.tsx" - "christophehurpeau/alouette:packages/alouette/src/ui/feedback/ConnectionState.tsx" - "christophehurpeau/alouette:packages/alouette/src/ui/feedback/ConnectionState.stories.tsx" - "christophehurpeau/alouette:packages/alouette/src/ui/feedback/LinearProgress.tsx" - "christophehurpeau/alouette:packages/alouette/src/ui/feedback/CircularProgress.tsx" --- This skill builds on alouette-theming. Read it first for the accent model. # alouette — Feedback messages `Message` is an accent-themed banner with an icon and optional dismiss button. Prefer the presets `InfoMessage` / `ConfirmationMessage` / `WarningMessage` / `ErrorMessage`, which set the accent and icon for you. ## Setup ```tsx import { InfoMessage } from "alouette"; <InfoMessage>Your changes were saved.</InfoMessage>; ``` ## Core Patterns ### Presets ```tsx import { InfoMessage, ConfirmationMessage, WarningMessage, ErrorMessage } from "alouette"; <InfoMessage>Heads up.</InfoMessage> {/* accent="info" */} <ConfirmationMessage>Saved.</ConfirmationMessage> {/* accent="success" */} <WarningMessage>Careful.</WarningMessage> {/* accent="warning" */} <ErrorMessage>Payment failed.</ErrorMessage> {/* accent="danger" */} ``` ### Dismissible message `onDismiss` and `dismissIconAriaLabel` must be provided together: ```tsx <WarningMessage onDismiss={hide} dismissIconAriaLabel="Dismiss"> Low disk space. </WarningMessage> ``` ### Elevation — `variant` `variant` is `"surface"` (default) or `"flat"`. `surface` carries `shadow-m`: the banner is its own raised layer above the screen background, which is what you want almost everywhere. `flat` only drops the shadow. Reach for it **only** when the message is already inside a raised surface — a `Modal`/`AlertDialog` panel, a `Surface` card, a `PressableListItem` row — where a second elevation reads as a card stacked on a card. Even there, prefer laying the message out on the screen background (its own `surface` banner above or below the card) when the layout allows it; `flat` is the allowance for when it cannot. ```tsx <ErrorMessage>Payment failed.</ErrorMessage> {/* on the page */} <Surface> <Text>Billing</Text> <ErrorMessage variant="flat">Payment failed.</ErrorMessage> {/* inside a card */} </Surface> ``` `AlertDialog` already renders its `errorToMessage` failure flat, and `ActionButton` exposes `errorMessageVariant` for the same reason (see alouette-actions). ### Custom Message (other accents / icons) The four presets cover `info` / `success` / `warning` / `danger`. For a different accent or a custom icon, use the base `Message` with an explicit `accent` and `icon`. `size` is `"sm" | "md" | "lg"`. ```tsx import { Message } from "alouette"; import { XCircleRegularIcon } from "alouette-icons/phosphor-icons/XCircleRegularIcon"; <Message accent="brand" icon={<XCircleRegularIcon />} size="lg"> Custom banner. </Message>; ``` ## Connection status banner `ConnectionState` is a thin banner pinned to the top of its nearest positioned ancestor. It stays hidden while `connected` and slides down to reveal a pill when `connecting` or `disconnected`. It sets its own accent (`success` when connected, `danger` otherwise), so no `accent` prop. ```tsx import { ConnectionState } from "alouette"; <ConnectionState state={status}> {status === "connected" ? "Connected" : "Reconnecting…"} </ConnectionState>; ``` `state` is `"connected" | "connecting" | "disconnected" | null` (`null` renders nothing). `children` is the required pill label. On reconnection it turns green and holds briefly before sliding out. `forceVisible` keeps it on-screen even when connected (demos); `forceHidden` forces it off-screen regardless of state. The banner is absolutely positioned, so its parent must establish a positioning context and clip the off-screen pill — wrap it in `relative overflow-hidden`. ## Progress indicators `LinearProgress` (a thin bar pinned to the top of its positioned ancestor) and `CircularProgress` (a ring) show a **known** completion percentage. Both take `progress` (0-100), `accent` (defaults `brand`), `size` (`"xs" | "sm" | "md" | "lg"`), and `hidden` (fades out without unmounting). The fill animates on `progress` change. ```tsx import { LinearProgress, CircularProgress } from "alouette"; <CircularProgress progress={uploaded} accent="brand" size="md" /> <Box className="relative overflow-hidden"> <LinearProgress progress={uploaded} hidden={uploaded >= 100} /> </Box> ``` For an **unknown**-duration wait (spinner), don't hand-roll one — a `Button` with `state="loading"` already renders the indeterminate spinner (see alouette-actions). There is no exported standalone indeterminate component. ## Common Mistakes ### MEDIUM onDismiss without dismissIconAriaLabel Wrong: ```tsx <InfoMessage onDismiss={hide}>Saved</InfoMessage> ``` Correct: ```tsx <InfoMessage onDismiss={hide} dismissIconAriaLabel="Dismiss"> Saved </InfoMessage> ``` `Message` types `onDismiss` and `dismissIconAriaLabel` as a required pair; providing one without the other is a type error and leaves the dismiss button without an accessible label. Source: packages/alouette/src/ui/feedback/Message.tsx ### MEDIUM Rendering the base Message without accent/icon Wrong: ```tsx <Message>Heads up</Message> ``` Correct: ```tsx <WarningMessage>Heads up</WarningMessage> ``` The base `Message` requires both `accent` and `icon`. For the common cases use a preset, which sets them. Source: packages/alouette/src/ui/feedback/Message.tsx ### MEDIUM Reaching for variant="flat" outside a surface Wrong: ```tsx <VStack> <ErrorMessage variant="flat">Payment failed.</ErrorMessage> </VStack> ``` Correct: ```tsx <VStack> <ErrorMessage>Payment failed.</ErrorMessage> </VStack> ``` `flat` is not "the quiet look" — it is the fix for a banner nested in a raised surface. On the screen background it loses the elevation that separates the banner from the page. Default to `surface`; use `flat` only inside a Modal / AlertDialog panel or a `Surface`, and prefer restructuring so the message can sit on the page instead. Source: packages/alouette/src/ui/feedback/Message.tsx ### MEDIUM Hand-building a colored banner instead of Message Wrong: ```tsx <Box className="bg-yellow-100"> <Text>Warning</Text> </Box> ``` Correct: ```tsx <WarningMessage>Warning</WarningMessage> ``` A manual banner loses accent theming, the leading icon, dark-mode support and the dismiss a11y that `Message` provides. Source: packages/alouette/src/ui/feedback/Message.tsx ### MEDIUM ConnectionState in a non-positioned, non-clipping parent Wrong: ```tsx <Box> <ConnectionState state={status}>Reconnecting…</ConnectionState> </Box> ``` Correct: ```tsx <Box className="relative overflow-hidden"> <ConnectionState state={status}>Reconnecting…</ConnectionState> </Box> ``` The banner is `absolute inset-x-0 top-0` and slides in from off-screen. Without a positioned (`relative`) ancestor it anchors to the wrong element, and without `overflow-hidden` the hidden/pre-slide pill leaks above the container. Source: packages/alouette/src/ui/feedback/ConnectionState.tsx ### LOW Passing accent to ConnectionState `ConnectionState` derives its accent from `state` (`success` when connected, `danger` otherwise) — there is no `accent` prop. To theme it, change `state`. Source: packages/alouette/src/ui/feedback/ConnectionState.tsx ### MEDIUM Using LinearProgress/CircularProgress for an unknown-duration wait Wrong: ```tsx <CircularProgress progress={0} /> {/* as a spinner */} ``` Correct: ```tsx <Button text="Save" state="loading" onPress={save} /> ``` `LinearProgress` / `CircularProgress` are determinate — they render the `progress` value you pass. There is no exported indeterminate variant; a pending, no-percentage wait is a `Button` `state="loading"` spinner (or `ActionButton`). Source: packages/alouette/src/ui/feedback/CircularProgress.tsx; ui/actions/Button.tsx See also: alouette-animation/SKILL.md — render messages in PresenceList for animated add/remove; alouette-data/SKILL.md — Badge, for an inline status pill rather than a banner.