# CLI release notes (/docs/native/releases/cli)

Every version of `delacour`. The CLI that copies components into your app. It shares one version with the other Delacour packages — see [Release channels](/docs/native/releases/channels).

## 0.8.0 [#080]

[GitHub release](https://github.com/delacournz/delacour-ui/releases/tag/v0.8.0)

### Minor changes [#minor-changes]

- [#335](https://github.com/delacournz/delacour-ui/pull/335) The CLI now sends anonymous usage telemetry, on by default: the command, the names (never the values) of the flags typed, the components asked for from the official registry, the outcome and duration, the package manager and Expo SDK, and the OS, runtime and CI or coding-agent context, to `telemetry.delacour.co.nz`. It never sends source code, file names or paths, remote URLs, error messages or an IP address. A notice prints on first use. Turn it off with `delacour telemetry disable`, `DO_NOT_TRACK=1`, `DELACOUR_TELEMETRY_DISABLED=1` or `DELACOUR_CLI_TELEMETRY_DISABLED=1`; `DELACOUR_TELEMETRY_DEBUG=1` prints what would be sent instead. New `delacour telemetry [status|enable|disable]` command, documented at `/docs/native/cli#telemetry`.

## 0.7.0 [#070]

[GitHub release](https://github.com/delacournz/delacour-ui/releases/tag/v0.7.0)

### Minor changes [#minor-changes-1]

- [#327](https://github.com/delacournz/delacour-ui/pull/327) `native-components.json` records a `version`. `init` writes the current one, and `update` brings an older config up to it first: at a terminal it asks once about each option the file predates (`tests.enabled`, and `prefix` while nothing is copied yet), then records the answers and the version. `--yes` keeps the defaults; `--json`, a pipe, CI and the MCP server leave the file alone and name what is still to choose. `doctor` warns on a config that is behind, or written by a newer CLI. The docs gain an Updating guide.

- [#327](https://github.com/delacournz/delacour-ui/pull/327) `init` asks what components should call the library in place of `DelacourUI` (`--prefix <name>` on
  `init` or the first `add` answers it), and `update` asks a project that has no `prefix` even after
  components are copied: answering renames it through every copy, merging into edited files, and lists
  the project's own files that still import `DelacourProvider`. A `prefix` set by hand in
  `native-components.json` is renamed through on the next `update` the same way.

- [#327](https://github.com/delacournz/delacour-ui/pull/327) When `add` or `update` copies tests, it adds `test:ui` (every copied suite), `test:ui:unit` (the
  logic suites) and, on Jest, `test:ui:render` (the render tests) to `package.json`, scoped to the
  component directories so the project's own `test` script is untouched. A script already under one
  of those names is kept as it is.

- [#327](https://github.com/delacournz/delacour-ui/pull/327) `update` lists each component it would change — every file it updates, adds or merges, with a line
  count — and asks which to take; an unticked component is left for the next run. `add` and `update`
  now ask which missing packages to install, one checkbox each, instead of all or nothing.

  `update` no longer adds a component the project does not hold unless the registry introduced it
  since the copy: a dependency the project removed (an icon set swapped for another) is reported and
  offered unticked, and a test that renders a component the project lacks is left out instead of
  copying that component in.

### Patch changes [#patch-changes]

- [#327](https://github.com/delacournz/delacour-ui/pull/327) `update` no longer reports a merge as clean when the project and the registry each added the same line
  in different places. The merge used to keep both — a duplicate parameter in a file that then failed to
  parse — and now writes the region as a conflict to resolve.

- [#327](https://github.com/delacournz/delacour-ui/pull/327) `add` and `update` install a package again at the library's range when `package.json` has it below
  that range — a project on `tailwind-variants` 3 now gets 4, which the copied `lib/tv.ts` imports from.
  The report names each one and the version it found. `update` also reads an old ref out of git when the
  registry is a local directory, so a linked CLI merges an edited file instead of skipping it and
  copying newer tests beside the old source.

- [#327](https://github.com/delacournz/delacour-ui/pull/327) `DELACOUR_REGISTRY` names the registry to read when neither `--registry` nor `registry.url` in `native-components.json` does — a path, a URL or `github:owner/repo`. Empty means the published registry.

- [#327](https://github.com/delacournz/delacour-ui/pull/327) The test kit no longer mocks native modules the project may not have. Skia, Pulsar, MapLibre,
  `expo-linear-gradient` and `expo-blur` each have a mock of their own under `test/mocks/`, copied only
  with a component that installs the module and added to Jest's `setupFiles` — so a project without
  `chart` no longer fails every suite with "Cannot find module 'react-native-skia'".

- [#326](https://github.com/delacournz/delacour-ui/pull/326) `update` no longer crashes with `EPIPE` when the project's formatter exits before reading its input; the file is compared unformatted and the failure reported once.

## 0.6.0 [#060]

[GitHub release](https://github.com/delacournz/delacour-ui/releases/tag/v0.6.0)

### Minor changes [#minor-changes-2]

- [#289](https://github.com/delacournz/delacour-ui/pull/289) Add `prefix` to `native-components.json`: `add` and `update` rename every `DelacourUI` display name and thrown-message tag to it, and `DelacourProvider` to `<prefix>Provider` — `"prefix": "UI"` gives `UI.Flow.Provider` and `UIProvider`. `init` and `doctor` name the provider the same way.

  `add` now installs the plain npm packages the components use (tailwind-variants, tailwind-merge, cn, tailwindcss, the icon set) at the ranges `@delacour/react-native-ui` declares, instead of npm's latest. tailwind-variants 4.0.0 broke every copied `*.variants.ts`.

- [#311](https://github.com/delacournz/delacour-ui/pull/311) Add component render tests with `@testing-library/react-native` under Jest. `delacour add --tests` now copies a component's render suite, the Jest setup that stubs its native modules and a `renderWithProviders` helper into a Jest project, adds the setup to the project's Jest config, and remembers the choice in `native-components.json`. Fix a disabled `Switch` flipping on a screen reader's activation or its `Field` label press.

- [#291](https://github.com/delacournz/delacour-ui/pull/291) Upgrade `tailwind-variants` to v4. `lib/tv` now builds `tv` with `createTV` from `tailwind-variants/config`, the only v4 entry that accepts `twMergeConfig` — the default entry throws on it, so a `tv.ts` copied by an earlier CLI breaks as soon as v4 is installed. `tailwind-merge` is no longer a dependency: v4 ships its own compiled merge tables. `delacour add` stops installing it.

  v4's types drop numeric variant keys, so `KpiVariantProps["colorIndex"]`, `PlannerVariantProps["colorIndex"]` and `LeaderboardVariantProps["place"]` are now string unions (`"1" | "2" | …`). The component props — `KpiColorIndex`, `PlannerColorIndex`, `LeaderboardPlace` — stay numeric.

### Patch changes [#patch-changes-1]

- [#316](https://github.com/delacournz/delacour-ui/pull/316) Copied tests now typecheck on TypeScript 6. `add --tests` prepends a `/// <reference types>` for the runner's ambient types (`bun`, or `node` under Jest and Vitest), since TypeScript 6 — what Expo SDK 58 ships — defaults `types` to `[]` and every copied suite failed `tsc` in a fresh app.

- [#312](https://github.com/delacournz/delacour-ui/pull/312) `doctor` warns when a Jest project using `chart` has no transform for `.mjs`. d3-shape 3.2.1 ships only `.mjs`, which `jest-expo`'s transform does not compile, so every suite reaching `chart` failed with "Must use import to load ES Module" — add `transform: { "^.+\\.mjs$": "babel-jest" }` to the Jest config.

- [#311](https://github.com/delacournz/delacour-ui/pull/311) `add --tests` on Jest now adds `transform: { "^.+\\.mjs$": "babel-jest" }` to the Jest config, and `doctor` warns when it is missing. d3-shape 3.2.1 ships only `.mjs`, which `jest-expo`'s transform does not compile, so every suite reaching `chart` failed with "Must use import to load ES Module".

## 0.5.1 [#051]

[GitHub release](https://github.com/delacournz/delacour-ui/releases/tag/delacour%400.5.1)

### Patch changes [#patch-changes-2]

- [#253](https://github.com/delacournz/delacour-ui/pull/253) `update` merges a component's `AGENTS.md` that a project edited after copying it with an older CLI, instead of skipping it with no base to merge from — so docs still naming `bun test` pick up the package-manager-neutral text. The MCP `add_components` tool and the README describe `--tests` as copying tests written for the project's own runner.

## 0.5.0 [#050]

[GitHub release](https://github.com/delacournz/delacour-ui/releases/tag/delacour%400.5.0)

### Minor changes [#minor-changes-3]

- [#244](https://github.com/delacournz/delacour-ui/pull/244) `add --tests` copies each component's `bun test` suites beside it, records them in the lock, and asks for `@types/bun`; `update` keeps copied tests current and `update --tests` brings them in. The registry ships each item's tests in a separate `tests` list, so older CLIs are unaffected.

- [#246](https://github.com/delacournz/delacour-ui/pull/246) `add --tests` writes copied suites for the project's own runner — Vitest, Jest or Bun, read from `package.json` or set with `tests.runner` in `native-components.json` — and asks for that runner's packages instead of `@types/bun`. The shipped suites keep to the API all three share, and the registry build fails on one that does not. `add --tests` and `doctor` check that the runner can run them — its packages, a Jest config or a Vitest alias, and `tsconfigRaw` on Expo's tsconfig — and name the fix.

### Patch changes [#patch-changes-3]

- [#243](https://github.com/delacournz/delacour-ui/pull/243) Copied components no longer assume Bun or cite tests that are not copied. `add` strips maintainer-only notes and test-file rows from each component's `AGENTS.md`, the registry build fails on any shipped file that names Bun or an unshipped test, and the CLI prints Expo commands for the project's own package manager. The agent skill shows `npx` with its pnpm, yarn and bun equivalents.

## 0.4.0 [#040]

[GitHub release](https://github.com/delacournz/delacour-ui/releases/tag/delacour%400.4.0)

### Minor changes [#minor-changes-4]

- [#211](https://github.com/delacournz/delacour-ui/pull/211) Add `Breadcrumb` — the path to the current screen, links back up each level and the current page last.

  - `Breadcrumb.List` counts its direct `Breadcrumb.Item`s and puts a separator between every pair, none after the last. A hand-placed `Breadcrumb.Separator` stands in for the automatic one beside it, and the root's `separator` replaces the chevron everywhere.
  - Past `maxItems` the middle folds into an ellipsis, keeping `itemsBeforeCollapse` and `itemsAfterCollapse` at each end; `onEllipsisPress` makes it a button and hands over the hidden indices. `overflow="scroll"` runs the trail on in a horizontal scroller opened at the current page.
  - `Breadcrumb.Link` is a `Pressable` announced as a link with a 44-point target and takes an `onPress` — no router coupling. `Breadcrumb.Page` is announced selected; separators are hidden from screen readers; chevrons flip in right-to-left layouts.
  - `sm` and `md` sizes, on the caption and body text steps.
  - `delacour add breadcrumb` copies it into a project.

- [#216](https://github.com/delacournz/delacour-ui/pull/216) Add `CircularText` — text set around a circle, optionally turning

  The text sits on a `react-native-svg` `TextPath`, laid out once by the platform's shaper and closed
  exactly with `textLength`. `span` is a full ring, an arc or natural spacing; `side` stands the glyphs
  outside or inside the circle; `repeat="fill"` repeats a phrase until the ring closes. `spin` is a
  steady `loop` in degrees per second, driven by a frame-callback integrator so a `pause` (by press or
  by state) eases to a halt and resumes without a snap, or a `controlled` angle from a shared value.
  `centerContent` stays upright and independently accessible, the ring reads once with separators
  stripped, and a `loop` holds still under reduce motion or `isMotionCalm`.

- [#182](https://github.com/delacournz/delacour-ui/pull/182) Add `ColorPicker` — pick a colour by dragging, typing or tapping a preset.

  - Compound anatomy: `ColorPicker.Area` (saturation and brightness), `.Hue`, `.Alpha`, `.Preview`, `.Input` (a hex field), `.Swatches` / `.Swatch`, `.Content` and `.Trigger`. A bare `<ColorPicker />` draws the area, the hue track and the field.
  - Every drag runs on the UI thread through one shared value, so nothing re-renders while a finger moves. `onValueChange` fires per frame, `onValueCommit` once a change settles.
  - Accepts hex (3, 4, 6, 8 digits), `rgb()`, `rgba()`, `hsl()` and `hsla()`; reports in `format` — `hex`, `rgb` or `hsl`. Greys and black keep their hue, and a controlled echo never drifts it.
  - `hasAlpha` adds an opacity track whose fade keeps the same RGB end to end. `presentation="sheet"` puts the surface in a `BottomSheet` behind a trigger row drawn on `Input`'s box.
  - Joins `Field`, takes `Input`'s sizes and variants, and is adjustable for screen readers in every axis, announcing on commit.
  - The `color-picker` subpath imports `BottomSheet`, so it needs `@delacour/react-native-bottom-sheet` installed even inline.
  - `delacour add color-picker` copies it into a project.

- [#206](https://github.com/delacournz/delacour-ui/pull/206) Add `Compare`, two layers of one frame with a seam the finger drags across — before and after, one screen in two themes, a redesign against the original. The front layer is revealed by a sliding mask rather than resized, so both halves stay in register; the handle is an `adjustable` with stepped assistive actions, snap points on release, haptics at stops and bounds, horizontal or vertical orientation, and a `grab` mode that leaves vertical scrolling to the list

- [#190](https://github.com/delacournz/delacour-ui/pull/190) Add `Direction`, a per-subtree LTR/RTL wrapper with `useDirection` and `useDirectionSign`.

  - `<Direction dir="rtl">` mirrors its subtree on the next frame — rows reverse, `start`/`end` insets swap — with no restart and no remount, and nests: an inner `<Direction dir="ltr">` holds a phone number's order inside an RTL card.
  - Uniwind's `rtl:` and `ltr:` variants resolve against the nearest `Direction`, not the app.
  - `useDirection()` and `useDirectionSign()` report the direction to gesture and `translateX` maths. Outside any `Direction` they fall back to `I18nManager.isRTL` rather than throwing.
  - Worklet-safe helpers — `resolveDirection`, `directionSign`, `physicalSide`, `mirrorX`, `logicalDelta` — for code that runs on the UI thread.
  - `delacour add direction` copies it into a project.

- [#222](https://github.com/delacournz/delacour-ui/pull/222) Add ImageViewer: a fullscreen gallery that opens from a thumbnail, with pinch, pan and double-tap zoom, swipe between images and drag-to-dismiss, plus the `media` / `media-foreground` colour tokens.

- [#208](https://github.com/delacournz/delacour-ui/pull/208) Add `MessageScroller`, a conversation list anchored at the newest message

  It follows new messages while the reader is at the end and leaves them alone once they have
  scrolled up, with a floating "jump to latest" button carrying an unread count. Older history loads
  when the reader reaches the top, guarded to one request per page, and lands without moving the
  viewport. The list rises with the keyboard, draws day separators and an unread divider, and passes
  each message's place in its sender's run to `renderMessage`. `useMessageScrollerState` drives the
  same behaviour on another list, such as `Screen.ChatList`.

- [#218](https://github.com/delacournz/delacour-ui/pull/218) Add `Message`, a chat bubble with incoming and outgoing sides, run-aware logical corners, an avatar gutter, author and timestamp, delivery receipts with retry, reactions, actions and a typing indicator — read by a screen reader as one composed label

- [#205](https://github.com/delacournz/delacour-ui/pull/205) Add `Pagination`, for moving through the pages of a result set. The `numbers` variant draws a
  fixed-length run of page numbers and gaps, so the number under the reader's thumb never slides away
  as the window moves; a gap never hides a single page, and tapping one jumps `pageJump` pages.
  `compact` draws one "3 / 12" readout that VoiceOver swipes a page at a time, and `simple` the two
  labelled arrows alone. `Pagination.Summary` and `Pagination.Status` ("41–60 of 472") sit at the
  leading edge. A controlled `page` outside `[1, count]` is drawn clamped and reported once through
  `onPageChange`. `sm` targets reach 44 points with hit slop. `delacour add pagination` copies it in.

- [#200](https://github.com/delacournz/delacour-ui/pull/200) Add `Post`, a social card in four shapes — feed, vote, compact and media — with an author, a tokenised body with tags, mentions and links, a fixed-shape media frame with a scrim, stats whose glyph fills and whose count rolls, and a score pill; all counts and votes stay caller state

- [#195](https://github.com/delacournz/delacour-ui/pull/195) Add `Questionnaire` — a guided form, one question at a time. Six question kinds (single and multiple choice with a free-text "Other", text, rating, a numbered scale and yes/no), conditional questions that drop their stale answers, Back that follows the questions actually visited, deliberate skips, a dimmed-not-disabled Next that explains a blocked answer, async submit, controlled answers and navigation, and bar, stepper or count progress. The flow's rules are exported as pure functions, so a server can re-validate a submission.

- [#223](https://github.com/delacournz/delacour-ui/pull/223) Add `SectionProgress` — a floating pill over a long reading screen: a ring filling with scroll progress beside the title of the section being read, opening a card that lists every section.

  - Reads `useScrollSections`: `scroll` drives the ring and the reveal, `value` takes `activeId`, `onValueChange` takes `scrollTo`. The ring runs on the UI thread, so scrolling renders nothing; a jump eases over 180ms.
  - Six placements against the safe area, an `offset`, and a `revealAt` that latches once crossed. The panel grows out of the pill, scrolls past six rows, and closes on an outside tap, the escape gesture or Android back.
  - `SectionProgress.Item` takes a `color` for its marker and for the ring while it is active. `progress` overrides the scroll; `isOpen` / `onOpenChange` control the panel; `haptic` plays on a section change.
  - VoiceOver reads "Sections, Pricing, 42 percent"; opening moves focus to the active section. Reduce motion turns the panel's scale into a fade.
  - `delacour add section-progress` copies it into a project, with `use-scroll-sections`.

- [#214](https://github.com/delacournz/delacour-ui/pull/214) Add `SectionRail` — a thin rail of bars along a screen edge, one per section of a long screen, that opens into a labelled outline.

  - `SectionRail.Trigger` holds one `SectionRail.Bar` per section and `SectionRail.Content` one `SectionRail.Item` per row; `level` shortens a bar and indents its row by the same step. The active bar's colour eases in, and the active row is drawn in the foreground.
  - Tap the rail to open the outline, or scrub: drag along it and the row under the finger highlights — mapped on the UI thread, with an optional `haptic` tick per section crossed — and releasing jumps there. A pick lingers for `closeDelay` before closing; an outside tap or Android's back closes it.
  - `placement` (`end`, `start`) and `align` (`center`, `bottom`) are logical and mirror in right-to-left; the rail clears the safe area by `offset`. It fills its container and passes every other touch through, so the content under it keeps scrolling.
  - Pairs with `useScrollSections`: `value={sections.activeId}` and `onValueChange={sections.scrollTo}`. `value={undefined}` stays controlled, so a hook's empty first value does not flip modes.
  - One `adjustable` element to VoiceOver, named "Sections" and valued by the active title; swiping steps through the sections and focus lands on the active row when the outline opens.
  - `delacour add section-rail` copies it into a project, along with `use-scroll-sections`. The registry builder now reads a `registryDependencies` list from `ITEM_META` for edges no import records.

- [#221](https://github.com/delacournz/delacour-ui/pull/221) Add `Sortable` — a vertical list the user reorders by dragging.

  - Rows move by transform on the UI thread, so a drag renders nothing; `onReorder(order, { id, from, to })` fires once, after the row lands, and the transforms clear in the commit that renders the new order.
  - `activation="handle"` drags from `Sortable.Handle`; `"long-press"` lifts the whole row after `longPressDelay`. A row changes slot when its edge crosses the next row's midpoint, at any heights.
  - `isPinned` rows never move and the others reorder around them; `isDisabled` rows cannot be lifted.
  - `scrollRef` auto-scrolls the enclosing scroller near its edges. `haptic` plays one feedback on lift and one per slot passed.
  - Screen readers get Move up / Move down actions and "Position 2 of 5", with the new position announced.
  - `reorderItems` and `useSortableItem` are exported. `delacour add sortable` copies it into a project.

- [#179](https://github.com/delacournz/delacour-ui/pull/179) Add `SplitView`, two stacked panes with a drag row that settles on named snap points.

- [#177](https://github.com/delacournz/delacour-ui/pull/177) Add `Splitter`, resizable panes divided by draggable, adjustable handles, sized in percent.

- [#198](https://github.com/delacournz/delacour-ui/pull/198) Add `TagInput` — free-form tags typed into one field box, each a removable chip

  Return or a delimiter commits the text as a chip and keeps the keyboard up; a paste holding
  delimiters lands as several tags. Duplicates, a `max` and a `validate` hook refuse tags through
  `onReject` with a reason, and `allowOverflow` accepts past `max` while marking the field invalid.
  Backspace on an empty field arms the last chip, and a second removes it. The box is `Input`'s, it
  joins an enclosing `Field`, and tags and draft are each controlled or uncontrolled.

- [#220](https://github.com/delacournz/delacour-ui/pull/220) Add `TextAnimation` — five ways a piece of text or a number arrives, on one clock.

  The root reveals a string by word, character or line with a fade, slide or scale, staggered
  forward, in reverse, from the centre or in a seeded random order. `TextAnimation.Typing` types a
  phrase or cycles several with a bar or block caret, `TextAnimation.Rotating` swaps one word in
  place inside a sentence, `TextAnimation.Counting` tweens a formatted number on the UI thread, and
  `TextAnimation.Rolling` rolls an odometer whose wheels take the short way round. Nothing reflows
  while it plays, a screen reader hears the final text once, and under reduce motion every part shows
  its final text on the first frame.

- [#212](https://github.com/delacournz/delacour-ui/pull/212) Add `Tour` — a guided walkthrough: the screen dims, a hole opens around one control, and a card beside it explains it.

  - Wrap each control in a `Tour.Step` with an `order` and a `title`; the tour sorts the steps, measures the current one in window coordinates and re-measures on rotation. `onStepChange` fires first, so a target can be scrolled into view.
  - The hole is an SVG cutout, `rect` or `circle`, that glides between targets on the UI thread and jumps under reduce motion. `shape`, `padding`, `radius` and `placement` are set on the tour and overridden per step.
  - The card sits below the hole when it fits and above otherwise, centred and clamped to the safe area. Next, Back, Skip and Done, a "2 of 5" progress, and every label replaceable.
  - A React Native `Modal` by default; `isInteractive` draws inside the tour's root and passes touches inside the hole through to the control.
  - Open with `defaultOpen`, the `isOpen` triple or `useTour().start()`. `onFinish` and `onSkip` are where an app records that the tour was seen.
  - Focus moves to the card on each step; VoiceOver's escape and Android back skip when dismissible.
  - `delacour add tour` copies it into a project.

- [#207](https://github.com/delacournz/delacour-ui/pull/207) Add `Tree` — a hierarchy opened one level at a time, with branches that expand and collapse and
  optional single or multiple selection. Depth comes from context, closed groups unmount, and
  `hasChildren` marks a lazy branch before its children load.

- [#175](https://github.com/delacournz/delacour-ui/pull/175) Add `Combobox` — a long or remote list behind a field-shaped trigger, filtered as you type in a bottom sheet.

  - The sheet opens with its search field focused once it has settled. The default filter matches the label and `keywords` case- and accent-insensitively; `filter={{ kind: "custom", match }}` takes a predicate and `{ kind: "none" }` shows the options as given, for a server. The matched run of each label is bold, through accents.
  - Single selection by default, where a pick closes the sheet; `selectionMode="multiple"` keeps it open and shows removable chips on the trigger (folding into `+N`) and above the search field, with a two-step Backspace remove. `value` and `onValueChange` are typed per mode; `maxSelected` disables the rest once reached.
  - The query is controlled separately with `inputValue` and `onInputValueChange`, which reports `type`, `select`, `clear` or `close`. A picked option stays on the trigger after a server's results move on. `allowCustomValue` offers the typed text as a value.
  - Built from Select's leaves — the same trigger box and option rows — and joins `Field` the same way. `isClearable`, `isReadOnly`, `isLoading`, `Combobox.Empty` and a replaceable `Combobox.Trigger` cover the rest; the result count is announced to screen readers.
  - Needs `@delacour/react-native-bottom-sheet` and `BottomSheetProvider`. `delacour add combobox` copies it into a project, along with `select`, `chip` and `bottom-sheet`.

- [#172](https://github.com/delacournz/delacour-ui/pull/172) Add `DatePicker`, a field-shaped trigger that shows a date (`mode="single"`), a range (`"range"`) or several (`"multiple"`) and opens a `Calendar` in a bottom sheet to change it. The sheet closes when the pick is finished — on a day, on a range's second end, or on Done for several — and a half-picked range is held inside the sheet rather than reported. The trigger is the `Input` box at every `size` and `variant`; its text is formatted from the value through the calendar's `Intl` formatters, with `format` and `formatRange` overrides and a long-form screen-reader value. `minDate`/`maxDate`/`disabledDates`, `locale` and week start pass to the calendar; `isOpen`/`onOpenChange` and the value work controlled or uncontrolled; Clear, read-only, `presentation="inline"`, and `isInvalid`/`isDisabled`/label/label-tap from a `Field`. Needs `BottomSheetProvider`. `bunx delacour add date-picker` copies it.

- [#199](https://github.com/delacournz/delacour-ui/pull/199) Add `DateTimePicker`, one field for a date and a time of day picked together: an `Input`-shaped trigger that opens a `Calendar` and `TimePicker`'s wheel in one bottom sheet with one Done, or draws them in place with `presentation="inline"`. The value is a whole `{ date, time }` or `null`, never half — a day picked first takes the time from the clock, rounded up onto `minuteStep`; a time picked first lands on today or the nearest allowed day — and every pick and settle reports it, so Done only closes and announces. `layout="tabs"` (default) puts Date and Time behind tabs and moves to Time once after the first date pick; `layout="stacked"` draws the calendar over a time row that opens the wheel. `minDateTime`/`maxDateTime` are one window that bounds the calendar to its days and the wheel to its times on those days only, re-clamping the time when the date moves; plus `disabledDates`, `hourCycle`, `showSeconds`, `locale`, a custom `format`, `isClearable`, controlled or uncontrolled value and open state, and the `Field` cascade. The subpath exports the pure `DateTimeValue` helpers — `toNativeDate`/`fromNativeDate`, `formatDateTime`, `serialiseDateTime`/`parseDateTime`, `clampDateTime`, `timeBoundsForDate` and more. Needs `BottomSheetProvider`. `bunx delacour add date-time-picker` copies it.

- [#186](https://github.com/delacournz/delacour-ui/pull/186) Add `Input.Group.Button`, `Input.Group.Separator` and `Input.Group.Block`, decorative decorators, and `Textarea` inside a group

  - `Input.Group.Prefix` / `.Suffix` take `isDecorative`, which hides them from screen readers and lets
    touches through to the field. It defaults to true when every child is bare text or an `Icon`.
  - `Input.Group.Button` is a `Button` sized one step below the box (square when icon-only), disabled
    with the group without fading twice, and warns in development when icon-only with no label.
  - `Input.Group.Separator` draws a hairline whose direction comes from where it is written: vertical
    in the row, horizontal between a block and the row.
  - `Input.Group.Block` adds a full-width section above (`position="start"`) or below (`"end"`) the
    field inside the same border and focus ring. The group always renders an inner row, so adding a
    block never remounts the field.
  - `Textarea` reads the group's context and drops its own box, so a message composer is one box.

- [#191](https://github.com/delacournz/delacour-ui/pull/191) Add `MarkdownEditor`, a Markdown field with a formatting toolbar, a monospaced write pane and a rendered preview

  The toolbar wraps a selection or inserts markers at the caret, toggles a format off when pressed
  again, applies headings, quotes and lists to every touched line, and lights from the caret. Return
  continues a list. The preview draws the toolbar's subset on the `Text` presets and opens a link only
  for http, https, mailto and tel. It joins `Field` like `Input`, comes in a `bar` or `pill` toolbar,
  and ships `applyMarkdownCommand`, `continueMarkdownList` and `parseMarkdown` as plain functions. The
  CLI adds it with `delacour add markdown-editor`.

- [#188](https://github.com/delacournz/delacour-ui/pull/188) Add `Marker`, a centred inline note for steps and day breaks between conversation turns

  It comes as a bare `default` row, a hairline `border` capsule, or a `separator` label ruled to both edges. With no handler it is a plain view read as text; give it `onPress` or `onLongPress` and it becomes a pressable announced as a button. `Marker.Content shimmer` breathes the text on the UI thread while a step runs and announces the marker busy, stilled under reduce motion. `bunx delacour add marker` copies it in.

- [#184](https://github.com/delacournz/delacour-ui/pull/184) Add `NumberInput` — a number between a minus and a plus

  Tap a stepper to move by `step`, hold it to repeat after 400ms and accelerate, or type: while
  focused the field takes half-typed text (`""`, `"-"`, `"1."`) and commits on blur or submit, so it
  never fights the person typing. Every path goes through one reconcile — snapped to the step, held
  inside `[min, max]`, rounded to the step's precision — and `onValueChange` fires only on a committed
  change. The box is `Input.Group`'s, so it takes `Input`'s variants and sizes and an enclosing
  `Field`'s label, invalid and disabled state. `formatOptions` formats the value at rest through
  `Intl`; `commitMode="validate"` keeps an out-of-range number and flags it instead of clamping. The
  field is `adjustable` with increment and decrement actions for VoiceOver and TalkBack. The parse,
  format and step maths are exported as pure helpers. `bunx delacour add number-input` installs it.

- [#215](https://github.com/delacournz/delacour-ui/pull/215) Add `OtpInput`, a one-time code or PIN drawn as a row of cells over one hidden `TextInput`, so the number pad, a paste, iOS's QuickType code from Messages and Android's SMS autofill all fill every cell at once. Every change is sanitised to `pattern` (`digits`, `alphanumeric`, `alphabetic` or a one-character `RegExp`) and cut to `length`; `onComplete` fires once per transition to a full code with a `success` haptic. `groupSize` draws separators between groups, or write the anatomy out with `OtpInput.Group`, `OtpInput.Slot` and `OtpInput.Separator`. `isMasked` draws dots without switching off autofill, the caret holds still under reduce motion, the row is one accessible element, and `isInvalid` / `isDisabled` cascade from a `Field`. `bunx delacour add otp-input` copies it.

- [#194](https://github.com/delacournz/delacour-ui/pull/194) Add `ScrollBlur` — a progressive blur at a scrollable's edges that keeps floating controls legible over any background, falling back to a gradient wash with no engine or with Reduce Transparency on. Ships with `ScrollBlurLayerProvider`, the `expo/blur-layer` engine (`ExpoBlurLayer`, behind the new optional peer `expo-blur`), `useReduceTransparency` and `withAlpha` in `lib/color`. The CLI gains `scroll-blur`, `blur-layer` and `use-reduce-transparency` registry items, and classifies `expo-blur` as an `expo install` package.

- [#210](https://github.com/delacournz/delacour-ui/pull/210) Add `ScrollText`, text that resolves unit by unit as the screen scrolls past it. Four effects —
  `colour`, `fade`, `rise` and `highlight` — over a `word`, `character` (by grapheme) or `line` split,
  staggered by `overlap` inside a viewport `window`. Progress comes from the enclosing `Screen`, from
  any scroll view's offset (read against its own bounds with `viewport`), or from a shared value
  already in 0..1. Every frame runs on the UI thread and writes only opacity, transform and colour;
  un-revealed text never drops below a legible floor, reduce motion and `isMotionCalm` show it fully
  revealed, and the block reads as one accessibility element with the whole string.
  `delacour add scroll-text` copies it in.

- [#197](https://github.com/delacournz/delacour-ui/pull/197) Add `SearchBar`, the query field at the top of a list, on `Input.Group` with no chrome of its own. A clear button that keeps focus and the keyboard, a Cancel action shown never, on focus or always that empties the text and dismisses the keyboard, `debounce` with `onDebouncedChange` (flushed by the search key, immediate on clear), `isLoading` swapping clear for a spinner, and `tokens` drawn as removable chips with Backspace removing the last. `pill` and `rounded` shapes over `Input`'s variants and sizes, and it joins an enclosing `Field`. `delacour add search-bar` copies it.

- [#171](https://github.com/delacournz/delacour-ui/pull/171) Add `Select` — a closed set of choices behind a field-shaped trigger, picked from a bottom sheet.

  - Single selection by default, where a pick closes the sheet; `selectionMode="multiple"` keeps it open, draws a box on each row and closes from a Done footer. `value` and `onValueChange` are typed per mode — a string or `null`, or an array — and `maxSelected` disables the remaining rows once reached.
  - Options come as data through `options`, or as `Select.Item` and `Select.Group` children, and both are drawn from one normalised, virtualised list. `isSearchable` adds a search field that matches case- and accent-insensitively, hides groups it empties and clears on close.
  - The trigger is `Input`'s own box at every variant and size. Inside a `Field` the select takes its invalid and disabled state, reads `Field.Label` as its accessible name and sheet title, and opens when the label is tapped. `isReadOnly`, `isLoading`, `renderValue` and a replaceable `Select.Trigger` cover the rest.
  - Rows are radios in single mode and checkboxes in multiple to a screen reader; group headings are headers. `SelectOptionRow` is exported as the leaf a later picker reuses.
  - Needs `@delacour/react-native-bottom-sheet` and `BottomSheetProvider`. `delacour add select` copies it into a project, along with `bottom-sheet`.

- [#187](https://github.com/delacournz/delacour-ui/pull/187) Add `Signature`, a pad to sign with a finger or a stylus. Strokes are drawn on the UI thread and smoothed into ink, a tap leaves a dot, and React renders once per stroke rather than per move. `Signature.Undo`, `.Redo` and `.Clear` disable themselves when they would do nothing, and `onRequestAlternative` adds a "Can't sign? Type your name" link for anyone who cannot draw. The value is plain JSON that re-fits a pad of another size; the ref adds `toSVG()` and `toPaths()`. Four sizes, two variants, read-only and disabled states, and `isInvalid` / `isDisabled` cascade from a `Field`. `bunx delacour add signature` copies it.

- [#185](https://github.com/delacournz/delacour-ui/pull/185) Add `ThemeSelector`, a System, Light or Dark choice read from the live Uniwind theme and applied to
  it. System is selected while the app follows the device, so a theme changed anywhere else
  re-selects it. `segmented` joins the options into one attached run; `cards` stands them apart as
  tiles. `applyTheme={false}` with `value` turns it into a presentation layer so the app can persist
  the preference itself — there is no storage dependency — and `restoreThemeMode` validates a stored
  string before it reaches `Uniwind.setTheme`. `useThemeSelection` reads and sets the mode with no
  selector mounted. `delacour add theme-selector` copies it, with `toggle-button`, `icon` and `field`
  as registry dependencies.

- [#193](https://github.com/delacournz/delacour-ui/pull/193) Add `TimePicker`, a time of day on snapping wheels — hour, minute, optional second and, on a 12-hour clock, AM/PM. It presents as an `Input`-shaped trigger that opens a `BottomSheet`, or inline with `presentation="inline"`. The value is always a 24-hour `TimeValue`; `hourCycle` and `locale` change only how it reads. It takes `minuteStep`, `minTime`/`maxTime` (out-of-bounds rows dim and a wheel resting on one moves back), `showSeconds`, `visibleRows`, a custom `format`, `clearable`, controlled or uncontrolled value and open state, and joins an enclosing `Field`. Parts are `TimePicker.Trigger`, `.Value`, `.Icon`, `.Content`, `.Wheel`, `.Done` and `.Clear`; `TimePickerWheel` renders the bare wheel on its own, and the subpath exports the pure time helpers (`parseTime`, `serialiseTime`, `formatTime`, `snapTime`, `clampTime` and more). Each wheel column is one adjustable element to screen readers. The subpath imports the sheet engine, so it needs `@delacour/react-native-bottom-sheet` installed. The CLI can now `add time-picker`.

- [#180](https://github.com/delacournz/delacour-ui/pull/180) Add `Timeline`, a sequence of dated events down a rail or across a snapping strip

  `Timeline` lays out an order's history, a project's milestones or a match's key moments: each `Timeline.Item` is a
  marker on a rail with a title, a date, a description and optional side columns. One zero-based `value` says how far
  along the sequence is — events before it completed, at it current, after it upcoming — and the rail fills off that
  value alone, so it is never half drawn between two events. `tone` says what kind an event is (`info`, `success`,
  `warning`, `destructive`) and tints its marker whatever its progress. Five variants (`dot`, `icon`, `numbered`, `card`,
  `compact`) and two sizes. Horizontally it is a swipeable strip of columns that can snap, fires `onColumnChange` and a
  selection haptic as each column reaches the reading edge, and collapses an empty column to a tick. `Timeline.List`
  virtualises a long history over a `FlatList` and supplies each item's position itself. `Timeline.Masthead` and
  `Timeline.Stats` head the sequence. Each event is one VoiceOver stop, read as "Event 2 of 6, completed, success".

  `bunx delacour add timeline` copies it into your project.

### Patch changes [#patch-changes-4]

- [#219](https://github.com/delacournz/delacour-ui/pull/219) Add `QRCode`: a string a camera can read, drawn as one `react-native-svg` path, with an optional
  `QRCode.Logo` in the middle

  The encoder is in-house and dependency-free — numeric, alphanumeric and UTF-8 byte modes, versions
  1–40, levels L/M/Q/H — and is exported as `encodeQr` and `useQRCode` for custom renderers. Three
  module styles (`square`, `rounded`, `dots`) keep the finders concentric; modules snap to whole device
  pixels; a logo forces level H and grows the version until every block stays recoverable. The tile is
  dark-on-light in both themes, and an inverted or low-contrast pair warns in development. The
  registry now also skips `*.test-helpers.ts` and `*.fixtures.ts` alongside tests.

- [#183](https://github.com/delacournz/delacour-ui/pull/183) Add AnimatedBadge, a status pill that rolls its content and springs its width when the status changes.

- [#192](https://github.com/delacournz/delacour-ui/pull/192) Add `Attachment` — a file, image, video or recording with a thumbnail, size, upload state and remove

  `AttachmentMedia` is discriminated by `kind`, so an image without a `source` is a type error. Three
  layouts — `chip` for a composer, `tile` for a photo tray, `card` for inside a message — at three
  sizes. Upload stays the app's: `status` is `idle`, `uploading` (determinate or looping), `error`
  with the app's message, or `done`, and `onRemove` / `onRetry` compose their controls in beside the
  press target so a remove tap never opens the attachment. A screen reader meets one element with a
  composed label, progress in ten-point steps and remove / retry as actions. `Attachment.Group` is a
  horizontal tray that fades attachments in and out and slides the rest along, stilled under calm
  motion. `delacour add attachment` installs it.

- [#174](https://github.com/delacournz/delacour-ui/pull/174) Add `Countdown`, the time left until a fixed moment, read from the wall clock on every tick

  It reads the clock rather than decrementing a counter, so it is right after the app was backgrounded or the
  device slept, and it re-reads on returning to the foreground. Seconds round up — the final second shows `0:01`
  and `onComplete` fires once at zero, re-arming when `to` moves into the future. `units` picks which units show,
  the largest absorbing everything above it; `trim` drops leading zero units. `variant` is `segmented` — boxed
  digits that slide per changed digit, with captions from `labels` — or `inline`, one tabular run. `urgentBelow`
  turns the digits destructive. The `timer` label is coarse and names seconds only in the final minute.
  `bunx delacour add countdown` copies it into a project.

- [#226](https://github.com/delacournz/delacour-ui/pull/226) Move to Expo SDK 58: React Native 0.88, React 19.3, Gesture Handler 3

  The peer floors are now `react-native >=0.88` and `react-native-gesture-handler >=3.3`. React Native
  0.88 types its components through the strict API by default, so every ref is typed as the host
  instance it receives — `ViewInstance`, `TextInputInstance`, `ScrollViewInstance` — rather than as
  the component, and `ScreenScrollViewRef` is now `ScrollViewInstance`. Those types do not exist
  before 0.88. The sheet's and the drawer's pans keep the builder API under Gesture Handler 3's
  `LegacyPanGesture` type. The CLI's
  `verify:expo` scaffolds against SDK 58.

- [#170](https://github.com/delacournz/delacour-ui/pull/170) Add `FlipCard` — two faces of one card and a turn between them

  `FlipCard.Front` sits in flow and sizes the card, `FlipCard.Back` fills it, and `FlipCard.Trigger`
  turns it under every trigger. `trigger` is a discriminated union: `"press"` (a tap anywhere),
  `"swipe"` (a drag that scrubs the turn, rubber-bands past either rest and settles on the nearer face
  or the way it was flicked; `swipeDistance` exists only here) and `"manual"` (only `face`, the ref's
  `flip()` / `flipTo()` or a trigger). The face is state and the rotation follows it: the hidden face
  leaves the accessibility tree and stops taking touches the moment a turn is committed, which face is
  drawn is decided by the angle rather than `backfaceVisibility`, the settled face is announced, and a
  gesture card always offers an `activate` action. Under reduce motion or `isMotionCalm` the faces
  crossfade instead of turning. `delacour add flip-card` installs it.

- [#189](https://github.com/delacournz/delacour-ui/pull/189) Add `GridItem` and `GridItem.Group`, a bento tile grid with whole-cell spans

  `GridItem.Group` measures its width, sizes a cell from `columns`, `gap` and `aspect` or `rowHeight`, and
  places each direct child first-fit in writing order from its `colSpan` and `rowSpan`, on pixel-snapped edges
  and the logical `start` inset. It reserves its height before the first measure, so nothing jumps, and glides
  tiles to new cells on a relayout unless reduce motion is on. `GridItem` takes four variants and two sizes,
  renders a `Pressable` only when it has a press handler, and announces itself as one stop labelled from its
  title, value and description. Parts: `Background`, `Media`, `Title`, `Value`, `Description`, `Footer` and
  `Actions`; `useGridItem()` and `useGridItemGroup()` expose the tile's box and the group's cell size, and
  `bunx delacour add grid-item` copies it into a project.

- [#176](https://github.com/delacournz/delacour-ui/pull/176) Add `Leaderboard`: ranked people or teams with standard competition ties, the top three on a podium of growing bars or lifted cards, a movement column, and the highlighted entry pinned below the `limit` cut with its true rank.

  Its podium and rows read entries in any order and rank them stably, `order="asc"` for times; `unit` is spoken after every value. `bunx delacour add leaderboard` copies it into a project.

- [#213](https://github.com/delacournz/delacour-ui/pull/213) Add `ScrollFade`, a gradient at a scrollable's edges while content runs past them

  `@delacour/react-native-ui/scroll-fade` overlays any scrollable — a card row, a list in a `Card`, a
  sheet body — and fades its start and end edges only while there is content past them, on either
  axis. It reads a `ScrollSource` from `useScrollSource`, or needs no wiring at all inside a `Screen`.
  The fade is a colour, so name the surface with `color`; `edges`, `size`, `fadeInDistance` and
  `insetStart` / `insetEnd` tune it. The CLI registry gains the `scroll-fade` item.

- [#181](https://github.com/delacournz/delacour-ui/pull/181) Add `Table`, rows and columns of short values lined up by one set of column rules

  `columns` on the table declares each column once — `{ flex }` or `{ width }`, with an `align` — and every row's
  Nth cell reads the Nth rule, so a header, the body and a footer line up without a width on any cell. Bare text is
  set in tabular figures. `Table.Head` takes `sort` to become a button that draws and announces its direction while
  the caller owns the order; `Table.Row` takes `onPress` and `isSelected` to become one selectable button named by its
  cells, and each cell announces its column's heading. `size`, `variant="outline"` and `striped` set density and
  chrome; `minWidth` scrolls a wide table sideways with edge fades that dissolve into the surface behind it; rows
  render from a `FlatList` with `index` and `isLast`; `Table.Empty` keeps the header; `Table.Frame` puts the table in a
  card under a title and an action. `bunx delacour add table` copies it into a project.

## 0.3.0 [#030]

[GitHub release](https://github.com/delacournz/delacour-ui/releases/tag/delacour%400.3.0)

### Minor changes [#minor-changes-5]

- [#126](https://github.com/delacournz/delacour-ui/pull/126) Add Carousel: swipeable slides with peek, loop, vertical, coverflow, autoplay, dots and arrows. Adds `lib/paging`, the shared worklet-safe paging maths.

- [#164](https://github.com/delacournz/delacour-ui/pull/164) Add `useScrollSections` — section-aware scroll tracking for long screens.

  - `useScrollSections({ readingLine })` returns a `scrollHandler` for an `Animated.ScrollView`, a `register(id)` that hands back each section's `onLayout`, the `activeId` (React state that changes only when the reader crosses into another section), `progress` and `scrollY` as shared values, and `scrollTo(id)`.
  - The active section is resolved on the UI thread and crosses to React only on a change, so scrolling never re-renders the screen.
  - The pure resolvers behind it — `resolveActiveSection`, `resolveScrollProgress` and `resolveSectionScrollTarget` — are worklet-safe and exported from `lib/scroll-sections`.
  - `delacour add use-scroll-sections` copies the hook and its resolvers into a project.

### Patch changes [#patch-changes-5]

- [#163](https://github.com/delacournz/delacour-ui/pull/163) Add the scroll family's shared base: `useScrollSource`, `scroll-maths` and `scroll-edges`

  `@delacour/react-native-ui/hooks/use-scroll-source` gives any scrollable a `ScrollSource` — its
  offset, content size and layout size as shared values, plus its axis — and the props to spread onto
  it; `ScrollSourceProvider` shares one and `useResolvedScrollSource` is how an effect finds it.
  `lib/scroll-maths` holds the worklet maths an edge affordance needs (`scrollEdgeOpacity`,
  `scrollProgress`, `readScrollEvent`) and `lib/scroll-edges` the band geometry. A `Screen` now
  publishes its own body as a scroll source, so scroll-linked effects inside one need no wiring. The
  CLI registry gains the three items, and `screen` now depends on `use-scroll-source`.

## 0.2.0 [#020]

[GitHub release](https://github.com/delacournz/delacour-ui/releases/tag/delacour%400.2.0)

### Minor changes [#minor-changes-6]

- [#159](https://github.com/delacournz/delacour-ui/pull/159) Add `Map` — a themed map for places and paths, at `@delacour/react-native-ui/map`

  Markers that are React views and anchor on their pin's tip, labels, themed popups, routes, arcs and
  floating zoom, compass, recenter and locate controls, on MapLibre (`@maplibre/maplibre-react-native`).
  The basemap is OpenStreetMap vector tiles from OpenFreeMap — free, no key — painted from the theme's
  tokens on both platforms, so light, dark and any retuned theme carry through to the map; `mapStyle`
  or `buildMapStyle` swap in other tiles. Props set the opening view; a ref moves the camera with
  `flyTo`, `fitBounds` and `recenter`. `@maplibre/maplibre-react-native` is a new optional peer,
  resolved only by an app that imports `/map`; `delacour add map` copies the component into a project
  and `expo install`s it.

- [#144](https://github.com/delacournz/delacour-ui/pull/144) Add `delacour update`, which brings copied components up to the registry and keeps your edits.

  `add` now records where each file came from in `native-components.lock.json` — the registry ref and
  a hash of the text as the registry served it. `update` uses that to tell an upstream fix from a
  local change: a file only the registry moved is replaced, a file only you moved is left alone, and
  a file both moved is three-way merged. Where both changed the same lines the file is written with
  git conflict markers and the command exits `1`; an edit is never overwritten.

  Your own formatter (Biome or Prettier, from your `node_modules`) is run over the registry's side
  before anything is compared, so a file you only reformatted counts as untouched and an update
  arrives in your style.

  - `update --dry-run` reports the plan and writes nothing; `--json` prints it.
  - `update --base <ref>` merges files that were copied before the lock existed.
  - `update --prune` deletes untouched files a component no longer has.
  - `diff` now prints the plan `update` would apply, so for a tracked file it shows the registry's
    change on its own rather than both sides.
  - The MCP server gains `check_updates` and `update_components`, and `doctor` warns when components
    are present with no lock file.

  Commit `native-components.lock.json`. A project without one keeps working: the first `update`
  records every file that still matches the registry.

- [#131](https://github.com/delacournz/delacour-ui/pull/131) `cn()` now runs on [`cn`](https://github.com/shadcn-ui/cn) instead of `clsx` + `tailwind-merge`: the same output (held to tailwind-merge's on every variant class), much faster on repeated render calls. `clsx` is no longer a dependency; `tailwind-merge` stays, as `tailwind-variants`' peer for `tv()`. Components added with `delacour add` now install `cn`.

### Patch changes [#patch-changes-6]

- [#148](https://github.com/delacournz/delacour-ui/pull/148) `delacour update` now asks what to do with the files it skipped.

  A file copied before `native-components.lock.json` existed, which no longer matches the registry,
  has nothing to merge from, so `update` leaves it alone. Run at a terminal, it now finishes, reports,
  and then asks about those files: leave them, merge them from a ref you type in (what `--base <ref>`
  does), or replace them with the registry's copy. Replacing asks again before touching a file with
  uncommitted changes.

  Nothing is asked under `--yes`, `--json`, in CI or over MCP — there the files stay skipped, as
  before.

## 0.1.0 [#010]

[GitHub release](https://github.com/delacournz/delacour-ui/releases/tag/delacour%400.1.0)

### Minor changes [#minor-changes-7]

- [#97](https://github.com/delacournz/delacour-ui/pull/97) Add `Meter` — a measurement on a fixed scale, coloured by where it falls.

  - Built on `Progress`: `Meter.Header`, `Meter.Label`, `Meter.Output`, `Meter.Track` and `Meter.Fill` are the progress bar's parts, with a root that clamps the reading and judges it. A bare `<Meter value={68} />` draws the scale on its own.
  - Judge a reading by `low`, `high` and `optimum` — good, worse and worst regions painted success, warning and destructive, with `optimum` saying which end is good — or by a `thresholds` list naming the colour from points along the scale. The prop type allows one or the other, never both.
  - `segments` draws the scale as whole blocks that fade on and off; any reading above the floor lights at least one.
  - `valueLabel` takes a function handed the judged reading and its `region`, so the judgement is put into words that are drawn and spoken alike rather than left to colour. One accessible element with the `progressbar` role, spoken the way `Progress` speaks its value.
  - `delacour add meter` copies it into a project, along with `progress`.

- [#88](https://github.com/delacournz/delacour-ui/pull/88) Add `Progress` — a bar showing how far a task has got, or a looping segment while it is under way.

  - Compound anatomy: `Progress.Header`, `Progress.Label`, `Progress.Output`, `Progress.Track` and `Progress.Fill`; a bare `<Progress value={40} />` draws the track and fill on its own.
  - The fill animates on the UI thread as a clipped `translateX`, with no layout pass per frame. `isIndeterminate` sweeps a segment across the track, and breathes in place instead when Reduce Motion is on.
  - Six colours and three sizes, shared with `Slider`. `formatOptions`, a function child on `Progress.Output`, or `valueLabel` word the readout.
  - One accessible element with the `progressbar` role: the value is spoken as a percentage over 0–100 and as a count (`18 of 24`) over any other range, and an indeterminate bar reports busy with no value.
  - `delacour add progress` copies it into a project.

- [#137](https://github.com/delacournz/delacour-ui/pull/137) Add `SelectionMode` — pick several things at once, then act on them from a bar. A long press enters the mode with the pressed item picked; taps then toggle. `SelectionMode.Item` wraps any row, avatar or swatch with a round `leading` mark, a `ring` or nothing; `.Header` counts the picks and offers select-all and the way out; `.Bar` and `.Action` act on the selection; `.Group` lays items out as a stacked card, a grid or a horizontal strip. Selection is a set of ids, controllable alongside the mode, with an optional `max`.

  `delacour add selection-mode` copies it into a project.

- [#135](https://github.com/delacournz/delacour-ui/pull/135) Add `SlideButton`, a control confirmed by dragging a handle across a rail

  The handle tracks the finger exactly and only the release is sprung. A release confirms past
  `threshold` (0.9 by default) with a small look-ahead, but a flick from halfway never does, and
  `threshold={1}` demands the far end. Controlled, the handle waits at the end until `isCompleted`
  answers; a rejected `onComplete` promise takes it home. Variants `secondary`, `destructive` and
  `success`; sizes match `Button`. Screen readers confirm with one named action, and the control
  flips under RTL.

- [#132](https://github.com/delacournz/delacour-ui/pull/132) Add `StackCard` — a deck taken one card at a time by throwing the top one off.

  - Compound anatomy: `StackCard.Card`, `StackCard.Stamp`, `StackCard.Empty`, `StackCard.Actions` and `StackCard.Action`. The root sorts its children by type, and anything it does not recognise is a card.
  - One shared value — the top card's offset — drives the drag, the tilt, the stamps and the cards behind, so nothing re-renders during a drag and the next card is already in place when the top one leaves.
  - `directions` picks which ways a drag throws; a horizontal-only deck lets vertical scrolls through. A flick throws from a short drag, and a disallowed direction gives a little and returns.
  - `layout` draws the cards behind as a `stack`, a `fan` or `flat`, `depth` of them. Only a window around the top card is mounted, so a deck of five hundred costs what a deck of five does.
  - Undo brings the last card back from the side it left, and a controlled deck that leaves `index` where it was declines the throw and the card flies back.
  - Each allowed direction, and undo, is a screen-reader action on the top card, named by `directionLabels`; the cards behind are hidden. Under Reduce Motion a card fades rather than flies.
  - `delacour add stack-card` copies it into a project.

- [#92](https://github.com/delacournz/delacour-ui/pull/92) Add `Avatar`

  A person as a picture. The initials of `name` are painted first and the image goes on top, so the circle is never
  empty while a picture loads or after it fails, and a failed source retries on its own when its URI or headers change.
  `variant` and `color` paint the fallback on the six colours `Badge` takes; `sm`, `md`, `lg` and `xl` are fixed edges.

  `Avatar.Badge` pins a count or, left empty, a presence dot to a corner without the circle clipping it. `Avatar.Group`
  overlaps its faces with the first on top, rings each in the page background, and counts the people past `max` — or
  up to `total` — in a trailing `+N` tile that `onOverflowPress` can make a button.

  `delacour add avatar` copies it in.

- [#124](https://github.com/delacournz/delacour-ui/pull/124) Add `Calendar`, an always-visible month grid for picking one day (`mode="single"`), several (`"multiple"`) or a range (`"range"`), controlled or uncontrolled. Always six weeks, so the height never moves; swipe or tap the arrows to page, and tap the caption for month and year jump views. `minDate`/`maxDate` and `disabled` matchers (a date, a span, weekdays or a predicate) limit what can be picked; names and the first day of the week come from the locale. Two variants, three sizes on the input scale, optional `Surface` chrome, custom day content, and `isInvalid` / `isDisabled` / the label cascade from a `Field`. Days are plain `CalendarDate`s — `{ year, month, day }`, no time zone — with the helpers to compare, add, format, parse and serialise them, so no date library is needed. `bunx delacour add calendar` copies it.

- [#117](https://github.com/delacournz/delacour-ui/pull/117) Add `isMotionCalm` to `DelacourProvider`, and `useCalmMotion()`

  An E2E build passes `isMotionCalm` and every decorative loop holds still, exactly as it does under
  the OS reduce-motion setting — so a test runner that waits for the screen to settle before each
  gesture (Argent, Detox, Maestro) never waits out a shimmering `Skeleton`. Motion that is the
  behaviour keeps moving: `Spinner` and an indeterminate `Progress` are untouched.

  `useCalmMotion()` (`@delacour/react-native-ui/hooks/use-calm-motion`) is the one question a
  component asks before it loops — reduce motion, or the app asking — and `CalmMotionProvider` sets
  the app's half for a hand-composed root. `Skeleton` and `Skeleton.Group` now read it.

- [#90](https://github.com/delacournz/delacour-ui/pull/90) Add `Chip`, an interactive pill for filters, tags and removable tokens

  What a chip does follows from its props. With no handler it is a plain tag; with `onPress` it is
  a button; with `isSelected`, `defaultSelected` or `onSelectedChange` it is a filter that toggles —
  controlled or uncontrolled, with a `selection` haptic, announced to a screen reader as selected or
  not. `onClose` adds a remove control with a press of its own, so removing a chip never also toggles
  it.

  ```tsx
  import { Chip } from "@delacour/react-native-ui/chip";

  <Chip isSelected={open} onSelectedChange={setOpen} variant="outline">
    <Icon icon={IconFilter1} />
    <Chip.Label>Open only</Chip.Label>
  </Chip>;
  ```

  It shares `Badge`'s colours, sizes and tones — an unselected `soft` or `outline` chip is painted
  exactly as the badge beside it — and selection swaps in a solid fill in the chip's colour without
  changing its size, so a wrapping row never reflows. Parts: `Chip.Label`, `Chip.StartContent`,
  `Chip.EndContent`, `Chip.CloseButton`, and `useChip()` for a child that restyles itself on
  selection.

  `bunx delacour add chip` copies it in, along with `badge`, whose tones it reads.

  `Pressable` now multiplies a `className`'s opacity into its press feedback instead of overwriting it,
  so a disabled `Button`, `Badge` or `Chip` fades as its variant says it should.

- [#87](https://github.com/delacournz/delacour-ui/pull/87) Add `Collapsible` — one section of content shown and hidden by its own trigger. Controlled (`isOpen` / `onOpenChange`) or uncontrolled (`defaultOpen`), with `Collapsible.Trigger`, `.Title`, `.Description`, `.Indicator` and `.Content`. The panel's height is measured and sprung, so whatever sits below follows it; the panel mounts on first open and stays mounted, and a closed panel leaves the accessibility tree. Shares `Accordion`'s variants, sizes and motion, and `bunx delacour add collapsible` copies it without pulling in an accordion.

- [#136](https://github.com/delacournz/delacour-ui/pull/136) Add `Fab`, one primary action floating over the screen it belongs to. `placement` pins it to the
  bottom start, centre or end of its nearest positioned ancestor, clear of the safe area, or leaves it
  in flow when omitted; sizes are 44, 56 and 64pt from new `--spacing-fab-*` tokens, in `primary`,
  `secondary`, `surface` and `destructive`. `isExtended` with `Fab.Label` makes a labelled stadium.
  `Fab.Group` unfolds a dial of `Fab.Action`s over a scrim from one spring with a stagger, turns its
  plus into a cross, unmounts the actions once closed, closes on the scrim, an action or Android back,
  and takes `isOpen` / `defaultOpen` / `onOpenChange`. `delacour add fab` copies it in.

- [#93](https://github.com/delacournz/delacour-ui/pull/93) Add `Item`, a row of media, text and actions for lists and settings. It renders as a `Pressable` when given `onPress` and as a plain view otherwise, has `default`, `outline` and `muted` surfaces, `sm`/`md`/`lg` sizes, a `vertical` orientation for cards, `isDisabled` and `isSelected` states, and `Item.Media` (bare icon, icon tile or clipped image), `Item.Content`, `Item.Title`, `Item.Description`, `Item.Actions`, `Item.Header`, `Item.Footer`, `Item.Group` and `Item.Separator`. Dropped into a `ListGroup` it takes the group's size, draws no surface of its own and lines up with the group's dividers. The CLI can now `add item`.

- [#85](https://github.com/delacournz/delacour-ui/pull/85) Add `Label`, a form control's name with required, invalid and disabled states

  `Label` renders `Text.Label` and takes a colour, never a scale, so it keeps the type scale the rest
  of a form uses. `isRequired` appends a destructive asterisk as a nested run behind a no-break space,
  so a label that wraps carries the mark after its last word, and announces the label as
  "Email, required" rather than reading the asterisk aloud. `isInvalid` turns it destructive and
  `isDisabled` fades it and reports it disabled to assistive technology.

  ```tsx
  import { Label } from "@delacour/react-native-ui/label";

  <Label isRequired>Email</Label>;
  ```

  `bunx delacour add label` copies it in, bringing `text` and `tv` with it.

- [#138](https://github.com/delacournz/delacour-ui/pull/138) Add `ProgressButton`, a button held rather than tapped to confirm. A fill grows from the leading
  edge over `holdDuration` (2000 ms by default) and `onComplete` fires only when it reaches the end,
  read from the animation's own finish rather than a timer. Released early, the fill plays back at the
  same rate, and a second press resumes from where it is. Every variant (`primary`, `secondary`,
  `destructive`, `success`) rests on the same surface and carries its colour in a label drawn twice,
  so the text stays readable across the wipe. It takes the button's sizes and a `pill` or `rounded`
  shape, draws a tick on completion or a caller's `ProgressButton.Done`, rewinds by travelling back
  with `isAutoReset` or a controlled `isCompleted`, steps in fifths under reduced motion, and
  completes on a screen reader's activate. `delacour add progress-button` copies it in.

- [#91](https://github.com/delacournz/delacour-ui/pull/91) Add `Rating`, a row of stars that reads or sets a score. Tap a star or drag along the row to set it, in whole stars or any step that divides one (`step={0.5}` for halves); a read-only rating draws any value, filling a fraction of a star. `allowClear` lets a tap on the value held withdraw it, `Rating.Output` shows the value, and the row is one adjustable control to screen readers. Six colours, three sizes, and `isInvalid` / `isDisabled` cascade from a `Field`. `bunx delacour add rating` copies it.

- [#96](https://github.com/delacournz/delacour-ui/pull/96) Add `Skeleton`, a placeholder for content that is still loading

  It comes in three shapes — `rect`, `line` and `circle` — and either shimmers a glint across itself or pulses its opacity, on the UI thread. Pass the real content as children and the placeholder takes its exact size, then fades the content in when `isLoading` flips off with nothing moving. `Skeleton.Lines` draws a paragraph, and `Skeleton.Group` keeps every skeleton inside it on one clock and one loading flag. Motion stops under the OS reduce-motion setting, and a placeholder stays hidden from screen readers unless it has a `label`. `bunx delacour add skeleton` copies it in.

- [#99](https://github.com/delacournz/delacour-ui/pull/99) Add `Steps`, a stepper for multi-step flows

  `Steps` shows where someone is in a flow: numbered indicators joined by a line, each step completed, current or
  upcoming against one zero-based `value`. It runs horizontally, with titles under the indicators, or vertically, with
  titles and descriptions beside them, in two variants and three sizes. The connectors are drawn for you — the root
  counts its `Steps.Item`s and every one but the last draws a line to the next, filled once the value has passed it.

  A step can be loading (a spinner in the indicator), invalid (a cross and a destructive title) or disabled, and
  `completed` overrides whether it reads as done. Steps take presses and move the value there; `isLinear` keeps the
  steps ahead closed, and a controlled `value` with no `onValueChange` is a read-only progress display whose steps are
  not announced as buttons. `Steps.Panel` holds a step's form or summary below its title, outside the tap target, so its
  controls stay reachable by a screen reader. Each step is announced as its title with a value such as "Step 2 of 3,
  completed".

  `bunx delacour add steps` copies it into your project.

- [#89](https://github.com/delacournz/delacour-ui/pull/89) Add `Textarea`, a multiline text field sized in rows. It renders `Input`'s box — variants, sizes, focus, invalid, disabled and the `Field` cascade — and adds a height derived from `rows` and the size's line height, `autoGrow` up to `maxRows`, and a `showCount` character count against `maxLength` that turns destructive at the limit. `delacour add textarea` copies it, with `input` and `text` as registry dependencies.

- [#84](https://github.com/delacournz/delacour-ui/pull/84) Add `ToggleButton`, a button that stays pressed. On its own it is controlled with `isSelected` and
  `onSelected` or holds its own state from `defaultSelected`; inside `ToggleButton.Group` the group
  owns one array of selected values, in `multiple` or `single` selection mode, with
  `isSelectionRequired` to keep the last choice from being cleared. Each state draws with one of the
  button's own variants (`default`, `outline`, `ghost`), so sizes, icons, loading and press feedback
  are the button's. An attached group joins into one run like `Button.Group`; a detached one wraps
  with a gap. The state is announced as a toggle button that is checked, or as a selected radio in a
  single-choice group. `delacour add toggle-button` copies it in.

- [#35](https://github.com/delacournz/delacour-ui/pull/35) `init` copies the root provider in and `doctor` accepts `DelacourProvider` as the gesture root

  `delacour init` now adds the `provider` item alongside `styles`, so `DelacourProvider` is in the
  `ui` directory before anything is mounted, and its follow-up list names that import rather than a
  bare `GestureHandlerRootView`. `doctor`'s Gesture Handler check passes on either name, reads a
  blank template's root `App.tsx` as well as `app/` and `src/`, and no longer counts the copied
  `provider.tsx` itself as the app mounting it.

- [#49](https://github.com/delacournz/delacour-ui/pull/49) `add` sets the project up itself

  `add` no longer fails on a project with no `native-components.json`. It runs `init` first — writing
  the config, wrapping Metro, pointing Tailwind at the components and copying the theme and the root
  provider in — and then adds what was asked for. That was previously a prompt, and only where there
  was a terminal to ask in, so `--yes`, CI and every MCP call hit `MissingConfigError` while a human
  sailed past. `--no-init` is the opt-out, and `-s, --src <dir>` forwards to `init` so a template that
  keeps its files at the project root still needs one command.

  `init` now returns the result of the `add` it ends on, so a caller that set a project up still
  learns what the components need from npm.

  New MCP tool `init_project`, for the layout an agent cannot infer — a shared package in a monorepo,
  or a source directory that is not `src`. `add_components` needs it no more often than a person
  needs `init`.

- [#25](https://github.com/delacournz/delacour-ui/pull/25) One theme file, the same shape everywhere

  `theme.css` is now the one file in `styles/` that is yours, and its header says so. What
  `delacour init` ships, what the docs site's `/theme` page emits with no preset, and what
  `delacour theme` writes are held to the same shape, declaration for declaration.

  **`delacour theme` converts `theme.css` in place.** Paste a shadcn or tweakcn `globals.css` over
  the file and run the command with no argument: a file already in Uniwind's shape is left alone, a
  shadcn-shaped one is rewritten, and anything else is named. `delacour doctor` fails on a `theme.css`
  still in shadcn's `:root` / `.dark` shape, which Uniwind reads as a utility class named `dark` and a
  dark theme that never arrives.

  **The converter fills what shadcn v4 stopped declaring.** `--destructive-foreground` — which
  `Button`, `Badge`, `Switch`, `Slider` and `Checkbox` all paint with — and the shadow scale are now
  derived when a source omits them, and the light `--elevated` derivation follows the card, as the
  shipped file already did.

  **The shipped defaults are shadcn's current ones.** The chart ramp is the neutral greys `shadcn
init` writes today, and the default typeface is each platform's own sans rather than Geist, which a
  fresh app had never loaded. The `/theme` page shows `theme.css` first, with shadcn's `globals.css`
  in a second tab for a web app sharing the theme.

- [#51](https://github.com/delacournz/delacour-ui/pull/51) `delacour skills` installs an agent skill

  An agent asked for "a button" writes plausible JSX — the right shape, and none of the parts that
  matter: the icon that inherits its size from the button's context, the spinner that _replaces_ the
  icon so the label does not shift, the `expo install` route for the native modules underneath.

  `bunx delacour@alpha skills` installs a skill into whichever assistants a project uses — Claude
  Code, Cursor, OpenCode or Codex, detected from the directories present, or named with `--agent`, in
  `--scope project` or `user`. The files are bundled into the binary, so a run works offline and
  installs the skill matching the version you are pinned to. The docs site serves the same bytes at
  `/skills/delacour-ui/SKILL.md`.

  The skill names no component on purpose. A catalogue on someone's disk is stale the day the next
  component ships, and silently so — it teaches `list`, `view`, `add` and `doctor` instead, and spends
  its own words on the failures that produce no error message.

### Patch changes [#patch-changes-7]

- [#117](https://github.com/delacournz/delacour-ui/pull/117) Fix `Accordion` and `Collapsible` panels that never opened on their first expand in Release builds

  The item's effect decided "has the panel measured?" by reading the measured height's shared value
  on the JS thread, straight after the panel's `onLayout` had written it. That write is queued onto
  the UI runtime and the read does not drain the queue, so a Release build read the unmeasured
  sentinel every time, bailed, and nothing re-ran it — the trigger said expanded and the panel stayed
  shut. Debug builds were slow enough to hide it. "Measured" is now React state, the decision is a
  pure `accordionTravelTarget` / `collapsibleTravelTarget`, and a test sweeps both components for any
  JS-thread read of the height.

- [#94](https://github.com/delacournz/delacour-ui/pull/94) Add `Alert`, a status message on a `Surface`

  Five statuses — `default`, `info`, `success`, `warning` and `destructive` — pick the leading glyph
  and colour it and the title from one token, while the description stays muted. `variant="soft"`
  washes the surface in the status's soft fill; `variant="surface"` keeps a neutral fill that steps
  off whatever it sits in. Three sizes move padding, type and glyph together. Composed from
  `Alert.Indicator`, `Alert.Content`, `Alert.Title`, `Alert.Description`, `Alert.Action` and
  `Alert.CloseButton`; `isDismissible` adds the close control, uncontrolled or through `isOpen` /
  `onOpenChange`, and `useAlert().dismiss` closes it from an action. `bunx delacour add alert` copies
  it into a project, with `surface` alongside.

- [#95](https://github.com/delacournz/delacour-ui/pull/95) Add `Card`, a content surface with a header, a body and a footer

  Built on `Surface`, so it takes the same four fills and steps to the next one when nested. Six parts —
  `Card.Header`, `Card.Title`, `Card.Description`, `Card.Action`, `Card.Content` and `Card.Footer` —
  share one inset through context across three sizes, and the padding lives on the parts, so media placed
  straight in the card reaches its edges. `Card.Action` is pinned to the header's corner wherever it is
  written, the title follows the foreground token of the card's fill, and `Card.Footer variant="band"`
  sets the footer into the card on the next fill down. `useCard()` exposes the size and fill to custom
  parts, and `bunx delacour add card` copies it into a project, with `surface` alongside.

- [#116](https://github.com/delacournz/delacour-ui/pull/116) `add bottom-sheet` installs the engine instead of the library it replaced: `@delacour/react-native-bottom-sheet` from npm, and `react-native-teleport` through `expo install`, because it ships a Fabric portal view and needs a rebuild. `@gorhom/bottom-sheet` has left the install map, `doctor` watches `react-native-teleport` for a duplicated copy in a monorepo, and its New Architecture failure now names `BottomSheet`, whose portal does not render on the old one.

- [#106](https://github.com/delacournz/delacour-ui/pull/106) Install Delacour packages from the CLI's own release line. An alpha CLI (`delacour@alpha`) adds `@delacour/react-native-ui@alpha` and `@delacour/react-native-charts@alpha`, and a stable CLI adds them untagged from `latest`. A peer on a Delacour package is still written as `>=0.0.0-0`, so either line satisfies it.

- [#125](https://github.com/delacournz/delacour-ui/pull/125) Add `Dialog`, a centred card over a dimmed app that asks for a decision or a short input

  `@delacour/react-native-ui/dialog`, and `delacour add dialog`. A compound root with `Trigger`,
  `Content`, `Close`, `Header`, `Title`, `Description`, `Body` and `Footer`, drawn through the overlay
  foundation, so it sits above every bottom sheet and the navigator's header. `isOpen` /
  `defaultOpen` / `onOpenChange`, and `isDismissible={false}` for an alert dialog that only its own
  actions close. Four sizes (`sm`, `md`, `lg`, `full`), a `plain` or `panel` footer that stacks on
  `sm`, a card that lifts just clear of the keyboard, a fade-only entrance under Reduce Motion, and
  accessibility focus that moves to the title on open and back to the trigger on close.

  Also: `Overlay.Portal`'s missing-provider warning no longer names the npm package, so a copied
  overlay carries no reference to it.

- [#129](https://github.com/delacournz/delacour-ui/pull/129) Add `Drawer`, a panel that slides in from an edge and covers the app until dismissed

  `@delacour/react-native-ui/drawer`, and `delacour add drawer`. A compound root with `Trigger`,
  `Content`, `Header`, `Title`, `Description`, `Body`, `Footer` and `Close`, drawn through the overlay
  foundation, so it sits above every bottom sheet and the navigator's header. Four sides — `start` and
  `end` swap under RTL, plus `top` and `bottom` — and four sizes as a capped fraction of the window.
  Swipe toward the edge to dismiss: past 40% or on a fling it carries on from the finger, short of that
  it eases back, a selection haptic marks the threshold and the scrim thins with the drag. The panel
  pads the safe-area insets on its screen sides, fades instead of sliding under Reduce Motion, and
  moves accessibility focus to the title on open and back to the trigger on close.

- [#86](https://github.com/delacournz/delacour-ui/pull/86) Add `EmptyState`

  A placeholder for a list or screen with nothing in it. `EmptyState.Header` stacks `Media`, `Title` and
  `Description`, and `EmptyState.Content` holds the actions. `variant="card"` draws a dashed block for an
  empty section beside populated ones, and `size` scales the padding, media and type together. A bare
  `Icon` in `Media` inherits its size and colour, and `Media variant="icon"` tints a box behind it.

  `delacour add empty-state` copies it into a project.

- [#130](https://github.com/delacournz/delacour-ui/pull/130) Add `Feedback`, a dialog for writing — the field in a recessed well, the actions on the band around it

  `@delacour/react-native-ui/feedback`, and `delacour add feedback`. Built on `Dialog`, so open state,
  portal, scrim, back, escape, focus and the keyboard lift are Dialog's. A compound root with
  `Trigger`, `Content`, `Panel`, `Title`, `Close`, `Field`, `Footer`, `Action`, `Cancel` and `Submit`,
  and `useFeedback()`. The draft is `value` / `defaultValue` / `onValueChange` on the root and survives
  close and reopen until `clear()`. `Submit` is gated by `canSubmitFeedback` (empty and whitespace are
  empty, `canSubmitEmpty` for chips or a rating), passes the trimmed text, shows its loading state and
  makes the field read-only while a returned promise is in flight, and never closes on its own. The
  well eases to its measured height when a multi-step flow swaps its content, so the card never
  jumps; under Reduce Motion it changes height at once. The field grows from `minRows` (6) to
  `maxRows` (12) before it scrolls, and takes the title's text as its label.

- [#98](https://github.com/delacournz/delacour-ui/pull/98) Add `Kpi`, one number, its change and a sparkline of how it got there

  Built on `Card`, so it takes the card's four fills and three sizes and sits on the card's inset. `Kpi.Trend`
  takes a signed percentage and colours it by what it means rather than by its sign — `goodDirection` on the
  card says whether up, down or neither is good news, and every trend inside follows it — as a line of text or
  a badge with an arrow, announced as one string. `Kpi.Sparkline` is a `Chart` line with no axes in the card's
  series colour, under the number or in a fixed column beside it, and holding it scrubs a point: the KPI keeps
  the scrubbed index as controllable state that `useKpi()` reads. `isLoading` holds placeholders of each part's
  size, and `Kpi.Group` lays several metrics out in a row or a column, optionally on one surface with rules
  between. `Chart` gains `frameClassName`, which sizes the plot's frame. `bunx delacour add kpi` copies it into a
  project, with `card` and `chart` alongside.

- [#120](https://github.com/delacournz/delacour-ui/pull/120) Add `OverlayProvider`, the layer every overlay is drawn on

  `@delacour/react-native-ui/overlay` mounts the one teleport host that overlays and bottom sheets
  share, and a registry that orders them in bands — every overlay above every sheet, an anchored
  panel above the dialog that opened it, a toast above both — and gives Android's back button to the
  topmost overlay only. `Overlay.Portal`, `Overlay.Scrim`, `useOverlayPresence` (keeps an overlay
  mounted through its exit animation) and `useOverlayBackHandler` are exported for building more.
  `BottomSheetProvider` now detects an `OverlayProvider` above or below it and mounts teleport's
  provider only once; the engine's provider takes `hasPortalProvider` to make that possible.
  `bunx delacour add overlay` copies it into a project.

- [#127](https://github.com/delacournz/delacour-ui/pull/127) Add `Popover` — a small panel anchored to its trigger that flips and shifts to stay inside the safe area and above the keyboard, with an arrow that keeps pointing at the trigger, a title, a description, a close control, an optional scrim, `width="trigger"` and a scrollable body. Its anchoring pieces — `resolveAnchoredPosition`, `useAnchorMeasure`, `useAnchoredContent` and `AnchoredArrow` — are exported for other anchored overlays. `delacour add popover` copies it.

- [#83](https://github.com/delacournz/delacour-ui/pull/83) Add `Surface`, a rounded container on the theme's fill ladder

  Four fills — `default`, `secondary`, `tertiary` and `transparent` — and four padding steps. A
  surface that names no variant steps to the next fill from the one it sits in, so a panel inside a
  card never vanishes into it, and a transparent surface passes the plane beneath it through.
  `useSurface()` exposes the resolved fill to custom children, and `padding="none"` clips, for
  content bled to the corners. `bunx delacour add surface` copies it into a project.

- [#122](https://github.com/delacournz/delacour-ui/pull/122) Add `Toast` — a brief message shown with `toast()` from anywhere, including outside React, and drawn by one `<ToastViewport />` mounted inside `OverlayProvider`. Toasts stack at the top or bottom edge, three drawn with the newest in front and the rest queued; they sit above the home indicator and the keyboard, pause their clock while touched or backgrounded, and swipe away toward their edge or sideways. Statuses, glyphs and title colours are `Alert`'s; `toast.promise` turns one loading toast into the success or the failure in place; `render` composes a custom card from `<Toast>`'s parts. Each toast is announced as it appears and stays at least ten seconds under a screen reader. Alert's status glyphs move to the `alert-glyphs.ts` leaf so the two share them. `delacour add toast` copies it.

- [#128](https://github.com/delacournz/delacour-ui/pull/128) Add `Tooltip` — a short label anchored to its control that opens on a long press (or a press, with `openOn="press"`), hides itself after `duration`, and closes on any outside tap while letting that tap through to what it landed on. It flips and shifts like `Popover`, has an inverted and a surface variant, an arrow that points at the trigger, and reads its `label` to a screen reader on the trigger without opening. `OverlayProvider` now hears every touch that starts beneath it, through `subscribeTouchStart`, without claiming any. `delacour add tooltip` copies it.

- [#48](https://github.com/delacournz/delacour-ui/pull/48) Publish the libraries under the `@delacour` org

  `delacour-react-native-ui` is now `@delacour/react-native-ui`, and `delacour-react-native-charts` is now
  `@delacour/react-native-charts`. The old names are deprecated and take no further versions. (Both were briefly spelled
  `@delacour/native-ui` and `@delacour/charts` in this repository; neither reached npm, so the line
  above is the whole story for anyone installing.) Nothing about the
  components changed — swap the package and the import prefix:

  ```bash
  bun remove delacour-react-native-ui delacour-react-native-charts
  bun add @delacour/react-native-ui@alpha @delacour/react-native-charts@alpha
  ```

  ```diff
  - import { Button } from "delacour-react-native-ui/button";
  + import { Button } from "@delacour/react-native-ui/button";
  ```

  and in `global.css`, `@import '@delacour/react-native-ui/styles';`.

  The CLI keeps its name. `delacour add chart` now installs `@delacour/react-native-charts`.

- [#22](https://github.com/delacournz/delacour-ui/pull/22) Add bar, scatter, candlestick and pie charts, stacked areas and horizontal bars

  **`@delacour/react-native-charts`** gains four marks and a second root. `ChartBar` draws
  one bar per datum on a cubic-cornered rect path, so a corner radius animates
  without snapping; sibling bars share a step and bars naming one `stackId`
  stack in data space, so the y domain covers the running totals rather than
  the tallest series. `ChartArea` takes the same `stackId`. `ChartScatter` is
  one Skia path per series, and `ChartCandlestick` draws every candle through every sentiment
  path so a colour flip is a morph rather than a cut. `orientation="horizontal"`
  swaps the axis roles at the model, so bars grow rightward from a category
  axis. `PolarChart` is the new root, with `PieSlices` on a fixed-verb path
  that morphs between any two data sets and a scrub-free tap that resolves a
  slice index. `@delacour/react-native-charts/core` exports the bar, scatter, candle and
  slice geometry alongside the scales.

  **`@delacour/react-native-ui/chart`** skins all of it. `Chart.Bar`, `Chart.Scatter`
  and `Chart.Candlestick` join `Chart.Line` and `Chart.Area`; bars group by
  being siblings, stack by sharing a `stackId`, round their value end from
  `--radius`, and take `labels`. Candles borrow `success`, `destructive` and
  `muted-foreground` for their sentiment. Over bars or candles `Chart.Tooltip.X`
  becomes a band one step wide. `PieChart` is a second root — `PieChart.Slice`,
  `.Label`, `.Center`, `.Tooltip` and `.Legend` — whose categories are its rows,
  with `innerRadius` for a donut and a tap-driven readout.

  Series colours now dedupe before the theme lookup, so twenty slices walking
  the five-token ramp resolve five tokens rather than throwing past the eighth.

  The CLI's chart registry item picks up the new files and names the new marks
  in its description.

- [#52](https://github.com/delacournz/delacour-ui/pull/52) Teach one verb, and hold the docs to the CLI

  The Quick start forks before the first command — a new app, an existing one, or hand it to an
  agent — and lands all three on one rendered Button. It scaffolds Expo's `with-router-uniwind`
  example and never names `init`: `add` does that setup itself, so a reader learns one verb.

  The landing page's hero says `add` too, the package path names Uniwind as a real setup step with
  links to its own guide, and a handful of claims that had gone stale are corrected — the registry
  holds no copy of the library's source, `/llms.txt` lives on `ui.delacour.co.nz`, and the releases
  page no longer reports a version that was never published.

  `docs-commands.test.ts` walks the commander program and holds every copyable `delacour …` in the
  repository to it — verb, long flags, positional arity, and whether a component named in an example
  is in the registry. It caught `add --src` before a reader did.

- [#72](https://github.com/delacournz/delacour-ui/pull/72) List every native peer in the install command. The charts README's `expo install` line named only Skia, and `delacour add chart` skipped Gesture Handler — the scrub and the pie's tap then never fire, with no error.

- [#104](https://github.com/delacournz/delacour-ui/pull/104) Point the "registry may be newer than this CLI" hint at `--ref develop`. `main` now moves only on a release, so unreleased components live on `develop`.

- [#50](https://github.com/delacournz/delacour-ui/pull/50) `doctor` stops failing correct Metro configs, and tells you a path you can paste

  - **`withUniwindConfig is not the outermost wrapper`, when it was.** The check required the export
    expression to _begin_ with `withUniwindConfig`, so it failed both
    `const c = withUniwindConfig(…); module.exports = c;` and the reassignment a Metro config uses
    when it applies several wrappers in turn — `config = withUniwindConfig(config, …)`. A wrapper
    genuinely applied after Uniwind still fails, which is the point of the check.
  - **`cssEntryFile does not point at the configured entry` restated the problem rather than the
    fix.** It now says which file Metro actually compiles and why that is the one that has to win.
  - **The CSS import it told you to add did not resolve.** It was `./` plus the file's basename,
    which is right only when the root layout sits in the same directory as the CSS. On the ordinary
    Expo Router layout it is `../styles/global.css`, and that is what both `doctor` and `init` now
    print — from one function.

- [#50](https://github.com/delacournz/delacour-ui/pull/50) Adopt the Tailwind entry an app already has, and print the root layout

  **One entry, never two.** `init` picked `<src>/styles/global.css` unless a wrapped Metro config
  named another, so an app that had installed Uniwind and written its own `global.css` — without
  wiring Metro to it yet — got a second entry. Tailwind then compiled the file holding the `@source`
  globs while the app imported the one without them: every component unstyled, nothing logged, and
  `doctor` reporting that nothing imports the entry. An entry already on disk is now adopted.

  **The root layout is printed whole.** Two of the three follow-ups are edits to one file, so `init`
  shows that file rather than describing it — and detects Expo Router, whose root layout is a
  different file with a different shape (`app/_layout.tsx` rendering a `<Slot />`, not `App.tsx`).
  The bullet and the snippet take their import paths from one function, so they cannot disagree.

- [#55](https://github.com/delacournz/delacour-ui/pull/55) Refresh the lockfile and drop an obsolete patch

  `bun.lock` pinned `expo-modules-jsi@57.0.5` while a dependency already required `~57.1.0`, so
  `bun install --frozen-lockfile` failed the moment anything forced a re-resolve. The patch that
  pinning existed for — declaring `retainRuntimeScheduler` / `releaseRuntimeScheduler` for Swift
  bridging — ships in `57.1.0` itself, so it and its `patchedDependencies` entry are gone.

- [#49](https://github.com/delacournz/delacour-ui/pull/49) Stop the last line suggesting a command that already ran

  `add` delegates to `init` whenever a project has no config, so a run that copied `button` in ended
  on _"Ready. `delacour add button` to get started."_ — the command the reader had just run. The outro
  now names what landed instead: _"Ready. `button` is yours to edit."_

  It no longer mentions `doctor` either. The follow-up block directly above it already ends on
  `delacour doctor`, and two consecutive lines pointing at the same command read as a glitch rather
  than as emphasis.

- [#22](https://github.com/delacournz/delacour-ui/pull/22) Add charts: a headless Skia engine, and the `Chart` component that skins it

  **`@delacour/react-native-charts` is new** — a token-free charting engine for React Native,
  drawn with Skia, animated with Reanimated and driven by Gesture Handler. It
  ships `CartesianChart` with `Line`, `Area`, `Grid` and both axes, a scrub whose
  dot rides the drawn curve rather than hopping between data points, and path
  morphing that never falls back to snapping. `@delacour/react-native-charts/core` is every
  scale, tick, curve and solver in it, importable with no Skia in the module graph.

  **`@delacour/react-native-ui/chart`** is that engine wearing the theme. A shadcn-shaped
  `config` names each series and assigns `--chart-1` … `--chart-5` by position, so
  a call site writes `<Chart.Line yKey="revenue" />` and never a colour. Parts are
  placed rather than configured: `Chart.Grid`, `Chart.Line`, `Chart.Area`,
  `Chart.XAxis` and `Chart.YAxis` draw into the canvas, while `Chart.Tooltip` and
  `Chart.Legend` are React Native views layered over and under it.

  Also new: `--spacing-chart-sm/md/lg`, because a canvas has no intrinsic height
  and a dashboard's rows only line up if every chart agrees on one.

  **This needs a dev-client rebuild.** `@shopify/react-native-skia` is a native
  module and is new to the workspace — run `expo prebuild --clean` and rebuild
  before running the playground.

  The CLI learns two things: how to install a Skia-backed component, and that
  `@delacour/react-native-charts` publishes to the `alpha` tag while this repository is in pre
  mode, since a bare `bun add` of it would resolve `latest` and find nothing.

- [#50](https://github.com/delacournz/delacour-ui/pull/50) Work correctly on a project that already has Uniwind

  Three bugs, all found against Expo's `with-router-uniwind` example — a scaffold that arrives with
  Uniwind, Tailwind and Metro already wired.

  - **`init` wrote its `@source` block into a file Metro does not compile.** A wired Metro config
    names its own `cssEntryFile`, and `init` recorded `<src>/styles/global.css` regardless — so
    Tailwind scanned a file with no globs in it, every class the components use was dropped, and
    every component rendered unstyled with nothing logged. It now reads `cssEntryFile` and `dtsFile`
    off the wrapped config and records those.
  - **`doctor` failed the official template.** Its outermost-wrapper check required the export
    expression to begin with `withUniwindConfig`, and that template assigns the wrapped config to a
    variable before exporting it. The exported name is now followed to the last thing assigned to it
    above the export, a few hops deep.
  - **`init` asked for a CSS import that was already there.** The follow-up list is now built from
    what the project actually has, so neither the CSS import nor the provider is listed once it is
    mounted.

- [#50](https://github.com/delacournz/delacour-ui/pull/50) Refuse to stack a second Tailwind transform

  Nothing noticed when a project already had **NativeWind**. It is Tailwind for React Native too: it
  compiles `className`, and it does that by wrapping Metro. Wrapping Metro again on top of it leaves
  classes resolving through whichever wrapper ran last and a build that fails naming neither library.

  `init` now warns before it touches `metro.config.js`, and `doctor` carries a `Styling` check that
  keeps saying so.

  It is deliberately not fixed automatically. Which of the two a project keeps is the owner's call,
  and uninstalling someone's styling library is not a thing a component CLI gets to do — so the
  message points at Uniwind's migration guide instead.

## 0.1.0-alpha.6 [#010-alpha6]

### Patch changes [#patch-changes-8]

- [#104](https://github.com/delacournz/delacour-ui/pull/104) Point the "registry may be newer than this CLI" hint at `--ref develop`. `main` now moves only on a release, so unreleased components live on `develop`.

## 0.1.0-alpha.5 [#010-alpha5]

### Patch changes [#patch-changes-9]

- [#72](https://github.com/delacournz/delacour-ui/pull/72) List every native peer in the install command. The charts README's `expo install` line named only Skia, and `delacour add chart` skipped Gesture Handler — the scrub and the pie's tap then never fire, with no error.

## 0.1.0-alpha.4 [#010-alpha4]

### Minor changes [#minor-changes-8]

- [#49](https://github.com/delacournz/delacour-ui/pull/49) `add` sets the project up itself

  `add` no longer fails on a project with no `native-components.json`. It runs `init` first — writing
  the config, wrapping Metro, pointing Tailwind at the components and copying the theme and the root
  provider in — and then adds what was asked for. That was previously a prompt, and only where there
  was a terminal to ask in, so `--yes`, CI and every MCP call hit `MissingConfigError` while a human
  sailed past. `--no-init` is the opt-out, and `-s, --src <dir>` forwards to `init` so a template that
  keeps its files at the project root still needs one command.

  `init` now returns the result of the `add` it ends on, so a caller that set a project up still
  learns what the components need from npm.

  New MCP tool `init_project`, for the layout an agent cannot infer — a shared package in a monorepo,
  or a source directory that is not `src`. `add_components` needs it no more often than a person
  needs `init`.

- [#51](https://github.com/delacournz/delacour-ui/pull/51) `delacour skills` installs an agent skill

  An agent asked for "a button" writes plausible JSX — the right shape, and none of the parts that
  matter: the icon that inherits its size from the button's context, the spinner that _replaces_ the
  icon so the label does not shift, the `expo install` route for the native modules underneath.

  `bunx delacour@alpha skills` installs a skill into whichever assistants a project uses — Claude
  Code, Cursor, OpenCode or Codex, detected from the directories present, or named with `--agent`, in
  `--scope project` or `user`. The files are bundled into the binary, so a run works offline and
  installs the skill matching the version you are pinned to. The docs site serves the same bytes at
  `/skills/delacour-ui/SKILL.md`.

  The skill names no component on purpose. A catalogue on someone's disk is stale the day the next
  component ships, and silently so — it teaches `list`, `view`, `add` and `doctor` instead, and spends
  its own words on the failures that produce no error message.

### Patch changes [#patch-changes-10]

- [#52](https://github.com/delacournz/delacour-ui/pull/52) Teach one verb, and hold the docs to the CLI

  The Quick start forks before the first command — a new app, an existing one, or hand it to an
  agent — and lands all three on one rendered Button. It scaffolds Expo's `with-router-uniwind`
  example and never names `init`: `add` does that setup itself, so a reader learns one verb.

  The landing page's hero says `add` too, the package path names Uniwind as a real setup step with
  links to its own guide, and a handful of claims that had gone stale are corrected — the registry
  holds no copy of the library's source, `/llms.txt` lives on `ui.delacour.co.nz`, and the releases
  page no longer reports a version that was never published.

  `docs-commands.test.ts` walks the commander program and holds every copyable `delacour …` in the
  repository to it — verb, long flags, positional arity, and whether a component named in an example
  is in the registry. It caught `add --src` before a reader did.

- [#50](https://github.com/delacournz/delacour-ui/pull/50) `doctor` stops failing correct Metro configs, and tells you a path you can paste

  - **`withUniwindConfig is not the outermost wrapper`, when it was.** The check required the export
    expression to _begin_ with `withUniwindConfig`, so it failed both
    `const c = withUniwindConfig(…); module.exports = c;` and the reassignment a Metro config uses
    when it applies several wrappers in turn — `config = withUniwindConfig(config, …)`. A wrapper
    genuinely applied after Uniwind still fails, which is the point of the check.
  - **`cssEntryFile does not point at the configured entry` restated the problem rather than the
    fix.** It now says which file Metro actually compiles and why that is the one that has to win.
  - **The CSS import it told you to add did not resolve.** It was `./` plus the file's basename,
    which is right only when the root layout sits in the same directory as the CSS. On the ordinary
    Expo Router layout it is `../styles/global.css`, and that is what both `doctor` and `init` now
    print — from one function.

- [#50](https://github.com/delacournz/delacour-ui/pull/50) Adopt the Tailwind entry an app already has, and print the root layout

  **One entry, never two.** `init` picked `<src>/styles/global.css` unless a wrapped Metro config
  named another, so an app that had installed Uniwind and written its own `global.css` — without
  wiring Metro to it yet — got a second entry. Tailwind then compiled the file holding the `@source`
  globs while the app imported the one without them: every component unstyled, nothing logged, and
  `doctor` reporting that nothing imports the entry. An entry already on disk is now adopted.

  **The root layout is printed whole.** Two of the three follow-ups are edits to one file, so `init`
  shows that file rather than describing it — and detects Expo Router, whose root layout is a
  different file with a different shape (`app/_layout.tsx` rendering a `<Slot />`, not `App.tsx`).
  The bullet and the snippet take their import paths from one function, so they cannot disagree.

- [#55](https://github.com/delacournz/delacour-ui/pull/55) Refresh the lockfile and drop an obsolete patch

  `bun.lock` pinned `expo-modules-jsi@57.0.5` while a dependency already required `~57.1.0`, so
  `bun install --frozen-lockfile` failed the moment anything forced a re-resolve. The patch that
  pinning existed for — declaring `retainRuntimeScheduler` / `releaseRuntimeScheduler` for Swift
  bridging — ships in `57.1.0` itself, so it and its `patchedDependencies` entry are gone.

- [#49](https://github.com/delacournz/delacour-ui/pull/49) Stop the last line suggesting a command that already ran

  `add` delegates to `init` whenever a project has no config, so a run that copied `button` in ended
  on _"Ready. `delacour add button` to get started."_ — the command the reader had just run. The outro
  now names what landed instead: _"Ready. `button` is yours to edit."_

  It no longer mentions `doctor` either. The follow-up block directly above it already ends on
  `delacour doctor`, and two consecutive lines pointing at the same command read as a glitch rather
  than as emphasis.

- [#50](https://github.com/delacournz/delacour-ui/pull/50) Work correctly on a project that already has Uniwind

  Three bugs, all found against Expo's `with-router-uniwind` example — a scaffold that arrives with
  Uniwind, Tailwind and Metro already wired.

  - **`init` wrote its `@source` block into a file Metro does not compile.** A wired Metro config
    names its own `cssEntryFile`, and `init` recorded `<src>/styles/global.css` regardless — so
    Tailwind scanned a file with no globs in it, every class the components use was dropped, and
    every component rendered unstyled with nothing logged. It now reads `cssEntryFile` and `dtsFile`
    off the wrapped config and records those.
  - **`doctor` failed the official template.** Its outermost-wrapper check required the export
    expression to begin with `withUniwindConfig`, and that template assigns the wrapped config to a
    variable before exporting it. The exported name is now followed to the last thing assigned to it
    above the export, a few hops deep.
  - **`init` asked for a CSS import that was already there.** The follow-up list is now built from
    what the project actually has, so neither the CSS import nor the provider is listed once it is
    mounted.

- [#50](https://github.com/delacournz/delacour-ui/pull/50) Refuse to stack a second Tailwind transform

  Nothing noticed when a project already had **NativeWind**. It is Tailwind for React Native too: it
  compiles `className`, and it does that by wrapping Metro. Wrapping Metro again on top of it leaves
  classes resolving through whichever wrapper ran last and a build that fails naming neither library.

  `init` now warns before it touches `metro.config.js`, and `doctor` carries a `Styling` check that
  keeps saying so.

  It is deliberately not fixed automatically. Which of the two a project keeps is the owner's call,
  and uninstalling someone's styling library is not a thing a component CLI gets to do — so the
  message points at Uniwind's migration guide instead.

## 0.1.0-alpha.3 [#010-alpha3]

### Patch changes [#patch-changes-11]

- [#48](https://github.com/delacournz/delacour-ui/pull/48) Publish the libraries under the `@delacour` org

  `delacour-react-native-ui` is now `@delacour/react-native-ui`, and `delacour-react-native-charts` is now
  `@delacour/react-native-charts`. The old names are deprecated and take no further versions. Nothing about the
  components changed — swap the package and the import prefix:

  ```bash
  bun remove delacour-react-native-ui delacour-react-native-charts
  bun add @delacour/react-native-ui@alpha @delacour/react-native-charts@alpha
  ```

  ```diff
  - import { Button } from "delacour-react-native-ui/button";
  + import { Button } from "@delacour/react-native-ui/button";
  ```

  and in `global.css`, `@import '@delacour/react-native-ui/styles';`.

  The CLI keeps its name. `delacour add chart` now installs `@delacour/react-native-charts`.

## 0.1.0-alpha.2 [#010-alpha2]

### Minor changes [#minor-changes-9]

- [#35](https://github.com/delacournz/delacour-ui/pull/35) `init` copies the root provider in and `doctor` accepts `DelacourProvider` as the gesture root

  `delacour init` now adds the `provider` item alongside `styles`, so `DelacourProvider` is in the
  `ui` directory before anything is mounted, and its follow-up list names that import rather than a
  bare `GestureHandlerRootView`. `doctor`'s Gesture Handler check passes on either name, reads a
  blank template's root `App.tsx` as well as `app/` and `src/`, and no longer counts the copied
  `provider.tsx` itself as the app mounting it.

## 0.1.0-alpha.1 [#010-alpha1]

### Minor changes [#minor-changes-10]

- [#25](https://github.com/delacournz/delacour-ui/pull/25) One theme file, the same shape everywhere

  `theme.css` is now the one file in `styles/` that is yours, and its header says so. What
  `delacour init` ships, what the docs site's `/theme` page emits with no preset, and what
  `delacour theme` writes are held to the same shape, declaration for declaration.

  **`delacour theme` converts `theme.css` in place.** Paste a shadcn or tweakcn `globals.css` over
  the file and run the command with no argument: a file already in Uniwind's shape is left alone, a
  shadcn-shaped one is rewritten, and anything else is named. `delacour doctor` fails on a `theme.css`
  still in shadcn's `:root` / `.dark` shape, which Uniwind reads as a utility class named `dark` and a
  dark theme that never arrives.

  **The converter fills what shadcn v4 stopped declaring.** `--destructive-foreground` — which
  `Button`, `Badge`, `Switch`, `Slider` and `Checkbox` all paint with — and the shadow scale are now
  derived when a source omits them, and the light `--elevated` derivation follows the card, as the
  shipped file already did.

  **The shipped defaults are shadcn's current ones.** The chart ramp is the neutral greys `shadcn
init` writes today, and the default typeface is each platform's own sans rather than Geist, which a
  fresh app had never loaded. The `/theme` page shows `theme.css` first, with shadcn's `globals.css`
  in a second tab for a web app sharing the theme.

### Patch changes [#patch-changes-12]

- [#22](https://github.com/delacournz/delacour-ui/pull/22) Add bar, scatter, candlestick and pie charts, stacked areas and horizontal bars

  **`@delacour/react-native-charts`** gains four marks and a second root. `ChartBar` draws
  one bar per datum on a cubic-cornered rect path, so a corner radius animates
  without snapping; sibling bars share a step and bars naming one `stackId`
  stack in data space, so the y domain covers the running totals rather than
  the tallest series. `ChartArea` takes the same `stackId`. `ChartScatter` is
  one Skia path per series, and `ChartCandlestick` draws every candle through every sentiment
  path so a colour flip is a morph rather than a cut. `orientation="horizontal"`
  swaps the axis roles at the model, so bars grow rightward from a category
  axis. `PolarChart` is the new root, with `PieSlices` on a fixed-verb path
  that morphs between any two data sets and a scrub-free tap that resolves a
  slice index. `@delacour/react-native-charts/core` exports the bar, scatter, candle and
  slice geometry alongside the scales.

  **`@delacour/react-native-ui/chart`** skins all of it. `Chart.Bar`, `Chart.Scatter`
  and `Chart.Candlestick` join `Chart.Line` and `Chart.Area`; bars group by
  being siblings, stack by sharing a `stackId`, round their value end from
  `--radius`, and take `labels`. Candles borrow `success`, `destructive` and
  `muted-foreground` for their sentiment. Over bars or candles `Chart.Tooltip.X`
  becomes a band one step wide. `PieChart` is a second root — `PieChart.Slice`,
  `.Label`, `.Center`, `.Tooltip` and `.Legend` — whose categories are its rows,
  with `innerRadius` for a donut and a tap-driven readout.

  Series colours now dedupe before the theme lookup, so twenty slices walking
  the five-token ramp resolve five tokens rather than throwing past the eighth.

  The CLI's chart registry item picks up the new files and names the new marks
  in its description.

- [#22](https://github.com/delacournz/delacour-ui/pull/22) Add charts: a headless Skia engine, and the `Chart` component that skins it

  **`@delacour/react-native-charts` is new** — a token-free charting engine for React Native,
  drawn with Skia, animated with Reanimated and driven by Gesture Handler. It
  ships `CartesianChart` with `Line`, `Area`, `Grid` and both axes, a scrub whose
  dot rides the drawn curve rather than hopping between data points, and path
  morphing that never falls back to snapping. `@delacour/react-native-charts/core` is every
  scale, tick, curve and solver in it, importable with no Skia in the module graph.

  **`@delacour/react-native-ui/chart`** is that engine wearing the theme. A shadcn-shaped
  `config` names each series and assigns `--chart-1` … `--chart-5` by position, so
  a call site writes `<Chart.Line yKey="revenue" />` and never a colour. Parts are
  placed rather than configured: `Chart.Grid`, `Chart.Line`, `Chart.Area`,
  `Chart.XAxis` and `Chart.YAxis` draw into the canvas, while `Chart.Tooltip` and
  `Chart.Legend` are React Native views layered over and under it.

  Also new: `--spacing-chart-sm/md/lg`, because a canvas has no intrinsic height
  and a dashboard's rows only line up if every chart agrees on one.

  **This needs a dev-client rebuild.** `@shopify/react-native-skia` is a native
  module and is new to the workspace — run `expo prebuild --clean` and rebuild
  before running the playground.

  The CLI learns two things: how to install a Skia-backed component, and that
  `@delacour/react-native-charts` publishes to the `alpha` tag while this repository is in pre
  mode, since a bare `bun add` of it would resolve `latest` and find nothing.
