alouette 19.0.0-beta.3 → 19.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  </h1>
4
4
 
5
5
  <p align="center">
6
- A modern, customizable design system built on top of Tamagui with configurable defaults
6
+ A modern, customizable design system built on top of NativeWind v5 with configurable defaults
7
7
  </p>
8
8
 
9
9
  <p align="center">
@@ -13,78 +13,196 @@
13
13
  <a href="https://npmjs.org/package/alouette"><img src="https://img.shields.io/npm/types/alouette.svg?style=flat-square" alt="types"></a>
14
14
  </p>
15
15
 
16
+ Alouette provides a comprehensive set of universal components that render on both
17
+ web and React Native, styled entirely through Tailwind `className` via
18
+ [NativeWind v5](https://www.nativewind.dev/). Themes, accents, and design tokens
19
+ ship as CSS custom properties that cascade through the tree, so components stay
20
+ declarative and consistent across platforms.
21
+
16
22
  ## 🚀 Getting Started
17
23
 
18
24
  ### Prerequisites
19
25
 
20
- - Node.js >= 20.9.0 (includes Corepack for package management)
26
+ - Node.js >= 22.18.0 (includes Corepack for package management)
27
+ - A React Native / Expo app using Metro, or a web app using NativeWind v5
21
28
 
22
29
  ### Installation
23
30
 
24
- 1. Enable Corepack (if not already enabled):
25
-
26
31
  ```bash
27
- corepack enable
32
+ npm install alouette
33
+ # or with yarn
34
+ yarn add alouette
28
35
  ```
29
36
 
30
- 2. Install the package:
37
+ `alouette-icons` is installed automatically as a dependency.
38
+
39
+ Install the peer dependencies if your app does not already provide them:
31
40
 
32
41
  ```bash
33
- npm install alouette
34
- # or with yarn
35
- yarn add alouette
42
+ npm install nativewind@5.0.0-preview.4 tailwindcss@^4 \
43
+ react-native-reanimated react-native-svg
36
44
  ```
37
45
 
38
- Note: `alouette-icons` is automatically included as a dependency.
46
+ `expo-web-browser`, `react-dom`, and `react-native-reanimated` are optional peers
47
+ — add them only if your target needs them (`react-dom` for web, `react-native-reanimated`
48
+ for native animations, `expo-web-browser` for `ExternalLink`).
39
49
 
40
50
  ### Configuration
41
51
 
42
- Create or update your `tamagui.config.ts`:
52
+ Alouette relies on NativeWind v5's Metro + PostCSS pipeline. NativeWind discovers
53
+ themes and utilities from the imported `global.css` and scans your sources via
54
+ `@source` directives — there is no JS config to maintain.
55
+
56
+ 1. **Metro** — wrap your config with the Alouette helper:
57
+
58
+ ```js
59
+ // metro.config.cjs
60
+ const { withAlouetteConfig } = require("alouette/metro");
61
+ const { getDefaultConfig } = require("expo/metro-config.js");
62
+
63
+ module.exports = withAlouetteConfig(getDefaultConfig(__dirname));
64
+ ```
65
+
66
+ 2. **CSS entry** — create a `global.css` that re-exports Alouette's tokens and
67
+ points `@source` at the directories NativeWind should scan for class names:
68
+
69
+ ```css
70
+ /* global.css */
71
+ @import "alouette/global.css";
72
+
73
+ @source './src'; /* your own className / tv() literals */
74
+ @source '../node_modules/alouette/src'; /* alouette's source — required */
75
+ ```
76
+
77
+ Tailwind only emits classes it finds while scanning `@source` paths, so both
78
+ your app's source **and** alouette's source must be covered or the matching
79
+ utilities are silently purged. In a monorepo where alouette is hoisted to the
80
+ repo root `node_modules`, adjust the depth (e.g.
81
+ `@source '../../../node_modules/alouette/src'`); a path that resolves to nothing
82
+ fails silently with no error.
83
+
84
+ Import it once at your app's entry point:
43
85
 
44
86
  ```ts
45
- import {
46
- createAlouetteTamagui,
47
- defaultColorScales,
48
- createAlouetteTokens,
49
- createAlouetteThemes,
50
- } from "alouette/createAlouetteTamagui";
87
+ import "./global.css";
88
+ ```
89
+
90
+ 3. **PostCSS** — NativeWind compiles Tailwind through PostCSS on both web and
91
+ native. `@tailwindcss/postcss` ships as a dependency of `alouette`, so you
92
+ only add the config file (use `.mjs` so it loads as ESM regardless of your
93
+ package's `"type"`):
94
+
95
+ ```js
96
+ // postcss.config.mjs
97
+ export default {
98
+ plugins: {
99
+ "@tailwindcss/postcss": {},
100
+ },
101
+ };
102
+ ```
103
+
104
+ 4. **Babel** — use the Expo preset and the Reanimated/worklets plugin:
105
+
106
+ ```js
107
+ // babel.config.js
108
+ export default function (api) {
109
+ api.cache(true);
110
+ return {
111
+ presets: [["babel-preset-expo", { reanimated: false }]],
112
+ plugins: ["react-native-worklets/plugin"],
113
+ };
114
+ }
115
+ ```
116
+
117
+ 5. **Provider** — wrap your app in `AlouetteProvider`. It applies the OS
118
+ light/dark scheme as the root theme so base tokens resolve app-wide:
119
+
120
+ ```tsx
121
+ import { AlouetteProvider } from "alouette";
51
122
 
52
- const tokens = createAlouetteTokens(defaultColorScales);
53
- const config = createAlouetteTamagui(tokens, createAlouetteThemes(tokens));
123
+ export function App() {
124
+ return <AlouetteProvider>{/* your app */}</AlouetteProvider>;
125
+ }
126
+ ```
54
127
 
55
- export default config;
128
+ 6. **Fonts** — Alouette's typography uses Sora (body/heading) and Chivo Mono
129
+ (mono). On native, load the weight-specific font files (the standalone
130
+ `font-weight` utility has no effect because each weight is a distinct file):
131
+
132
+ ```tsx
133
+ import {
134
+ Sora_400Regular as SoraRegular,
135
+ Sora_700Bold as SoraBold,
136
+ Sora_800ExtraBold as SoraExtraBold,
137
+ useFonts,
138
+ } from "@expo-google-fonts/sora";
139
+ import {
140
+ ChivoMono_400Regular as ChivoMonoRegular,
141
+ ChivoMono_700Bold as ChivoMonoBold,
142
+ ChivoMono_800ExtraBold as ChivoMonoExtraBold,
143
+ } from "@expo-google-fonts/chivo-mono";
144
+
145
+ const [fontsLoaded] = useFonts({
146
+ SoraRegular,
147
+ SoraBold,
148
+ SoraExtraBold,
149
+ ChivoMonoRegular,
150
+ ChivoMonoBold,
151
+ ChivoMonoExtraBold,
152
+ });
56
153
  ```
57
154
 
58
155
  ## 🎨 Core Features
59
156
 
60
157
  ### Components
61
158
 
62
- Alouette provides a comprehensive set of components following the atomic design pattern:
159
+ Alouette ships a universal component set styled through `className`:
63
160
 
64
- #### Actions
161
+ - **Actions** — `Button`, `ExternalLinkButton`, `InternalLinkButton`, `IconButton`
162
+ - **Containers** — `Box`, `InteractiveBox`, `SafeAreaBox`, `Surface`, `ScopedTheme`, `AccentScope`, `PresenceOne`, `PresenceList`
163
+ - **Inputs** — `InputText`, `TextArea`, `Switch`
164
+ - **Feedback** — `Message`, `InfoMessage`, `ConfirmationMessage`, `WarningMessage`
165
+ - **Data** — `PressableBox`, `PressableListItem`
166
+ - **Layout** — `GradientBackground`, `GradientScrollView`
167
+ - **Primitives** — `View`, `Text`, `Paragraph`, `Icon`, `ScrollView`, `Stack`, `HStack`, `VStack`, `Separator`
168
+ - **Responsive** — `SwitchBreakpointsUsingDisplayNone`, `SwitchBreakpointsUsingNull`, `useCurrentBreakpointName`
65
169
 
66
- - `Button`: brand interaction component with multiple variants
67
- - `IconButton`: Circular button optimized for icon display
170
+ For detailed examples and API documentation, visit our [Storybook](https://www.chromatic.com/library?appId=679f9e8df3edc5f07975b64a).
68
171
 
69
- #### Containers
172
+ ### Text styling
70
173
 
71
- - `Box`: Basic layout container with theme support
72
- - `PressableBox`: Interactive container with press states
174
+ `<Text>` has no variant props style it entirely via `className`. Family and
175
+ weight are combined into a single utility (`font-body`, `font-body-bold`,
176
+ `font-heading-extrabold`, `font-mono`, …); size uses standard Tailwind
177
+ `text-*`; color uses tokens like `text-sharp`, `text-muted`, `text-accent`.
73
178
 
74
- #### Forms
179
+ ```tsx
180
+ import { Text } from "alouette";
75
181
 
76
- - `InputText`: Text input with theming and state management
182
+ <Text className="text-base">Body</Text>;
183
+ <Text className="font-heading-extrabold text-4xl">Title</Text>;
184
+ <Text className="font-mono text-xs text-muted">Code</Text>;
185
+ ```
77
186
 
78
- #### Layout
187
+ ### Theming and accents
79
188
 
80
- - `Separator`: Visual divider with customizable orientation
81
- - `List`: Structured data display components
189
+ Themes are sets of CSS variables (`light`, `dark`, `light_brand`, `dark_info`, …)
190
+ applied by `ScopedTheme`. Child components use **base tokens** (`bg-surface`,
191
+ `text-accent`, `border-muted`, …) and inherit the correct values from the nearest
192
+ theme scope. Components that introduce an accent wrap their children in
193
+ `AccentScope`:
82
194
 
83
- For detailed examples and API documentation, visit our [Storybook](https://www.chromatic.com/library?appId=679f9e8df3edc5f07975b64a).
195
+ ```tsx
196
+ import { AccentScope, Surface } from "alouette";
197
+
198
+ <AccentScope accent="info">
199
+ <Surface>{/* children use base tokens */}</Surface>
200
+ </AccentScope>;
201
+ ```
84
202
 
85
203
  ### Icons
86
204
 
87
- Icons are provided through the integrated `alouette-icons` package:
205
+ Icons come from the integrated `alouette-icons` package:
88
206
 
89
207
  ```tsx
90
208
  import { ArrowLeftRegularIcon } from "alouette-icons/phosphor-icons/ArrowLeftRegularIcon";
@@ -94,24 +212,6 @@ function MyComponent() {
94
212
  }
95
213
  ```
96
214
 
97
- ## 🏗️ Architecture
98
-
99
- ### Core Principles
100
-
101
- 1. **Universal Design**: Components work seamlessly across web and native platforms
102
- 2. **Performance First**: Optimized bundle size and runtime performance through Tamagui
103
- 3. **Accessibility**: WCAG 2.1 compliant components with proper ARIA attributes
104
- 4. **Customization**: Flexible theming system with sensible defaults
105
- 5. **Type Safety**: Built with TypeScript for enhanced developer experience
106
-
107
- ### Technical Architecture
108
-
109
- - **Component Structure**: Atomic design pattern with atoms, molecules, and organisms
110
- - **Styling System**: Tamagui's compile-time styling with runtime fallbacks
111
- - **Theme System**: Token-based design system with support for light/dark modes
112
- - **Responsive Design**: Mobile-first approach with flexible breakpoint system
113
- - **Icon System**: Based on Phosphor Icons with optimized bundle size
114
-
115
215
  ## 🎯 Examples
116
216
 
117
217
  ### Basic Button
@@ -121,11 +221,7 @@ import { Button } from "alouette";
121
221
 
122
222
  function MyComponent() {
123
223
  return (
124
- <Button
125
- theme="brand"
126
- text="Click me"
127
- onPress={() => console.log("Clicked!")}
128
- />
224
+ <Button accent="brand" text="Click me" onPress={() => console.log("Clicked!")} />
129
225
  );
130
226
  }
131
227
  ```
@@ -137,15 +233,30 @@ import { Button } from "alouette";
137
233
  import { ArrowLeftRegularIcon } from "alouette-icons/phosphor-icons/ArrowLeftRegularIcon";
138
234
 
139
235
  function MyComponent() {
140
- return (
141
- <Button theme="brand" icon={<ArrowLeftRegularIcon />} text="Go Back" />
142
- );
236
+ return <Button accent="brand" icon={<ArrowLeftRegularIcon />} text="Go Back" />;
143
237
  }
144
238
  ```
145
239
 
146
- ## 📚 Documentation
240
+ ## 🤖 Using an AI agent?
241
+
242
+ Alouette ships [skills](https://www.npmjs.com/package/@tanstack/intent) that teach
243
+ AI coding agents how to use the design system correctly:
147
244
 
148
- For more examples and detailed documentation:
245
+ ```bash
246
+ npx @tanstack/intent@latest install
247
+ ```
248
+
249
+ ## 🏗️ Architecture
250
+
251
+ - **Universal Design** — components render across web and native from one API
252
+ - **NativeWind v5 styling** — Tailwind `className`; animations are CSS
253
+ `@keyframes` + `--animate-*` tokens, run on native via Reanimated
254
+ - **Token-based theming** — CSS custom properties cascade through `ScopedTheme`;
255
+ light/dark + accent scopes
256
+ - **Accessibility** — proper ARIA / accessibility attributes
257
+ - **Type Safety** — built with TypeScript
258
+
259
+ ## 📚 Documentation
149
260
 
150
261
  - [Component Documentation](https://www.chromatic.com/library?appId=679f9e8df3edc5f07975b64a)
151
262
  - [GitHub Repository](https://github.com/christophehurpeau/alouette)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alouette",
3
- "version": "19.0.0-beta.3",
4
- "description": "A modern, customizable design system built on top of Tamagui with configurable defaults",
3
+ "version": "19.0.0-beta.4",
4
+ "description": "A modern, customizable design system built on top of NativeWind v5 with configurable defaults",
5
5
  "keywords": [
6
6
  "tanstack-intent"
7
7
  ],
@@ -123,6 +123,7 @@
123
123
  }
124
124
  },
125
125
  "dependencies": {
126
+ "@tailwindcss/postcss": "4.3.1",
126
127
  "alouette-icons": "8.0.7",
127
128
  "expo-web-browser": "~15.0.10",
128
129
  "react-native-safe-area-context": "5.6.2",
@@ -8,9 +8,10 @@ description: >
8
8
  fonts/bold weights look wrong. Covers ios, android and web.
9
9
  type: lifecycle
10
10
  library: alouette
11
- library_version: "19.0.0-beta.1"
11
+ library_version: "19.0.0-beta.3"
12
12
  sources:
13
13
  - "christophehurpeau/alouette:packages/storybook-native-app/metro.config.cjs"
14
+ - "christophehurpeau/alouette:packages/storybook-native-app/postcss.config.mjs"
14
15
  - "christophehurpeau/alouette:packages/storybook-native-app/src/global.css"
15
16
  - "christophehurpeau/alouette:packages/storybook-native-app/src/App.tsx"
16
17
  - "christophehurpeau/alouette:packages/alouette/src/core/AlouetteProvider.tsx"
@@ -19,10 +20,10 @@ sources:
19
20
 
20
21
  # alouette — Setup
21
22
 
22
- alouette is styled with NativeWind v5 / Tailwind CSS v4. An app needs four
23
- things wired before any component renders correctly: the metro plugin, the CSS
24
- entry with source globs, the provider, and the fonts. Everything targets
25
- ios/android/web from the same code.
23
+ alouette is styled with NativeWind v5 / Tailwind CSS v4. An app needs five
24
+ things wired before any component renders correctly: the metro plugin, the
25
+ PostCSS config, the CSS entry with source globs, the provider, and the fonts.
26
+ Everything targets ios/android/web from the same code.
26
27
 
27
28
  ## Setup
28
29
 
@@ -37,14 +38,39 @@ const config = getDefaultConfig(__dirname);
37
38
  module.exports = withAlouetteConfig(config);
38
39
  ```
39
40
 
40
- `src/global.css` (imported once, at the app entry):
41
+ `postcss.config.mjs` at the **app package root** — this is what actually runs
42
+ Tailwind. `@tailwindcss/postcss` ships as a dependency of `alouette`, so apps do
43
+ not install it; they only add this config file:
44
+
45
+ ```js
46
+ export default { plugins: { "@tailwindcss/postcss": {} } };
47
+ ```
48
+
49
+ Use the `.mjs` extension so it loads as ESM regardless of the package's `"type"`
50
+ field.
51
+
52
+ `src/global.css` (imported once, at the app entry). Add an `@source` for
53
+ **alouette's source** and one for **your own app source** — both are scanned
54
+ independently of the JS bundle, and anything not covered is purged:
41
55
 
42
56
  ```css
43
57
  @import "alouette/global.css";
44
58
 
45
- @source "../node_modules/alouette/src";
59
+ @source "./**/*.{ts,tsx}"; /* the app's own className / tv() literals */
60
+ @source "../node_modules/alouette/src/**/*.{ts,tsx,js}"; /* alouette source */
46
61
  ```
47
62
 
63
+ In a monorepo where alouette is hoisted to the **repo root** `node_modules`
64
+ (Yarn `node-modules` linker, pnpm hoisted, etc.), the path resolves from the
65
+ repo root, not the app — adjust the depth accordingly:
66
+
67
+ ```css
68
+ @source "../../../node_modules/alouette/src/**/*.{ts,tsx,js}";
69
+ ```
70
+
71
+ A wrong glob matches zero files and fails **silently** (no error) — utilities
72
+ are simply purged and components render unstyled.
73
+
48
74
  App entry — load fonts (native), then wrap the tree in `AlouetteProvider`:
49
75
 
50
76
  ```tsx
@@ -136,9 +162,31 @@ Append `&family=Chivo+Mono:wght@400;700;800` to the URL if you use `font-mono`.
136
162
 
137
163
  ## Common Mistakes
138
164
 
139
- ### CRITICAL global.css missing @source for alouette source
165
+ ### CRITICAL Missing postcss.config Tailwind never runs
140
166
 
141
- Wrong:
167
+ Symptom: components render unstyled (only alouette's hotpink `body` fallback
168
+ shows), and the build logs spam `Warning: Unknown at rule: @utility` /
169
+ `@source` / `@theme`. Those warnings are the diagnostic signature — Tailwind
170
+ directives are reaching lightningcss un-expanded because Tailwind never ran.
171
+
172
+ Mechanism: `withAlouetteConfig` → `withNativewind` delegates CSS compilation to
173
+ Expo's Metro transform worker, which runs Tailwind **only if it finds a
174
+ `postcss.config` file at the project root**. Absent → CSS passes straight to
175
+ lightningcss verbatim and zero utilities are emitted.
176
+
177
+ Fix — add `postcss.config.mjs` at the app package root:
178
+
179
+ ```js
180
+ export default { plugins: { "@tailwindcss/postcss": {} } };
181
+ ```
182
+
183
+ `@tailwindcss/postcss` is a dependency of `alouette`, so no install is needed.
184
+
185
+ Source: packages/storybook-native-app/postcss.config.mjs
186
+
187
+ ### CRITICAL global.css missing @source, or wrong path in a monorepo
188
+
189
+ Wrong (no `@source`, or a path that resolves to nothing):
142
190
 
143
191
  ```css
144
192
  @import "alouette/global.css";
@@ -149,12 +197,25 @@ Correct:
149
197
  ```css
150
198
  @import "alouette/global.css";
151
199
 
152
- @source "../node_modules/alouette/src";
200
+ @source "./**/*.{ts,tsx}"; /* the app's own classes */
201
+ @source "../node_modules/alouette/src/**/*.{ts,tsx,js}"; /* alouette source */
153
202
  ```
154
203
 
155
- Tailwind v4 only emits classes it finds in scanned files. Without an `@source`
156
- covering alouette's source, every alouette utility class is purged and
157
- components render unstyled.
204
+ Tailwind v4 only emits classes it finds in scanned files. Two failure modes,
205
+ both producing the same silent unstyled result with **no error**:
206
+
207
+ 1. No `@source` for alouette's source → every alouette utility is purged.
208
+ 2. No `@source` for the app's own source → the app's own classes (e.g.
209
+ arbitrary values like `from-[#f39c12]`, `bg-linear-to-t`) are purged while
210
+ alouette's still work — easy to misdiagnose.
211
+ 3. In a monorepo where alouette is hoisted to the **repo root**
212
+ `node_modules`, `../node_modules/alouette/src` resolves to nothing. Use the
213
+ correct depth, e.g. `@source "../../../node_modules/alouette/src/**/*.{ts,tsx,js}"`.
214
+
215
+ Note: `@source` is a text-scan of alouette's shipped `src/*.tsx` (the verbatim
216
+ `className` / `tv()` string literals) — independent of the JS bundle, which
217
+ Metro resolves to the compiled `dist`. The two pipelines are decoupled, which is
218
+ why the scan targets `src` and not the build output.
158
219
 
159
220
  Source: packages/storybook-native-app/src/global.css
160
221
 
package/src/global.css CHANGED
@@ -616,6 +616,12 @@
616
616
 
617
617
  /* let height/width keyframes interpolate to/from auto (collapse-in/out) on web */
618
618
  :root { interpolate-size: allow-keywords; }
619
+
620
+ body, #root {
621
+ display: flex;
622
+ flex-direction: column;
623
+ min-height: 100vh;
624
+ }
619
625
  }
620
626
 
621
627
  /* keyframes referenced by the --animate-* theme tokens above. */