@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.
- package/README.md +134 -138
- 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
|
-
|
|
3
|
+
<!-- badges:start -->
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@inkorange/space-ui)
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
[](https://space-components.vercel.app)
|
|
7
10
|
|
|
8
|
-
<!--
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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="
|
|
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
|
-
|
|
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
|
-
|
|
49
|
+
## The design language is the component
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
:
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
71
|
-
|
|
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
|
-
##
|
|
71
|
+
## Built for dense, dark UI
|
|
75
72
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
95
|
-
|
|
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
|
-
|
|
98
|
-
@import "@inkorange/space-ui/tokens.css";
|
|
101
|
+
There are three tiers, from broadest to narrowest.
|
|
99
102
|
|
|
100
|
-
.
|
|
101
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
114
|
-
|
|
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-
|
|
120
|
-
--sp-
|
|
121
|
-
--sp-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
132
|
-
|
|
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
|
-
|
|
135
|
+
--sp-progress-height: 12px;
|
|
136
|
+
--sp-select-trigger-max-width: 24rem;
|
|
137
|
+
--sp-loader-moon-size: 10px;
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
##
|
|
159
|
+
## The components
|
|
170
160
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
195
|
-
|
|
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
|
-
|
|
200
|
-
|
|
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
|
+
"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
|
}
|