@inkorange/space-ui 1.0.3 → 1.0.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.
Files changed (2) hide show
  1. package/README.md +134 -138
  2. package/package.json +6 -2
package/README.md CHANGED
@@ -1,204 +1,200 @@
1
- # SpaceUI
1
+ # SpaceUI: Dark interfaces with their own light source
2
2
 
3
- **Components for dark, instrument-dense interfaces.**
3
+ <!-- badges:start -->
4
4
 
5
- 24 React components and 20 icons on a seven-role token system, with zero
6
- runtime dependencies.
5
+ [![npm](https://img.shields.io/npm/v/@inkorange/space-ui)](https://www.npmjs.com/package/@inkorange/space-ui)
6
+ ![coverage](https://img.shields.io/badge/coverage-83%25-green)
7
+ ![minzip](https://img.shields.io/badge/minzip-22.1%20kB-blue)
8
+ ![dependencies](https://img.shields.io/badge/dependencies-0-blue)
9
+ [![docs](https://img.shields.io/badge/docs-live%20gallery-0b7dd6)](https://space-components.vercel.app)
7
10
 
8
- <!-- Absolute URLs on purpose: npm renders this file too, and relative paths
9
- resolve against the registry rather than the repository. -->
10
- <img alt="A lit-glass button, select, badges, slider, progress bar and folder tabs on a dark ground"
11
- src="https://raw.githubusercontent.com/inkorange/space-ui/main/.github/assets/components.svg"
12
- width="100%">
13
-
14
- 📖 **[Browse the gallery →](https://space-components.vercel.app)** — every
15
- component, its props, its tokens, and the source for each example.
11
+ <!-- badges:end -->
16
12
 
17
- <a href="https://space-components.vercel.app">
18
- <img alt="The SpaceUI documentation gallery: components, their props, tokens and source"
19
- src="https://raw.githubusercontent.com/inkorange/space-ui/main/.github/assets/doc-screen.jpg"
20
- width="100%">
21
- </a>
13
+ Lit glass. An orbiting rim. Faint starlight across a surface. Not a theme you
14
+ configure — the way these components look out of the box, with nothing to
15
+ compose and nothing to opt into.
22
16
 
23
- ## Install
17
+ <!-- Absolute URLs on purpose: npm renders this file too, and relative paths
18
+ resolve against the registry rather than the repository. This sheet is a
19
+ screenshot of the real components, shot from the gallery — see
20
+ `pnpm assets`. -->
21
+ <img alt="Stickersheet: Button, Badge, Select, TextField, Slider, Progress, IconToggle, RadioGroup, Loader, Tabs, icons, Text, TextArea, Card and ScrollArea on a dark ground"
22
+ src="https://raw.githubusercontent.com/inkorange/space-ui/main/.github/assets/components.jpg"
23
+ width="100%">
24
24
 
25
25
  ```bash
26
26
  pnpm add @inkorange/space-ui
27
27
  ```
28
28
 
29
29
  ```tsx
30
- // once, at your app entry — one import, defaults included
31
30
  import "@inkorange/space-ui/styles.css";
32
-
33
- import { Button, Card, Heading } from "@inkorange/space-ui";
31
+ import { Card, Heading, Text, Badge, Button } from "@inkorange/space-ui";
34
32
 
35
33
  export function Planet() {
36
34
  return (
37
35
  <Card>
38
- <Heading size="4">Kepler-442b</Heading>
36
+ <Heading size="5">Kepler-442b</Heading>
37
+ <Badge color="success">Temperate</Badge>
38
+ <Text size="2" color="muted">
39
+ A super-earth in the habitable zone, 1,206 light years out.
40
+ </Text>
39
41
  <Button>Build planet</Button>
40
42
  </Card>
41
43
  );
42
44
  }
43
45
  ```
44
46
 
45
- `styles.css` is the precompiled component CSS **with the default token values
46
- baked in**, so that single import gives you a working library. Plain CSS — no
47
- Sass, CSS modules, or framework tooling required downstream. All components are
48
- client components (`"use client"` is baked into the bundle).
47
+ That is the whole setup. Every component arrives already wearing the design.
49
48
 
50
- ### Theming is a one-file swap
49
+ ## The design language is the component
51
50
 
52
- Every component reads role-named tokens and nothing else, so a whole theme —
53
- light mode, a brand palette — is one `:root` block loaded *after* the library:
51
+ Most systems hand you primitives and a theme to paint them with. This one does
52
+ not separate the two. A `Button` is a lit-glass capsule whose rim catches light
53
+ like a planet's atmosphere; a `Slider` is a glass tube with a limb-lit moon you
54
+ drag along it. There is no plain mode, because a plain mode would be a
55
+ different library.
54
56
 
55
- ```css
56
- /* theme.css, imported after styles.css */
57
- :root {
58
- --sp-gray-panel: #ffffff;
59
- --sp-gray-text: #14161c;
60
- --sp-primary-solid: #7c5cff;
61
- --sp-font-family: "Inter", system-ui, sans-serif;
62
- }
63
- ```
57
+ What you *can* control is movement. Ambient motion suits a hero button and
58
+ distracts in a dense form, so one prop stills it — the look untouched, only the
59
+ loops stopped:
64
60
 
65
- Same specificity, later source order, so your values win. You only override
66
- what you want to change — anything you leave out keeps the shipped default.
67
- `@inkorange/space-ui/tokens.css` is exported separately if you want to read or
68
- extend the full default set.
61
+ ```tsx
62
+ <Button>Build planet</Button>
63
+ {/* rim orbits, stars twinkle */}
64
+ <Button animated={false}>Build planet</Button>
65
+ {/* same glass, held still */}
66
+ ```
69
67
 
70
- **Requirements:** React 19 as a peer dependency, and a dark surface —
71
- components are built for the space-dark ground (`#111113`) and assume it.
72
- There is no light theme.
68
+ Readers who ask for reduced motion get the stilled treatment automatically,
69
+ whatever the prop says.
73
70
 
74
- ## Four rules, enforced
71
+ ## Built for dense, dark UI
75
72
 
76
- Each of these is a constraint the build checks, not a preference the docs
77
- describe. That is the difference between a design system and a folder of
78
- components.
73
+ Forms, overlays and controls that hold up when there are a lot of them on
74
+ screen at once — the kind of interface where someone is adjusting values and
75
+ watching something respond.
79
76
 
80
- | Rule | What it means | Enforced by |
81
- | --- | --- | --- |
82
- | **Eight-point spacing** | Every gap, inset, and offset lands on the grid. Off-grid values round **up**, so density never creeps in by accident. | `12px → 16px` |
83
- | **Seven gray roles** | Grays are named for the job they do, not their step on a ramp. Fifteen Radix variants collapsed into seven roles. | `--sp-gray-text-dim` |
84
- | **No framework in the surface** | No Radix, no runtime dependencies, no framework-specific props. | `radixImports.test.ts` |
85
- | **CSS arrives precompiled** | Consumers import one stylesheet. Authored in Sass; nothing downstream needs a Sass toolchain. | `styles.css` |
77
+ ```tsx
78
+ <Select.Root value={star} onValueChange={setStar}>
79
+ <Select.Trigger />
80
+ <Select.Content>
81
+ {types.map((t) => (
82
+ <Select.Item key={t} value={t}>{t}-type star</Select.Item>
83
+ ))}
84
+ </Select.Content>
85
+ </Select.Root>
86
+ ```
86
87
 
87
- ## Design tokens
88
+ The small things are handled so you never have to notice them. That Select
89
+ sizes itself to its widest option, so it does not change width as you choose.
90
+ Dialogs ride the browser's own top layer, so focus trapping and Escape are the
91
+ platform's job rather than a library's approximation. Tabs connect to the panel
92
+ beneath them.
88
93
 
89
- Radix gave us fifteen numbered grays. A numbered ramp makes you guess — is
90
- `gray-11` a label, a border, or a placeholder? SpaceUI ships seven, each named
91
- for the work it does, so the name tells you where it belongs and a reviewer can
92
- tell when it is wrong. Set a role's value once and every correct use follows.
94
+ ## Make it yours — it's all CSS variables
93
95
 
94
- Tokens are plain CSS custom properties on `:root`. Nothing about them is
95
- React-specific.
96
+ No component holds a value of its own. Every colour, size and duration in the
97
+ library resolves through a **CSS custom property** in the `--sp-` namespace,
98
+ and the defaults ship inside `styles.css` — so retheming is a block of
99
+ variables you write, never a fork, a config file, or a build step.
96
100
 
97
- ```css
98
- @import "@inkorange/space-ui/tokens.css";
101
+ There are three tiers, from broadest to narrowest.
99
102
 
100
- .planet-panel {
101
- background: var(--sp-gray-panel);
102
- border: 1px solid var(--sp-gray-border);
103
- padding: var(--spacing-md); /* 16px — on the grid */
104
- gap: var(--spacing-sm);
105
- }
103
+ **Palette roles.** Named for the job the colour does, never the hue. Change one
104
+ and every component playing that role moves with it:
106
105
 
107
- .planet-panel__label {
108
- color: var(--sp-gray-text-dim); /* secondary text */
109
- font-size: var(--sp-font-sm);
106
+ ```css
107
+ :root {
108
+ --sp-primary-solid: #7c5cff; /* solid accent fill: badges, progress */
109
+ --sp-primary-text: #b9a6ff; /* accent text and links */
110
+ --sp-gray-panel: #14161c; /* card and panel fills */
111
+ --sp-gray-border: #d6ebfd30; /* hairlines and control borders */
112
+ --sp-danger-text: #ff9592; /* destructive, not "red" */
110
113
  }
111
114
  ```
112
115
 
113
- Because every component reads the same roles, rebranding is one block of
114
- overrides rather than a pass through the component tree:
116
+ **Surface channels.** The lit glass is built from layered translucency, so
117
+ those variables carry colour *channels* and let each layer pick its own alpha:
115
118
 
116
119
  ```css
117
- /* theme.css — loaded after tokens.css */
118
120
  :root {
119
- --sp-gray-panel: #14161c;
120
- --sp-primary-solid: #7c5cff;
121
- --sp-font-family: "Inter", system-ui, sans-serif;
121
+ --sp-rim-rgb: 190 160 255; /* the lit atmosphere limb */
122
+ --sp-glow-rgb: 150 130 255; /* hover and focus bloom */
123
+ --sp-glass-rgb: 18 14 34; /* the glass fill itself */
122
124
  }
123
125
  ```
124
126
 
125
- Every token, its resolved value, and the Radix variant it replaced is listed
126
- under **Foundations** in the gallery, along with a reverse index of which
127
- components read which token.
128
-
129
- ### Fonts
127
+ Inside the components these read as `rgb(var(--sp-rim-rgb) / 0.4)`, so give
128
+ them space-separated channels — a `#hex` or a full `rgb(...)` leaves the alpha
129
+ with nothing to work on.
130
130
 
131
- Almost nothing sets a `font-family` — the library inherits whatever your app
132
- already loaded, and nothing renders through a portal, so inheritance reaches
133
- every component. Two components pin a stack (`Badge` and `Button`), and
134
- both read the same token:
131
+ **Component properties.** Where one component needs a dial of its own it
132
+ exposes one, always named `--sp-[component]-[modifier]-[type]`:
135
133
 
136
134
  ```css
137
- :root { --sp-font-family: "Inter", system-ui, sans-serif; }
135
+ --sp-progress-height: 12px;
136
+ --sp-select-trigger-max-width: 24rem;
137
+ --sp-loader-moon-size: 10px;
138
138
  ```
139
139
 
140
- There is deliberately no per-component font hook. Typeface is a system-level
141
- decision made in one place, and a test fails the build if a component
142
- introduces its own.
140
+ Every component page in the gallery lists its own in a **Custom properties**
141
+ table, saying what each one changes.
143
142
 
144
- ## The look is not optional
143
+ Because these are ordinary CSS variables, they cascade. Declare them on `:root`
144
+ to theme the application, or on any element to retheme just that subtree —
145
+ a warmer palette inside one panel, a tighter control in one toolbar:
145
146
 
146
- Lit glass, an orbiting rim, faint starfield specks — that is what a SpaceUI
147
- component *is*. There is no plain mode and no class to compose: install the
148
- package and you get the system.
149
-
150
- What you can turn off is the **motion**, because ambient loops that suit a hero
151
- button distract in a dense form or a long list. One prop, one meaning:
152
-
153
- ```tsx
154
- <Button>Build planet</Button> {/* ambient motion, the default */}
155
- <Button animated={false}>Build planet</Button> {/* same look, no loops */}
156
-
157
- <TextField.Root animated={false} />
158
- <Select.Trigger animated={false} />
147
+ ```css
148
+ .launch-panel {
149
+ --sp-glass-rgb: 30 16 14;
150
+ --sp-rim-rgb: 255 180 130;
151
+ --sp-control-height: 32px;
152
+ }
159
153
  ```
160
154
 
161
- `animated={false}` stills the orbiting rim, the glint sweep and the twinkling
162
- stars. Every gradient, rim and shadow stays exactly where it was. Readers who
163
- set `prefers-reduced-motion` get this without asking — the library honours it
164
- whatever the prop says.
165
-
166
- `Slider` takes no `animated` prop: its skin has no ambient loop, and a prop
167
- that does nothing is worse than no prop.
155
+ You override only what you name, and everything you leave alone keeps its
156
+ shipped value. Supply no variables at all and the library still renders exactly
157
+ as it does in the gallery.
168
158
 
169
- ## Extracted, not invented
159
+ ## The components
170
160
 
171
- These components ran in production before they became a package, so they
172
- arrived with their edge cases already found rather than imagined. The
173
- extraction kept the rendered output identical — a few deliberate exceptions to
174
- the spacing grid survive where parity with the shipped app beat grid purity,
175
- and they are commented where they occur.
161
+ Every one of these has a live page in the gallery — the component running, the
162
+ source behind it, its full prop table with defaults, and the custom properties
163
+ it exposes.
176
164
 
165
+ | | |
166
+ | --- | --- |
167
+ | **Typography** | [Text](https://space-components.vercel.app/?story=components--typography--text-sizes) · [Link](https://space-components.vercel.app/?story=components--typography--text-sizes) · [Heading](https://space-components.vercel.app/?story=components--typography--headings) · [Badge](https://space-components.vercel.app/?story=components--typography--badges) · [Separator](https://space-components.vercel.app/?story=components--typography--separator) |
168
+ | **Layout** | [Card](https://space-components.vercel.app/?story=components--layout--card) · [Flex](https://space-components.vercel.app/?story=components--layout--flex-and-grid) · [Grid](https://space-components.vercel.app/?story=components--layout--flex-and-grid) · [Box](https://space-components.vercel.app/?story=components--layout--flex-and-grid) · [ScrollArea](https://space-components.vercel.app/?story=components--layout--scroll-area) |
169
+ | **Forms** | [TextField](https://space-components.vercel.app/?story=components--forms--text-field) · [TextArea](https://space-components.vercel.app/?story=components--forms--text-area) · [Select](https://space-components.vercel.app/?story=components--forms--select) · [Slider](https://space-components.vercel.app/?story=components--forms--slider) · [RadioGroup](https://space-components.vercel.app/?story=components--forms--radio-group) |
170
+ | **Buttons** | [Button](https://space-components.vercel.app/?story=components--buttons--buttons) · [IconToggle](https://space-components.vercel.app/?story=components--buttons--icon-toggle) |
171
+ | **Feedback** | [Loader](https://space-components.vercel.app/?story=components--buttons--loader) · [Progress](https://space-components.vercel.app/?story=components--buttons--progress) |
172
+ | **Overlays** | [Dialog](https://space-components.vercel.app/?story=components--overlays--dialog) · [AlertDialog](https://space-components.vercel.app/?story=components--overlays--alert-dialog) · [DropdownMenu](https://space-components.vercel.app/?story=components--overlays--dropdown-menu) · [Tabs](https://space-components.vercel.app/?story=components--overlays--tabs) · [Tooltip](https://space-components.vercel.app/?story=components--overlays--tooltip) |
173
+ | **Icons** | [20 icons](https://space-components.vercel.app/?story=components--icons--all-icons) |
174
+ | **Foundations** | [Color](https://space-components.vercel.app/?story=foundations--color) · [Spacing](https://space-components.vercel.app/?story=foundations--spacing) · [Type scale](https://space-components.vercel.app/?story=foundations--type-scale) · [Motion](https://space-components.vercel.app/?story=foundations--motion) · [Token usage](https://space-components.vercel.app/?story=foundations--token-usage) |
177
175
 
178
- ## Develop
176
+ <a href="https://space-components.vercel.app">
177
+ <img alt="The SpaceUI documentation gallery: components, their props, tokens and source"
178
+ src="https://raw.githubusercontent.com/inkorange/space-ui/main/.github/assets/doc-screen.jpg"
179
+ width="100%">
180
+ </a>
179
181
 
180
- ```bash
181
- pnpm install
182
- pnpm docs # Ladle gallery at localhost:61000
183
- pnpm test # 49 tests, incl. the Radix-ban and token-grid guards
184
- pnpm build
185
- ```
182
+ Start at **[space-components.vercel.app](https://space-components.vercel.app)** — the
183
+ introduction covers the token system and how to theme it, and every component
184
+ page shows the code you would actually write.
186
185
 
187
- The gallery runs against the library **source**, not `dist` — component edits
188
- hot-reload with no build step in the loop. Prop tables and token usage on the
189
- docs site are generated from the source at build time, so they cannot drift
190
- from what ships.
186
+ ## What you get
191
187
 
192
- ## Releases
188
+ **Zero runtime dependencies**, and about 22 kB over the wire gzipped — a 16 kB
189
+ ESM bundle and a 7 kB stylesheet. React 19, precompiled CSS, no build tooling
190
+ required downstream. Both numbers are measured from the build on every CI run,
191
+ so the badges above cannot drift.
193
192
 
194
- [Changesets](https://github.com/changesets/changesets): every PR that changes
195
- `packages/space-ui/src` adds one (`pnpm changeset`). Merging to main
196
- opens/updates a "Version Packages" PR; merging that publishes to npm and tags
197
- the release.
193
+ These ran in production before they became a package, so they arrived with
194
+ their edge cases already found rather than imagined.
198
195
 
199
- - **patch** — visual fix, internal refactor, docs
200
- - **minor** — new component, new prop, new export
201
- - **major** — removed/renamed export or prop, changed rendering default
196
+ **Requires** React 19 and a dark surface. There is deliberately no light theme;
197
+ these components assume the dark they were drawn for.
202
198
 
203
199
  ## License
204
200
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkorange/space-ui",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "SpaceUI — a space-themed React component library and design system",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -51,6 +51,7 @@
51
51
  "@types/react": "^19",
52
52
  "@types/react-dom": "^19",
53
53
  "@vitejs/plugin-react": "^4.6.0",
54
+ "@vitest/coverage-v8": "^3.2.7",
54
55
  "happy-dom": "^18.0.0",
55
56
  "react": "^19",
56
57
  "react-dom": "^19",
@@ -63,6 +64,9 @@
63
64
  "build": "vite build && tsc -p tsconfig.build.json --emitDeclarationOnly && cp src/styles/tokens.css dist/tokens.css",
64
65
  "test": "vitest run",
65
66
  "typecheck": "tsc --noEmit",
66
- "check:exports": "node scripts/check-exports.mjs"
67
+ "check:exports": "node scripts/check-exports.mjs",
68
+ "test:coverage": "vitest run --coverage",
69
+ "badges:write": "node scripts/badges.mjs --write",
70
+ "badges:check": "node scripts/badges.mjs --check"
67
71
  }
68
72
  }