# alouette 23

Breaking changes of 23.0.0. Run the 22.x codemod first ([22.md](22.md)).

## To 23.0.0

The button material is reworked. The default is now `tonal`: a ground lighter
than the page, a pale tone of the accent in light mode, with the accent carried
by the label's ink (`text-on-tonal`). The old accent-filled `contained` button
becomes `filled`, and is flat (no shadow). The secondary action beside a
primary one is `accent="neutral" variant="soft"`: a neutral text button.

### Custom palette: regenerate it

If the app ships its own palette (`writeTheme` / `generateTheme` from
`alouette/theme-generator`), rerun its build script. The interactive tokens are
renamed (see [Color tokens](#color-tokens)), so a palette generated by 22.x has
no ground for any button. Apps on alouette's default palette have nothing to do.

### Variants

| Component                                                                                               | Before                     | After                                                              |
| ------------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------ |
| `Button`, `ActionButton`, `ExternalLinkButton`, `InternalLinkButton`, `AppHeaderSignIn`, `PressableBox` | `variant="contained"`      | `variant="filled"` to keep the accent fill, or nothing for `tonal` |
|                                                                                                         | `variant="ghost"`          | `variant="soft"`                                                   |
|                                                                                                         | no `variant` (contained)   | no `variant` (now `tonal`)                                         |
|                                                                                                         | `variant="list"`           | nothing (`tonal`)                                                  |
| `IconButton`                                                                                            | `variant="contained"`      | `variant="filled"`, or nothing for `tonal`                         |
|                                                                                                         | no `variant` (contained)   | no `variant` (now `tonal`)                                         |
|                                                                                                         | `variant="list"`           | nothing (`tonal`)                                                  |
|                                                                                                         | `variant="outlined"`       | `variant="soft"`                                                   |
|                                                                                                         | `variant="ghost"`          | `variant="soft"`                                                   |
| `PressableListItem`                                                                                     | `variant="list"` (default) | `variant="tonal"` (the default)                                    |
|                                                                                                         | `variant="contained"`      | `variant="filled"`                                                 |
|                                                                                                         | `variant="ghost"`          | nothing (`tonal`) or `variant="outlined"`                          |
| `EditableItem` `variant`, `EditableSection` `editIconVariant`                                           | any `IconButton` variant   | the `IconButton` mapping above                                     |
| `RadioCardGroup`, `CheckboxCardGroup`                                                                   | `variant="contained"`      | `variant="tonal"` (the default)                                    |

`outlined` and `soft` are unchanged on `Button` and `PressableBox`, but a `soft`
`Button` is now a text button: its label is `text-accent` and underlined.

Do not map every `contained` to `filled`. `filled` is for the one action that
must dominate; everything else takes the `tonal` default. The secondary action
of a pair (Cancel, Dismiss, Discard) is `accent="neutral" variant="soft"`, not
`accent="neutral"` alone: a neutral `tonal` button keeps its ground and shadow,
so the pair reads as two equal choices, and on a white `bg-highlight` ground (a
`Modal` footer, the `AppHeader` bar) that ground is the same white and
dissolves.

```tsx
// A pair: the primary on the default, the secondary neutral and soft
<Button accent="neutral" variant="soft" text="Cancel" onPress={close} />
<Button text="Save" onPress={save} />

// The one action that must dominate: filled; the other stays neutral and soft
<Button accent="neutral" variant="soft" text="Dismiss" onPress={close} />
<Button variant="filled" text="Save and close" onPress={saveAndClose} />
```

alouette's own footers (`AlertDialog`, `useFormEditorModal`) and the header
"Sign up" now do this.

**An accented surface** (`<Box accent="…" className="surface">`, a
`GradientBackground`) needs a change too: an accented `tonal` ground is the
surface's own color in light mode and dissolves. Make a lone button there
`accent="neutral"`, and the accented action `variant="filled"` or
`variant="soft"`. On web, outside production, `PressableBox` logs
`[Alouette] A tonal pressable rests on its own ground` when this happens.

### Removed and renamed components

| Before                                       | After                                                                 |
| -------------------------------------------- | --------------------------------------------------------------------- |
| `CheckboxButtonGroup` + `CheckboxButton`     | `CheckboxGroup` + `Checkbox`, or `CheckboxCardGroup` + `CheckboxCard` |
| `AppHeaderNav` / `AppHeaderNavProps`         | `HeaderNav` / `HeaderNavProps`                                        |
| `AppHeaderNavItem` / `AppHeaderNavItemProps` | `HeaderNavItem` / `HeaderNavItemProps`                                |

`HeaderNav` and `HeaderNavItem` take the same props as before; only the names
change.

### Deprecated components removed

The aliases deprecated in 22.x are gone. Migrate with the codemod before
upgrading (see
[22.md](22.md)
for the full mapping and its warnings):

```sh
npx alouette-codemod surface-and-stacks src
```

| Before                                               | After                                                                    |
| ---------------------------------------------------- | ------------------------------------------------------------------------ |
| `VStack` / `VStackProps`                             | `<View>` / `ViewProps`                                                   |
| `HStack` / `HStackProps`                             | `<View className="flex-row">` / `ViewProps`                              |
| `Stack` / `StackProps`                               | `<View className="flex-row flex-wrap">` / `ViewProps`                    |
| `Surface` / `SurfaceProps`                           | `<Box className="surface">` / `BoxProps`                                 |
| `<EditableSurface>` / `EditableSurfaceProps`         | `<EditableSection className="surface">` / `EditableSectionProps`         |
| `<FormEditableSurface>` / `FormEditableSurfaceProps` | `<FormEditableSection className="surface">` / `FormEditableSectionProps` |

### Color tokens

Only relevant if the app writes these classes itself:

| Before                                                   | After                                                 |
| -------------------------------------------------------- | ----------------------------------------------------- |
| `*-interactive-contained-{pressable,hover,focus,active}` | `*-interactive-filled-{pressable,hover,focus,active}` |
| `*-interactive-contained-disabled`                       | `*-interactive-filled-disabled`                       |
| `*-interactive-list-{pressable,hover,focus,active}`      | `*-interactive-tonal-{pressable,hover,focus,active}`  |
| `text-on-list`                                           | `text-on-tonal`                                       |

New: `interactive-tonal-disabled`, and the shadow layer colors
(`shadow-highlight`, `dark-shadow`, `soft-shadow`, `shadow-lowered-dark`,
`shadow-lowered-highlight`, `bar-dark-shadow`, `bar-soft-shadow`), which
`shadow-s` / `-m` / `-l` / `-lowered` / `-bar` now read so that dark mode can
deepen them.

Some values change. In the neutral theme, the `filled` ground and `enabled` are
the sharp ink as a ground: near black in light mode, near white in dark mode,
where `text-on-accent` turns dark and `text-on-accent-muted` moves with it.
`enabled` moves one step on colored accents. Accented `emphasis` (dark mode),
`highlight-accent` (light mode), `disabled-sharp` and `disabled-muted` (dark
mode) move by one or two steps.

### Changed appearance

No code change is needed. Review these screens:

- `Avatar` is `bg-emphasis` + `text-on-emphasis` instead of `bg-enabled` +
  `text-on-accent`. `<Avatar variant="enabled">` restores the old fill.
- `Badge` `solid` is `bg-emphasis` + `text-on-emphasis` instead of
  `bg-highlight-accent` + `text-sharp`. `outlined` gains a `bg-highlight-accent`
  ground. `solid` and `solid.enabled` gain a 1px border in their fill color, so
  they are 2px larger, the size of `outlined`. `Badge` also accepts
  `accent="neutral"`.
- `AlertDialog` (confirm variant): Cancel is neutral `soft` and confirm is
  accented `tonal`. The new `primaryAction="cancel"` gives a neutral `filled`
  Cancel and a `soft` confirm, for an irreversible action where backing out is
  the expected answer.
- The close button of `Modal`, the dismiss of `Message` and the remove button of
  `FormFieldArray` are `soft`.
- `EditableSection` with an `accent` defaults its edit button to `soft`.
- `Radio` and `Checkbox` rows take a `soft` fill on hover, focus and press.
- `Message` and `Bullet` set `text-base` on their text. `Bullet` centers its icon
  on the first line.
- `StableAccentScope` with a `mode` and no `accent` now re-applies the inherited
  accent in that mode. It used to keep the inherited theme as it was, ignoring
  `mode`. `PortalAccentScope` takes the same `mode` prop.
