22
33Reusable React components by Early Bird, built with TypeScript and CSS Modules.
44
5- > [ !WARNING]
6- > ** Status: Alpha.** The component library is under active development. Component APIs, styling,
7- > and design tokens may change before 1.0.
5+ > [ !NOTE]
6+ > ** Status: Beta.** The public API is stabilizing. Breaking changes are still possible before 1.0,
7+ > but they will be called out in the changelog rather than shipped silently.
8+
9+ ## Requirements
10+
11+ - ** React** 19.2 or later (React 19 only).
12+ - ** ESM only.** The package ships no CommonJS build.
13+ - ** Browsers:** the current and previous release of Chrome, Edge, Firefox, and Safari. The styles
14+ rely on ` color-mix() ` and CSS custom properties, so browsers without them are unsupported.
15+ - ** Accessibility target:** WCAG 2.2 Level AA. Interactive controls meet the 3:1 non-text contrast
16+ and 24×24px target-size minimums, and chart series meet 3:1 in distinct lightness tiers. Charts
17+ still separate series by color and legend rather than by shape or dash pattern, so keep the
18+ legend visible and do not rely on color as the sole cue in your own labeling.
819
920## Install
1021
@@ -31,7 +42,6 @@ pnpm add @fontsource-variable/karla
3142``` tsx
3243import " @fontsource-variable/karla" ;
3344import {
34- BarChart ,
3545 Button ,
3646 ButtonIcon ,
3747 Checkbox ,
@@ -49,12 +59,10 @@ import {
4959 InputAction ,
5060 InputGroup ,
5161 InputIcon ,
52- LineChart ,
5362 Menu ,
5463 MenuContent ,
5564 MenuItem ,
5665 MenuTrigger ,
57- PieChart ,
5866 Radio ,
5967 RadioGroup ,
6068 Select ,
@@ -175,6 +183,18 @@ adornments need to sit beside it. `SelectLeadingIcon` and
175183` ComboboxLeadingIcon ` provide the same leading-icon composition for selection
176184controls. ` Textarea ` extends the native textarea props.
177185
186+ ` CardTitle ` renders an ` h2 ` by default. Set ` as ` to the heading level that fits the
187+ surrounding document outline so cards do not break the page's heading order:
188+
189+ ``` tsx
190+ <Card >
191+ <CardHeader >
192+ <CardTitle as = " h3" >Recent activity</CardTitle >
193+ </CardHeader >
194+ <CardContent >...</CardContent >
195+ </Card >
196+ ```
197+
178198## Overlays
179199
180200Dialog and Drawer include themed backdrops, surfaces, titles, descriptions, triggers,
@@ -227,8 +247,40 @@ the shared tokens can import the standalone entry:
227247```
228248
229249` @byearlybird/components/style.css ` already includes these tokens, so apps using the
230- components should import only the component stylesheet. The standalone token entry
231- contains the public theme values and the Pollen primitives used by the library.
250+ components should import only the component stylesheet.
251+
252+ Every custom property the library defines is prefixed ` --eb- ` and every one of them is
253+ supported public API. Read them, compose them in ` calc() ` , or override them — they are
254+ meant to be built on, not just themed. Because the library declares them at
255+ ` :where(:root) ` , an application's own ` :root ` rule always wins without specificity tricks.
256+
257+ ``` css
258+ .my-toolbar {
259+ gap : var (--eb-size-2 );
260+ padding : var (--eb-size-3 ) var (--eb-size-4 );
261+ font-size : var (--eb-font-size-body );
262+ border-block-end : var (--eb-border-width ) solid var (--eb-color-border );
263+ }
264+ ```
265+
266+ ### The token contract
267+
268+ | Group | Tokens |
269+ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
270+ | Layout | ` --eb-border-width ` , ` --eb-size-1 ` … ` --eb-size-10 ` (each step is 4px) |
271+ | Typography | ` --eb-font-family ` , ` --eb-font-size-body ` , ` --eb-font-size-title ` , ` --eb-font-weight-regular ` , ` --eb-font-weight-semibold ` , ` --eb-line-height-none ` , ` --eb-line-height-normal ` |
272+ | Color | ` --eb-color-primary ` , ` --eb-color-primary-text ` , ` --eb-color-background ` , ` --eb-color-text ` , ` --eb-color-text-muted ` , ` --eb-color-border ` , ` --eb-color-muted ` , ` --eb-color-danger ` , ` --eb-color-scrim ` |
273+ | Charts | ` --eb-chart-series-1 ` , ` --eb-chart-series-2 ` , ` --eb-chart-series-3 ` |
274+ | Shape | ` --eb-radius-surface ` , ` --eb-radius-input ` , ` --eb-radius-button ` |
275+ | Elevation | ` --eb-shadow-raised-content ` , ` --eb-shadow-elevated-content ` |
276+ | Motion | ` --eb-motion-duration ` , ` --eb-motion-easing-standard ` , ` --eb-motion-easing-out ` |
277+
278+ ** Compatibility policy.** Adding a token is a minor release. Renaming or removing one, or
279+ changing what it means, is a breaking change and will appear in the changelog. Adjusting a
280+ token's _ value_ — a shade, a duration — is a minor release, so pin the value yourself if
281+ your design depends on an exact number. The set is enforced by ` tests/tokens.test.ts ` ,
282+ which fails the build if a token is dropped, renamed, or added without being documented
283+ here.
232284
233285``` css
234286:root {
@@ -237,8 +289,10 @@ contains the public theme values and the Pollen primitives used by the library.
237289 --eb-color-background : #faf9f6 ;
238290 --eb-color-text : #252523 ;
239291 --eb-color-text-muted : color-mix(in srgb , var (--eb-color-text ) 65% , transparent );
240- --eb-color-border : #b8b5ad ;
292+ --eb-color-border : #939088 ;
241293 --eb-color-muted : #e3e1da ;
294+ --eb-color-danger : #b91c1c ;
295+ --eb-color-scrim : #000 ;
242296 --eb-font-family : " Karla Variable" , " Karla" , ui-sans-serif , system-ui , sans-serif ;
243297 --eb-radius-surface : 2px ;
244298 --eb-radius-input : 9999px ;
@@ -249,11 +303,22 @@ contains the public theme values and the Pollen primitives used by the library.
249303}
250304```
251305
306+ Use ` --eb-color-danger ` for error and destructive states; it is the border color the
307+ Input and Textarea error styles already use. ` --eb-color-scrim ` is the base color for
308+ modal backdrops and is intentionally black in both themes — compose it with ` color-mix() `
309+ rather than overriding it to a theme color.
310+
252311Use ` --eb-color-text-muted ` for secondary content such as timestamps,
253312metadata, and supporting icons. It derives a translucent color from the active
254313text color, so it follows both light and dark themes while preserving the color
255314of the surface beneath it. Use ` --eb-color-muted ` for muted surfaces instead.
256315
316+ > [ !IMPORTANT]
317+ > Because ` --eb-color-text-muted ` is translucent, its contrast depends on whatever sits
318+ > behind it. Against the default background it measures 4.77:1 in light mode and 5.89:1
319+ > in dark mode. If you override ` --eb-color-text ` or ` --eb-color-background ` , or place
320+ > muted text on a ` --eb-color-muted ` surface, re-check it against the 4.5:1 minimum.
321+
257322The standard motion duration is the default for control feedback, visual-state
258323changes, and larger surface or shape transitions. Pair it with the standard easing
259324for general state changes, or use the out easing when movement or expansion should
@@ -296,9 +361,17 @@ tricks.
296361
297362## Charts
298363
364+ Charts ship from a separate entry so applications that do not render charts never pull
365+ Recharts into their bundle:
366+
367+ ``` tsx
368+ import { BarChart , LineChart , PieChart } from " @byearlybird/components/charts" ;
369+ ```
370+
299371The library includes opinionated line, bar, and pie charts powered by Recharts. Each chart
300372is responsive, supports light and dark themes, and uses the existing component color
301- tokens by default.
373+ tokens by default. ` @byearlybird/components/style.css ` covers both entries, so there is no
374+ separate chart stylesheet to import.
302375
303376``` tsx
304377const data = [
@@ -338,8 +411,27 @@ const data = [
338411/>;
339412```
340413
341- Set a series ` color ` or pass a ` colors ` array to ` PieChart ` when a product-specific
342- palette is needed. CSS color values, including application theme variables, are
414+ Series are colored from ` --eb-chart-series-1 ` through ` --eb-chart-series-3 ` , cycling if a
415+ chart has more series than that. Each one meets the 3:1 non-text contrast minimum against
416+ the default background in both themes, and the three sit in distinct lightness tiers so
417+ they stay separable in grayscale and for red-green color vision deficiency.
418+
419+ Override them to match a product palette:
420+
421+ ``` css
422+ :root {
423+ --eb-chart-series-1 : #1d4ed8 ;
424+ --eb-chart-series-2 : #0e7490 ;
425+ --eb-chart-series-3 : #b45309 ;
426+ }
427+ ```
428+
429+ If you do, keep each color at 3:1 or better against your chart background and vary
430+ lightness as well as hue — a palette that differs only by hue collapses for a
431+ meaningful share of users.
432+
433+ Set a series ` color ` or pass a ` colors ` array to ` PieChart ` when a single chart needs to
434+ depart from the palette. CSS color values, including application theme variables, are
343435supported.
344436
345437## Develop
@@ -367,11 +459,13 @@ The package build is written to `dist/`, and the static Storybook site is writte
367459
368460## Publish
369461
370- Authenticate with npm, choose a new version, then publish:
462+ Authenticate with npm, choose a new version, then publish under the ` beta ` dist-tag so
463+ prereleases never become ` latest ` :
371464
372465``` bash
373466vp dlx bumpp
374- pnpm publish
467+ pnpm publish --tag beta
375468```
376469
377- The package is configured for public scoped publishing.
470+ The package is configured for public scoped publishing. CI runs ` vp check ` , ` vp test ` ,
471+ and the workspace build on every push and pull request; publishing stays manual.
0 commit comments