@phcdevworks/spectre-ui 0.0.1 → 0.0.3
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 +251 -27
- package/dist/base.css +45 -15
- package/dist/components.css +234 -114
- package/dist/index.cjs +215 -148
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +86 -52
- package/dist/index.d.ts +86 -52
- package/dist/index.js +212 -143
- package/dist/index.js.map +1 -1
- package/dist/utilities.css +3 -3
- package/package.json +42 -27
package/README.md
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @phcdevworks/spectre-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Framework-agnostic styling layer that powers Spectre Blocks, Spectre Astro, Spectre 11ty, and every Spectre integration.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
> One design system. Many frameworks. Full consistency.
|
|
8
|
-
|
|
9
|
-
---
|
|
5
|
+
> 📋 **[View Roadmap](https://github.com/phcdevworks/spectre-ui/blob/main/ROADMAP.md)** | 🤝 **[Contributing Guide](CONTRIBUTING.md)** | 📝 **[Changelog](CHANGELOG.md)**
|
|
10
6
|
|
|
11
7
|
## Overview
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
`@phcdevworks/spectre-ui` is the core styling layer of the Spectre design system. It consumes `@phcdevworks/spectre-tokens` and ships precompiled CSS, type-safe recipe helpers, and a Tailwind preset so downstream frameworks can stay in sync without duplicating logic. One design system runs the entire Spectre Suite; this package handles the implementation.
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
- **Precompiled CSS**: Ready-to-use stylesheets for fast integration
|
|
21
|
-
- **Design Primitives**: Reusable styling components and utilities
|
|
11
|
+
- ✅ Token-powered styles built on `@phcdevworks/spectre-tokens`
|
|
12
|
+
- ✅ Precompiled `base`, `components`, and `utilities` CSS bundles
|
|
13
|
+
- ✅ Type-safe recipes (`getButtonClasses`, `getCardClasses`, `getInputClasses`)
|
|
14
|
+
- ✅ Tailwind preset + helpers to generate a Spectre theme
|
|
15
|
+
- ✅ Framework-agnostic: works anywhere CSS and JavaScript run
|
|
22
16
|
|
|
23
17
|
## Installation
|
|
24
18
|
|
|
@@ -28,30 +22,260 @@ npm install @phcdevworks/spectre-ui
|
|
|
28
22
|
|
|
29
23
|
## Usage
|
|
30
24
|
|
|
31
|
-
Import Spectre
|
|
25
|
+
### 1. Import Spectre CSS
|
|
26
|
+
|
|
27
|
+
Import the CSS bundles anywhere in your app, layout, or build pipeline.
|
|
28
|
+
|
|
29
|
+
```css
|
|
30
|
+
@import "@phcdevworks/spectre-ui/base.css";
|
|
31
|
+
@import "@phcdevworks/spectre-ui/components.css";
|
|
32
|
+
@import "@phcdevworks/spectre-ui/utilities.css";
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Tailwind integration
|
|
36
|
+
|
|
37
|
+
Spectre ships an opinionated Tailwind preset that mirrors the design tokens exactly.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
// tailwind.config.ts
|
|
41
|
+
import { spectrePreset } from "@phcdevworks/spectre-ui";
|
|
42
|
+
|
|
43
|
+
export default {
|
|
44
|
+
content: ["./src/**/*.{js,ts,jsx,tsx,astro}"],
|
|
45
|
+
presets: [spectrePreset],
|
|
46
|
+
};
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Works with Tailwind 3.x and 4.x through the classic config API.
|
|
50
|
+
|
|
51
|
+
### 3. Use Spectre recipes
|
|
52
|
+
|
|
53
|
+
Recipes wrap Spectre's class combinations so every framework composes styles consistently.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import {
|
|
57
|
+
getButtonClasses,
|
|
58
|
+
getCardClasses,
|
|
59
|
+
getInputClasses,
|
|
60
|
+
} from "@phcdevworks/spectre-ui";
|
|
61
|
+
|
|
62
|
+
const buttonClasses = getButtonClasses({
|
|
63
|
+
variant: "primary",
|
|
64
|
+
size: "lg",
|
|
65
|
+
fullWidth: true,
|
|
66
|
+
});
|
|
67
|
+
// "sp-btn sp-btn--primary sp-btn--lg sp-btn--full"
|
|
68
|
+
|
|
69
|
+
const cardClasses = getCardClasses({ variant: "outline", padded: true });
|
|
70
|
+
// "sp-card sp-card--outline sp-card--padded"
|
|
71
|
+
|
|
72
|
+
const inputClasses = getInputClasses({
|
|
73
|
+
state: "error",
|
|
74
|
+
size: "sm",
|
|
75
|
+
fullWidth: true,
|
|
76
|
+
});
|
|
77
|
+
// "sp-input sp-input--error sp-input--sm sp-input--full"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Component Surfaces
|
|
81
|
+
|
|
82
|
+
### Button variants
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
getButtonClasses({ variant: "primary" }); // CTA baseline
|
|
86
|
+
getButtonClasses({ variant: "secondary" }); // Outlined
|
|
87
|
+
getButtonClasses({ variant: "ghost" }); // Low-emphasis
|
|
88
|
+
getButtonClasses({ variant: "danger" }); // Destructive
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Each variant ships with full state coverage: `default`, `hover`, `active`, `disabled`, and tone modifiers (`success`, `warning`, `danger`).
|
|
92
|
+
|
|
93
|
+
```css
|
|
94
|
+
.cta-button {
|
|
95
|
+
background: var(--sp-component-button-primary-bg);
|
|
96
|
+
color: var(--sp-component-button-primary-text);
|
|
97
|
+
}
|
|
98
|
+
.cta-button:hover {
|
|
99
|
+
background: var(--sp-component-button-primary-bg-hover);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Input states
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
getInputClasses({ state: "default" });
|
|
107
|
+
getInputClasses({ state: "error" });
|
|
108
|
+
getInputClasses({ state: "success" });
|
|
109
|
+
```
|
|
32
110
|
|
|
33
111
|
```css
|
|
34
|
-
|
|
112
|
+
.input:focus {
|
|
113
|
+
border-color: var(--sp-component-input-border-focus);
|
|
114
|
+
outline: var(--sp-focus-ring-width) var(--sp-focus-ring-style)
|
|
115
|
+
var(--sp-component-input-ring-focus);
|
|
116
|
+
}
|
|
117
|
+
.input.error {
|
|
118
|
+
border-color: var(--sp-component-input-border-error);
|
|
119
|
+
background: var(--sp-component-input-bg-error);
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Card variants
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
getCardClasses({ variant: "elevated" }); // Default shadow
|
|
127
|
+
getCardClasses({ variant: "outline" }); // Bordered
|
|
128
|
+
getCardClasses({ variant: "ghost" }); // Transparent
|
|
35
129
|
```
|
|
36
130
|
|
|
37
|
-
|
|
131
|
+
## Surface & Typography Roles
|
|
132
|
+
|
|
133
|
+
Spectre exposes semantic layers that decouple structural styles from raw palette values. Override these roles at any scope (root, layout, or component wrapper) to restyle whole experiences without editing CSS.
|
|
134
|
+
|
|
135
|
+
- `surface.page`, `surface.card`, `surface.input`, `surface.overlay`: semantic backgrounds for the app canvas, containers/tiles, form fields, and modal/dropdown layers.
|
|
136
|
+
- `text.onPage.*` vs `text.onSurface.*`: use `onPage` for copy sitting directly on the page canvas; use `onSurface` for text inside cards, tiles, inputs, overlays, and other elevated surfaces.
|
|
137
|
+
- `component.card.text`/`textMuted`, `component.input.text`/`placeholder`, and `component.button.textDefault`/`textOnPrimary` alias the underlying `text.onSurface` roles to keep component defaults aligned.
|
|
138
|
+
|
|
139
|
+
### Tailwind utilities
|
|
140
|
+
|
|
141
|
+
The Tailwind preset exposes semantic helpers:
|
|
142
|
+
|
|
143
|
+
- `bg-surface-page`, `bg-surface-card`, `bg-surface-input`
|
|
144
|
+
- `text-on-page`, `text-on-surface`
|
|
145
|
+
|
|
146
|
+
Use them to mix utility-first UIs with Spectre's semantic palette.
|
|
147
|
+
|
|
148
|
+
### Mode infrastructure
|
|
149
|
+
|
|
150
|
+
Spectre reserves the `data-sp-mode` attribute (or any wrapper selector) for future automatic light/dark modes. Override the semantic variables inside those selectors today and you're ready for upcoming multi-mode token drops.
|
|
151
|
+
|
|
152
|
+
## Usage Examples
|
|
153
|
+
|
|
154
|
+
### Surface-aware components
|
|
155
|
+
|
|
156
|
+
```css
|
|
157
|
+
.hero-panel {
|
|
158
|
+
--sp-surface-card: var(--sp-color-neutral-900);
|
|
159
|
+
--sp-text-on-surface-default: var(--sp-color-neutral-50);
|
|
160
|
+
--sp-text-on-surface-muted: var(--sp-color-neutral-200);
|
|
161
|
+
--sp-component-button-primary-bg: var(--sp-color-accent-400);
|
|
162
|
+
--sp-component-button-primary-text: var(--sp-color-neutral-900);
|
|
163
|
+
--sp-component-card-border: transparent;
|
|
164
|
+
--sp-component-input-border: var(--sp-color-accent-400);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
38
167
|
|
|
39
168
|
```html
|
|
40
|
-
<
|
|
169
|
+
<section class="hero-panel">
|
|
170
|
+
<button class="sp-btn sp-btn--primary">Surface Button</button>
|
|
171
|
+
<div class="sp-card sp-card--elevated">
|
|
172
|
+
<p>Cards inherit the contextual surface + text roles automatically.</p>
|
|
173
|
+
</div>
|
|
174
|
+
<input class="sp-input" placeholder="Email address" />
|
|
175
|
+
</section>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Tailwind semantic utilities
|
|
179
|
+
|
|
180
|
+
```jsx
|
|
181
|
+
export function SignupCard() {
|
|
182
|
+
return (
|
|
183
|
+
<div className="bg-surface-card text-on-surface sp-card sp-card--padded">
|
|
184
|
+
<h2 className="text-on-page font-semibold">Join the beta</h2>
|
|
185
|
+
<input className="sp-input mt-4" placeholder="you@spectre.dev" />
|
|
186
|
+
<button className="sp-btn sp-btn--primary mt-4">Request access</button>
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## CSS Path Constants
|
|
193
|
+
|
|
194
|
+
Utilities for referencing the published CSS files programmatically:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
import {
|
|
198
|
+
spectreBaseStylesPath,
|
|
199
|
+
spectreComponentsStylesPath,
|
|
200
|
+
spectreUtilitiesStylesPath,
|
|
201
|
+
spectreStyles,
|
|
202
|
+
} from "@phcdevworks/spectre-ui";
|
|
203
|
+
|
|
204
|
+
// spectreStyles.base → "@phcdevworks/spectre-ui/base.css"
|
|
205
|
+
// spectreStyles.components → "@phcdevworks/spectre-ui/components.css"
|
|
206
|
+
// spectreStyles.utilities → "@phcdevworks/spectre-ui/utilities.css"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Repository Layout
|
|
210
|
+
|
|
211
|
+
| Folder | Responsibility |
|
|
212
|
+
| ------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
213
|
+
| `src/` | TypeScript source: recipes, Tailwind preset, token re-exports, CSS constants. |
|
|
214
|
+
| `src/styles/` | Raw CSS files (`base.css`, `components.css`, `utilities.css`) copied to `dist/` during build. |
|
|
215
|
+
| `dist/` | Generated artifacts: `index.js`, `index.cjs`, `index.d.ts`, and CSS files. Regenerated via `npm run build`. |
|
|
216
|
+
|
|
217
|
+
Designers update tokens in `@phcdevworks/spectre-tokens`. Engineering evolves recipes, presets, and CSS in this package.
|
|
218
|
+
|
|
219
|
+
## Build & Release
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
npm run build
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
`tsup` compiles the TypeScript library (ESM, CJS, `.d.ts`) and copies CSS files to `dist/`. Because `dist/` is generated, releases are reproducible from `src/`.
|
|
226
|
+
|
|
227
|
+
For release history and version notes, see the **[Changelog](CHANGELOG.md)**.
|
|
228
|
+
|
|
229
|
+
## Design Principles
|
|
230
|
+
|
|
231
|
+
1. **Single source of truth** – All Spectre products consume these styles and recipes.
|
|
232
|
+
2. **No style duplication** – Downstream frameworks never re-encode Spectre logic.
|
|
233
|
+
3. **Token-first** – The Tailwind preset, CSS, and recipes are generated from tokens.
|
|
234
|
+
4. **Framework agnostic** – Works with any bundler, CMS, or runtime.
|
|
235
|
+
5. **Type-safe ergonomics** – Every helper exports strict types for confident usage.
|
|
236
|
+
|
|
237
|
+
## TypeScript Support
|
|
238
|
+
|
|
239
|
+
Type definitions are bundled automatically:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import type {
|
|
243
|
+
SpectreTokens,
|
|
244
|
+
SpectreTailwindTheme,
|
|
245
|
+
ButtonVariant,
|
|
246
|
+
InputState,
|
|
247
|
+
CardVariant,
|
|
248
|
+
ButtonRecipeOptions,
|
|
249
|
+
CardRecipeOptions,
|
|
250
|
+
InputRecipeOptions,
|
|
251
|
+
} from "@phcdevworks/spectre-ui";
|
|
41
252
|
```
|
|
42
253
|
|
|
43
254
|
## Part of the Spectre Suite
|
|
44
255
|
|
|
45
|
-
- **Spectre Tokens
|
|
46
|
-
- **Spectre UI
|
|
47
|
-
- **Spectre Blocks
|
|
48
|
-
- **Spectre Astro
|
|
49
|
-
- **Spectre 11ty
|
|
256
|
+
- **Spectre Tokens** – Design-token foundation
|
|
257
|
+
- **Spectre UI** – Core styling layer (this package)
|
|
258
|
+
- **Spectre Blocks** – WordPress block library
|
|
259
|
+
- **Spectre Astro** – Astro integration
|
|
260
|
+
- **Spectre 11ty** – Eleventy integration
|
|
261
|
+
|
|
262
|
+
For the project's future direction, see the **[Roadmap](https://github.com/phcdevworks/spectre-ui/blob/main/ROADMAP.md)**.
|
|
263
|
+
|
|
264
|
+
## Contributing
|
|
265
|
+
|
|
266
|
+
Issues and pull requests are welcome. If you are proposing style or recipe changes, update `src/` and include regenerated builds.
|
|
267
|
+
|
|
268
|
+
For detailed contribution guidelines, see **[CONTRIBUTING.md](CONTRIBUTING.md)**.
|
|
50
269
|
|
|
51
270
|
## License
|
|
52
271
|
|
|
53
|
-
MIT
|
|
272
|
+
MIT © PHCDevworks — See **[LICENSE](LICENSE)** for details.
|
|
54
273
|
|
|
55
|
-
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## ❤️ Support Spectre
|
|
277
|
+
|
|
278
|
+
If Spectre UI helps your workflow, consider sponsoring:
|
|
56
279
|
|
|
57
|
-
|
|
280
|
+
- [GitHub Sponsors](https://github.com/sponsors/phcdevworks)
|
|
281
|
+
- [Buy Me a Coffee](https://buymeacoffee.com/phcdevworks)
|
package/dist/base.css
CHANGED
|
@@ -1,42 +1,72 @@
|
|
|
1
1
|
@layer base {
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
--sp-surface-page: var(--sp-color-neutral-50, #f8fafc);
|
|
5
|
+
--sp-surface-card: #ffffff;
|
|
6
|
+
--sp-surface-input: var(--sp-form-default-bg, #ffffff);
|
|
7
|
+
--sp-surface-overlay: rgba(15, 23, 42, var(--sp-opacity-overlay, 0.5));
|
|
8
|
+
}
|
|
9
|
+
|
|
2
10
|
*,
|
|
3
11
|
*::before,
|
|
4
12
|
*::after {
|
|
5
13
|
box-sizing: border-box;
|
|
6
14
|
}
|
|
7
15
|
|
|
16
|
+
html,
|
|
8
17
|
body {
|
|
9
18
|
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
body {
|
|
10
23
|
min-height: 100vh;
|
|
11
|
-
font-family: var(--sp-font-family-sans, system-ui);
|
|
24
|
+
font-family: var(--sp-font-family-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
|
|
12
25
|
font-size: var(--sp-font-md-size, 1rem);
|
|
13
26
|
line-height: var(--sp-font-md-line-height, 1.5);
|
|
14
|
-
color: var(--sp-color-neutral-900, #0f172a);
|
|
15
|
-
background-color: var(--sp-color-neutral-50, #f8fafc);
|
|
16
|
-
|
|
27
|
+
color: var(--sp-text-on-page-default, var(--sp-color-neutral-900, #0f172a));
|
|
28
|
+
background-color: var(--sp-surface-page, var(--sp-color-neutral-50, #f8fafc));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
img,
|
|
32
|
+
picture,
|
|
33
|
+
video,
|
|
34
|
+
canvas,
|
|
35
|
+
svg {
|
|
36
|
+
display: block;
|
|
37
|
+
max-width: 100%;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
input,
|
|
41
|
+
button,
|
|
42
|
+
textarea,
|
|
43
|
+
select {
|
|
44
|
+
font: inherit;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
button {
|
|
48
|
+
border: none;
|
|
49
|
+
background: none;
|
|
50
|
+
padding: 0;
|
|
51
|
+
cursor: pointer;
|
|
17
52
|
}
|
|
18
53
|
|
|
19
54
|
a {
|
|
20
|
-
color: var(--sp-color-
|
|
55
|
+
color: var(--sp-link-color, var(--sp-color-primary-600, #4f46e5));
|
|
21
56
|
text-decoration: none;
|
|
22
|
-
font-weight: var(--sp-font-md-weight, 500);
|
|
23
|
-
transition: color var(--sp-duration-fast, 150ms) var(--sp-easing-out, ease);
|
|
24
57
|
}
|
|
25
58
|
|
|
26
|
-
a:hover
|
|
27
|
-
a:focus-visible {
|
|
28
|
-
color: var(--sp-color-brand-700, #5626b4);
|
|
59
|
+
a:hover {
|
|
29
60
|
text-decoration: underline;
|
|
30
61
|
}
|
|
31
62
|
|
|
32
63
|
:focus-visible {
|
|
33
|
-
outline:
|
|
34
|
-
|
|
35
|
-
outline-offset: var(--sp-focus-ring-offset, 2px);
|
|
64
|
+
outline: 2px solid var(--sp-focus-ring-color, #4f46e5);
|
|
65
|
+
outline-offset: 2px;
|
|
36
66
|
}
|
|
37
67
|
|
|
38
68
|
::selection {
|
|
39
|
-
background-color: var(--sp-
|
|
40
|
-
color:
|
|
69
|
+
background-color: var(--sp-selection-bg, rgba(79, 70, 229, 0.15));
|
|
70
|
+
color: inherit;
|
|
41
71
|
}
|
|
42
72
|
}
|