@brrritscold/core-react 1.0.0 → 1.1.0
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 +27 -25
- package/dist/library.snapshot.json +21410 -0
- package/dist/styles.css +20 -6
- package/dist/tokens.json +41 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ The component library: shadcn (Base UI) React components on Tailwind v4, themed
|
|
|
4
4
|
|
|
5
5
|
**Storybook (the docs): https://brrritscold.github.io/ts-packages/core-react/** · run it locally with `pnpm storybook`. Spec: [`docs/design-system/SPEC.md` § D](https://github.com/bRRRITSCOLD/ts-packages/blob/main/docs/design-system/SPEC.md); terms: [`GLOSSARY.md`](https://github.com/bRRRITSCOLD/ts-packages/blob/main/docs/design-system/GLOSSARY.md).
|
|
6
6
|
|
|
7
|
-
**Every PR touching `src/` (stories aside), `tokens/tokens.json` or the `styles.css` build (`scripts/`) needs a changeset naming this package; CI fails without one.** Bumps: **minor** = new component, icon, variant value, optional prop or semantic token; **major** = renamed or removed prop, variant value, component, icon or token, or a changed default; **patch** = a token _value_ change, or a visual or behaviour fix with the same API. A major changeset has a `### Migration` section with exact before → after pairs and a pointer to the matching token migrations. Library-only changes with no published file (an annotation, a snapshot-only refresh) get none. There is no library version: the snapshot at tag `@brrritscold/core-react@x.y.z
|
|
7
|
+
**Every PR touching `src/` (stories aside), `tokens/tokens.json` or the `styles.css` build (`scripts/`) needs a changeset naming this package; CI fails without one.** Bumps: **minor** = new component, icon, variant value, optional prop or semantic token; **major** = renamed or removed prop, variant value, component, icon or token, or a changed default; **patch** = a token _value_ change, or a visual or behaviour fix with the same API. A major changeset has a `### Migration` section with exact before → after pairs and a pointer to the matching token migrations. Library-only changes with no published file (an annotation, a snapshot-only refresh) get none. There is no library version: the snapshot at tag `@brrritscold/core-react@x.y.z`, shipped in that release as `./library.snapshot.json`, is the library state that release matches. A snapshot-only refresh rides the next release.
|
|
8
8
|
|
|
9
9
|
## Using it
|
|
10
10
|
|
|
@@ -24,14 +24,15 @@ import { PlusIcon } from '@brrritscold/core-react/icons'
|
|
|
24
24
|
|
|
25
25
|
Dark mode is the `.dark` class on an ancestor; there is no theme provider.
|
|
26
26
|
|
|
27
|
-
| Subpath
|
|
28
|
-
|
|
|
29
|
-
| `.`
|
|
30
|
-
| `./icons`
|
|
31
|
-
| `./data-table`
|
|
32
|
-
| `./styles.css`
|
|
33
|
-
| `./tokens.json`
|
|
34
|
-
| `./
|
|
27
|
+
| Subpath | Holds |
|
|
28
|
+
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
29
|
+
| `.` | named component and part exports plus `cn`, from one pure barrel (`src/index.ts`) |
|
|
30
|
+
| `./icons` | every `lucide-react` export, one re-export per icon module; use the `<Name>Icon` aliases |
|
|
31
|
+
| `./data-table` | `useDataTable` (and its types): the one importer of `@tanstack/react-table`; see [Data table](#data-table) |
|
|
32
|
+
| `./styles.css` | the built theme: `@import "tailwindcss"`, its own `@source "./**/*.js"`, tokens, `@theme inline` |
|
|
33
|
+
| `./tokens.json` | the raw token file |
|
|
34
|
+
| `./library.snapshot.json` | the design system library snapshot this release matches (`design/library.snapshot.json`), for other renderers' drift checks |
|
|
35
|
+
| `./testing` | component objects for Playwright specs (`dialog(root)`, `toast(page)`, `toggleGroup(root)`, `accordion(root)`, `tabs(root)`, `dataTable(root)`, `calendar(root)`, `datePicker(trigger)`, …); `@playwright/test` is an optional peer |
|
|
35
36
|
|
|
36
37
|
## Where this package departs from the repo's package layout
|
|
37
38
|
|
|
@@ -40,9 +41,9 @@ Everything not listed here follows the shared layout (script names, strict pnpm
|
|
|
40
41
|
| The other packages | core-react | Why |
|
|
41
42
|
| -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
42
43
|
| tsup, dual ESM/CJS | **ESM only, unbundled**: `tsc -p tsconfig.build.json` emits one `.js` + `.d.ts` per source file; no `require` condition | each file keeps its own `"use client"` |
|
|
43
|
-
| `build` is `tsup` | `build` is Style Dictionary (`tokens/tokens.json` → `dist/styles.css`, `scripts/build-styles.ts`) → copy `tokens.json` to `dist/` → `tsc`
|
|
44
|
+
| `build` is `tsup` | `build` is Style Dictionary (`tokens/tokens.json` → `dist/styles.css`, `scripts/build-styles.ts`) → copy `tokens.json` and the library snapshot to `dist/` → `tsc` | the CSS and JSON exports are build output too |
|
|
44
45
|
| no `.` entry, no `index.ts` | `src/index.ts` is the `.` entry: named re-exports only, no logic, no `export *`. `scripts/check-entries.mjs` allowlists it and checks that | ESM and unbundled, so bundlers tree-shake it per component and Next's `optimizePackageImports` rewrites named imports from it |
|
|
45
|
-
| every export is JavaScript | `./styles.css` and `./
|
|
46
|
+
| every export is JavaScript | `./styles.css`, `./tokens.json` and `./library.snapshot.json` are plain files; `"sideEffects": ["*.css"]` | apps import the theme once and read raw tokens |
|
|
46
47
|
| typedoc site and generated README `## API` | **Storybook is the docs**; the root `typedoc.json` excludes this package and this README has no API section | a component's docs are its rendered variants |
|
|
47
48
|
| tiers `unit`, `integration`, `e2e` on `vitest.shared.ts` | own `vitest.config.ts`: `stories` (beside components in `src/`, excluded from the build) and `unit` on jsdom taking `.tsx`; `integration` is Playwright against a static Storybook build; no `e2e` | the story is the test; browser flows need real Playwright `Locator`s |
|
|
48
49
|
| siblings as `workspace:^` | devDeps `@brrritscold/design-core-js` and `design-core-node` as `workspace:*` | they are private, for the drift check, never published |
|
|
@@ -61,19 +62,19 @@ Scripts beyond the contract: `build:styles` (the token half of `build`), `drift:
|
|
|
61
62
|
- **`$type`s** follow Penpot's token types, so token sync writes them as they are: `color`, `spacing`, `sizing`, `borderRadius`, `fontFamilies`, `fontSizes`, `fontWeights`, `number` (line height), `letterSpacing`, `shadow`, `opacity`.
|
|
62
63
|
- **`styles.css`**: primitives and light semantics on `:root`, dark semantics on `.dark`, then the `@theme inline` block. It clears Tailwind's default scale for every token type and maps the tokens in their place, so a utility reads its token's variable (`p-4` → `var(--space-4)`) and changing a token changes every class that uses it:
|
|
63
64
|
|
|
64
|
-
| Token | Utilities
|
|
65
|
-
| ------------------ |
|
|
66
|
-
| colour semantics | `bg-primary`, `text-muted-foreground`, `border-input`, …
|
|
67
|
-
| `radius
|
|
68
|
-
| `space.*` | spacing and sizing: `p-4`, `gap-1.5`, `h-9`, `size-4`, `inset-x-4`
|
|
69
|
-
| `size.*` | `max-w-xs` … `max-w-2xl`
|
|
70
|
-
| `font-family.*` | `font-sans`, `font-mono`
|
|
71
|
-
| `font-size.*` | `text-xs` … `text-2xl` (font size only; line height comes from `leading-*`, inherited from `body`'s `leading-normal`)
|
|
72
|
-
| `font-weight.*` | `font-normal` … `font-bold`
|
|
73
|
-
| `line-height.*` | `leading-tight`, `leading-normal`, `leading-relaxed`
|
|
74
|
-
| `letter-spacing.*` | `tracking-tight`, `tracking-normal`, `tracking-wide`
|
|
75
|
-
| `shadow.*` | `shadow-xs`, `shadow-sm`
|
|
76
|
-
| `opacity.*` | `opacity-0`, `opacity-10`, `opacity-50`, `opacity-100`, and a colour's `/10` or `/50` modifier
|
|
65
|
+
| Token | Utilities |
|
|
66
|
+
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
67
|
+
| colour semantics | `bg-primary`, `text-muted-foreground`, `border-input`, … |
|
|
68
|
+
| `radius-*` | `rounded-xs` … `rounded-xl`, one semantic per step aliasing its `border-radius.*` primitive; `rounded-full` reads `border-radius.full`. `radius` itself stays for shadcn's `--radius` |
|
|
69
|
+
| `space.*` | spacing and sizing: `p-4`, `gap-1.5`, `h-9`, `size-4`, `inset-x-4` |
|
|
70
|
+
| `size.*` | `max-w-xs` … `max-w-2xl` |
|
|
71
|
+
| `font-family.*` | `font-sans`, `font-mono`. `sans` is Inter first: `styles.css` imports `@fontsource/inter` (pinned exactly) at 400, 500, 600 and 700, so apps get the font with no setup. An Inter bump is deliberate and matched by the other renderers |
|
|
72
|
+
| `font-size.*` | `text-xs` … `text-2xl` (font size only; line height comes from `leading-*`, inherited from `body`'s `leading-normal`) |
|
|
73
|
+
| `font-weight.*` | `font-normal` … `font-bold` |
|
|
74
|
+
| `line-height.*` | `leading-tight`, `leading-normal`, `leading-relaxed` |
|
|
75
|
+
| `letter-spacing.*` | `tracking-tight`, `tracking-normal`, `tracking-wide` |
|
|
76
|
+
| `shadow.*` | `shadow-xs`, `shadow-sm` |
|
|
77
|
+
| `opacity.*` | `opacity-0`, `opacity-10`, `opacity-50`, `opacity-100`, and a colour's `/10` or `/50` modifier |
|
|
77
78
|
|
|
78
79
|
A token already named as its theme variable (`--font-weight-medium`, `--shadow-xs`, `--opacity-50`) sits in a second `@theme inline reference` block, so Tailwind doesn't emit it again as a variable pointing at itself. Breakpoints, motion and z-index keep Tailwind's defaults. Font sizes are stored in px and emitted as rem; opacities are stored as fractions and emitted as percentages, the form a colour modifier's `color-mix()` takes. Style Dictionary fails the build on a broken reference.
|
|
79
80
|
|
|
@@ -99,7 +100,7 @@ Fixing a red check, lockstep PRs and promotion: the personal-ai `design-system`
|
|
|
99
100
|
|
|
100
101
|
Penpot can't say everything a class list says. The library twin keeps every checked attribute on a token and accepts these known differences:
|
|
101
102
|
|
|
102
|
-
-
|
|
103
|
+
- **Some corners still carry `radius`, not their step.** The `rounded-*` scale is the `radius-*` semantics in `tokens.json`, but library components built before those existed carry `radius` (10px) where the code uses `rounded-md` (8px) or another step. They move to the matching `radius-<step>` in [#116](https://github.com/bRRRITSCOLD/ts-packages/issues/116).
|
|
103
104
|
- **A colour at an opacity is a tint layer.** Applying a colour token resets the fill's opacity to 1, so Button `destructive`'s `bg-destructive/10` is an absolute `Tint` rectangle behind the label: fill `destructive`, layer opacity `opacity.10`. Penpot can't change an opacity by theme, so dark's `/20` stays at 10%.
|
|
104
105
|
- **`dark:` overrides that pick another semantic are dropped.** Button `outline`'s `dark:border-input dark:bg-input/30` stay `border` and `background`.
|
|
105
106
|
- **Hover and focus states have no variants**, and neither do the focus and `aria-invalid` rings (`ring-3 ring-*/20`). A state backed by a prop is a variant property named after it, with values `true` / `false`: Checkbox `checked` / `disabled` / `aria-invalid`, Switch `checked` / `disabled`, Input and Textarea `disabled` / `aria-invalid`. Button has none: it was built before the form controls.
|
|
@@ -125,6 +126,7 @@ Penpot can't say everything a class list says. The library twin keeps every chec
|
|
|
125
126
|
- **An icon's stroke stays 2px when resized.** lucide scales the stroke with the icon's size; Penpot scales the paths (constraints `scale`) but not the stroke width. A twin that resizes an icon copy sets the copy's stroke width by hand (Checkbox's 14px check: 2 × 14 / 24 ≈ 1.167).
|
|
126
127
|
- **An icon's dot is a filled circle.** lucide draws a dot (`Info`, `CircleExclamationPoint`) as a 0.01px path with round caps, which Penpot doesn't render; the twin uses a 2×2 ellipse with fill `foreground`, the same shape.
|
|
127
128
|
- **Library icons use lucide's canonical names, never aliases** (`CircleExclamationPoint`, not `CircleAlert`), so a lucide major that drops an alias doesn't break drift rule 4. Icon twins are built from `lucide-react`'s own icon data over MCP, so their geometry matches the installed version.
|
|
129
|
+
- **`lucide-react` is pinned exactly, and every Lucide bump is its own core-react release.** A Lucide release that only adds icons is a core-react minor; one that renames or removes an icon is a major. Other renderers (the GPUI library) vendor Lucide at the version this `package.json` names, so a range would let apps resolve a different icon set than the one released and checked against drift.
|
|
128
130
|
|
|
129
131
|
## Data table
|
|
130
132
|
|