@phcdevworks/spectre-ui 0.0.2 → 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 +180 -46
- package/dist/base.css +9 -2
- package/dist/components.css +153 -62
- package/dist/index.cjs +103 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +99 -2
- package/dist/index.js.map +1 -1
- package/package.json +38 -27
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
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
|
+
|
|
5
|
+
> 📋 **[View Roadmap](https://github.com/phcdevworks/spectre-ui/blob/main/ROADMAP.md)** | 🤝 **[Contributing Guide](CONTRIBUTING.md)** | 📝 **[Changelog](CHANGELOG.md)**
|
|
4
6
|
|
|
5
7
|
## Overview
|
|
6
8
|
|
|
7
|
-
|
|
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.
|
|
8
10
|
|
|
9
11
|
- ✅ Token-powered styles built on `@phcdevworks/spectre-tokens`
|
|
10
12
|
- ✅ Precompiled `base`, `components`, and `utilities` CSS bundles
|
|
@@ -22,21 +24,20 @@ npm install @phcdevworks/spectre-ui
|
|
|
22
24
|
|
|
23
25
|
### 1. Import Spectre CSS
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
Import the CSS bundles anywhere in your app, layout, or build pipeline.
|
|
26
28
|
|
|
27
29
|
```css
|
|
28
|
-
|
|
29
|
-
@import "@phcdevworks/spectre-ui/
|
|
30
|
-
@import "@phcdevworks/spectre-ui/
|
|
31
|
-
@import "@phcdevworks/spectre-ui/dist/utilities.css";
|
|
30
|
+
@import "@phcdevworks/spectre-ui/base.css";
|
|
31
|
+
@import "@phcdevworks/spectre-ui/components.css";
|
|
32
|
+
@import "@phcdevworks/spectre-ui/utilities.css";
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
### 2.
|
|
35
|
+
### 2. Tailwind integration
|
|
35
36
|
|
|
36
|
-
Spectre ships an opinionated Tailwind preset that mirrors the tokens exactly.
|
|
37
|
+
Spectre ships an opinionated Tailwind preset that mirrors the design tokens exactly.
|
|
37
38
|
|
|
38
39
|
```ts
|
|
39
|
-
// tailwind.config.
|
|
40
|
+
// tailwind.config.ts
|
|
40
41
|
import { spectrePreset } from "@phcdevworks/spectre-ui";
|
|
41
42
|
|
|
42
43
|
export default {
|
|
@@ -45,23 +46,7 @@ export default {
|
|
|
45
46
|
};
|
|
46
47
|
```
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
import {
|
|
52
|
-
spectreTokens,
|
|
53
|
-
createSpectreTailwindTheme,
|
|
54
|
-
} from "@phcdevworks/spectre-ui";
|
|
55
|
-
|
|
56
|
-
const theme = createSpectreTailwindTheme({
|
|
57
|
-
tokens: spectreTokens,
|
|
58
|
-
overrides: {
|
|
59
|
-
colors: {
|
|
60
|
-
brand: "#7928CA",
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
```
|
|
49
|
+
Works with Tailwind 3.x and 4.x through the classic config API.
|
|
65
50
|
|
|
66
51
|
### 3. Use Spectre recipes
|
|
67
52
|
|
|
@@ -92,6 +77,118 @@ const inputClasses = getInputClasses({
|
|
|
92
77
|
// "sp-input sp-input--error sp-input--sm sp-input--full"
|
|
93
78
|
```
|
|
94
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
|
+
```
|
|
110
|
+
|
|
111
|
+
```css
|
|
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
|
|
129
|
+
```
|
|
130
|
+
|
|
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
|
+
```
|
|
167
|
+
|
|
168
|
+
```html
|
|
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
|
+
|
|
95
192
|
## CSS Path Constants
|
|
96
193
|
|
|
97
194
|
Utilities for referencing the published CSS files programmatically:
|
|
@@ -104,14 +201,42 @@ import {
|
|
|
104
201
|
spectreStyles,
|
|
105
202
|
} from "@phcdevworks/spectre-ui";
|
|
106
203
|
|
|
107
|
-
// spectreStyles.base → "@phcdevworks/spectre-ui/
|
|
108
|
-
// spectreStyles.components → "@phcdevworks/spectre-ui/
|
|
109
|
-
// spectreStyles.utilities → "@phcdevworks/spectre-ui/
|
|
204
|
+
// spectreStyles.base → "@phcdevworks/spectre-ui/base.css"
|
|
205
|
+
// spectreStyles.components → "@phcdevworks/spectre-ui/components.css"
|
|
206
|
+
// spectreStyles.utilities → "@phcdevworks/spectre-ui/utilities.css"
|
|
110
207
|
```
|
|
111
208
|
|
|
112
|
-
##
|
|
209
|
+
## Repository Layout
|
|
113
210
|
|
|
114
|
-
|
|
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:
|
|
115
240
|
|
|
116
241
|
```ts
|
|
117
242
|
import type {
|
|
@@ -120,28 +245,37 @@ import type {
|
|
|
120
245
|
ButtonVariant,
|
|
121
246
|
InputState,
|
|
122
247
|
CardVariant,
|
|
248
|
+
ButtonRecipeOptions,
|
|
249
|
+
CardRecipeOptions,
|
|
250
|
+
InputRecipeOptions,
|
|
123
251
|
} from "@phcdevworks/spectre-ui";
|
|
124
252
|
```
|
|
125
253
|
|
|
126
|
-
|
|
254
|
+
## Part of the Spectre Suite
|
|
127
255
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
4. **Framework agnostic** – works with any bundler, CMS, or runtime.
|
|
134
|
-
5. **Type-safe ergonomics** – every helper exports strict types for confident usage.
|
|
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
|
|
135
261
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
- **Tailwind CSS**: ^3.4.0 or ^4.0.0 (if you consume the preset)
|
|
139
|
-
- **Build tooling**: ESM-compatible bundler capable of importing CSS from npm
|
|
262
|
+
For the project's future direction, see the **[Roadmap](https://github.com/phcdevworks/spectre-ui/blob/main/ROADMAP.md)**.
|
|
140
263
|
|
|
141
264
|
## Contributing
|
|
142
265
|
|
|
143
|
-
|
|
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)**.
|
|
144
269
|
|
|
145
270
|
## License
|
|
146
271
|
|
|
147
|
-
MIT © PHCDevworks
|
|
272
|
+
MIT © PHCDevworks — See **[LICENSE](LICENSE)** for details.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## ❤️ Support Spectre
|
|
277
|
+
|
|
278
|
+
If Spectre UI helps your workflow, consider sponsoring:
|
|
279
|
+
|
|
280
|
+
- [GitHub Sponsors](https://github.com/sponsors/phcdevworks)
|
|
281
|
+
- [Buy Me a Coffee](https://buymeacoffee.com/phcdevworks)
|
package/dist/base.css
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
@layer base {
|
|
2
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
|
+
|
|
3
10
|
*,
|
|
4
11
|
*::before,
|
|
5
12
|
*::after {
|
|
@@ -17,8 +24,8 @@
|
|
|
17
24
|
font-family: var(--sp-font-family-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
|
|
18
25
|
font-size: var(--sp-font-md-size, 1rem);
|
|
19
26
|
line-height: var(--sp-font-md-line-height, 1.5);
|
|
20
|
-
color: var(--sp-color-neutral-900, #0f172a);
|
|
21
|
-
background-color: var(--sp-color-neutral-50, #f8fafc);
|
|
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));
|
|
22
29
|
}
|
|
23
30
|
|
|
24
31
|
img,
|
package/dist/components.css
CHANGED
|
@@ -1,5 +1,76 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
|
|
3
|
+
:root {
|
|
4
|
+
/* button roles */
|
|
5
|
+
--sp-component-button-border-base: var(--sp-component-button-ghost-bg, var(--sp-button-ghost-bg));
|
|
6
|
+
--sp-component-button-shadow: var(--sp-shadow-sm);
|
|
7
|
+
--sp-component-button-primary-bg: var(--sp-button-primary-bg);
|
|
8
|
+
--sp-component-button-primary-bg-hover: var(--sp-button-primary-bghover);
|
|
9
|
+
--sp-component-button-primary-bg-active: var(--sp-button-primary-bgactive);
|
|
10
|
+
--sp-component-button-primary-bg-disabled: var(--sp-button-primary-bgdisabled);
|
|
11
|
+
--sp-component-button-primary-text: var(--sp-button-primary-text);
|
|
12
|
+
--sp-component-button-primary-text-disabled: var(--sp-button-primary-textdisabled);
|
|
13
|
+
--sp-component-button-secondary-bg: var(--sp-button-secondary-bg);
|
|
14
|
+
--sp-component-button-secondary-bg-hover: var(--sp-button-secondary-bghover);
|
|
15
|
+
--sp-component-button-secondary-bg-active: var(--sp-button-secondary-bgactive);
|
|
16
|
+
--sp-component-button-secondary-bg-disabled: var(--sp-button-secondary-bgdisabled);
|
|
17
|
+
--sp-component-button-secondary-text: var(--sp-button-secondary-text);
|
|
18
|
+
--sp-component-button-secondary-text-disabled: var(--sp-button-secondary-textdisabled);
|
|
19
|
+
--sp-component-button-secondary-border: var(--sp-button-secondary-border);
|
|
20
|
+
--sp-component-button-secondary-border-disabled: var(--sp-button-secondary-borderdisabled);
|
|
21
|
+
--sp-component-button-ghost-bg: var(--sp-button-ghost-bg);
|
|
22
|
+
--sp-component-button-ghost-bg-hover: var(--sp-button-ghost-bghover);
|
|
23
|
+
--sp-component-button-ghost-bg-active: var(--sp-button-ghost-bgactive);
|
|
24
|
+
--sp-component-button-ghost-bg-disabled: var(--sp-button-ghost-bgdisabled);
|
|
25
|
+
--sp-component-button-ghost-text: var(--sp-button-ghost-text);
|
|
26
|
+
--sp-component-button-ghost-text-disabled: var(--sp-button-ghost-textdisabled);
|
|
27
|
+
--sp-component-button-danger-bg: var(--sp-button-danger-bg);
|
|
28
|
+
--sp-component-button-danger-bg-hover: var(--sp-button-danger-bghover);
|
|
29
|
+
--sp-component-button-danger-bg-active: var(--sp-button-danger-bgactive);
|
|
30
|
+
--sp-component-button-danger-bg-disabled: var(--sp-button-danger-bgdisabled);
|
|
31
|
+
--sp-component-button-danger-text: var(--sp-button-danger-text);
|
|
32
|
+
--sp-component-button-danger-text-disabled: var(--sp-button-danger-textdisabled);
|
|
33
|
+
--sp-component-button-success-bg: var(--sp-button-success-bg);
|
|
34
|
+
--sp-component-button-success-bg-hover: var(--sp-button-success-bghover);
|
|
35
|
+
--sp-component-button-success-bg-active: var(--sp-button-success-bgactive);
|
|
36
|
+
--sp-component-button-success-bg-disabled: var(--sp-button-success-bgdisabled);
|
|
37
|
+
--sp-component-button-success-text: var(--sp-button-success-text);
|
|
38
|
+
--sp-component-button-success-text-disabled: var(--sp-button-success-textdisabled);
|
|
39
|
+
|
|
40
|
+
/* card roles */
|
|
41
|
+
--sp-component-card-bg: var(--sp-surface-card, var(--sp-color-neutral-50));
|
|
42
|
+
--sp-component-card-text: var(--sp-text-on-surface-default, var(--sp-color-neutral-900));
|
|
43
|
+
--sp-component-card-text-muted: var(--sp-text-on-surface-muted, var(--sp-color-neutral-600));
|
|
44
|
+
--sp-component-card-border: var(--sp-color-neutral-200);
|
|
45
|
+
--sp-component-card-border-base: var(--sp-component-card-ghost-border, var(--sp-component-card-bg));
|
|
46
|
+
--sp-component-card-shadow: var(--sp-shadow-sm);
|
|
47
|
+
--sp-component-card-shadow-elevated: var(--sp-shadow-lg);
|
|
48
|
+
--sp-component-card-shadow-flat: var(--sp-shadow-none);
|
|
49
|
+
--sp-component-card-shadow-outline: var(--sp-shadow-none);
|
|
50
|
+
--sp-component-card-shadow-ghost: var(--sp-shadow-none);
|
|
51
|
+
--sp-component-card-outline-bg: var(--sp-component-card-bg);
|
|
52
|
+
--sp-component-card-outline-border: var(--sp-component-card-border);
|
|
53
|
+
--sp-component-card-ghost-bg: var(--sp-component-button-ghost-bg, var(--sp-button-ghost-bg));
|
|
54
|
+
--sp-component-card-ghost-border: var(--sp-component-card-ghost-bg);
|
|
55
|
+
|
|
56
|
+
/* input roles */
|
|
57
|
+
--sp-component-input-border: var(--sp-form-default-border);
|
|
58
|
+
--sp-component-input-bg: var(--sp-surface-input, var(--sp-form-default-bg));
|
|
59
|
+
--sp-component-input-text: var(--sp-text-on-surface-default, var(--sp-form-default-text));
|
|
60
|
+
--sp-component-input-placeholder: var(--sp-text-on-surface-muted, var(--sp-form-default-placeholder));
|
|
61
|
+
--sp-component-input-border-focus: var(--sp-form-focus-border);
|
|
62
|
+
--sp-component-input-ring: var(--sp-form-focus-ring, var(--sp-color-focus-primary));
|
|
63
|
+
--sp-component-input-border-invalid: var(--sp-form-invalid-border);
|
|
64
|
+
--sp-component-input-bg-invalid: var(--sp-form-invalid-bg);
|
|
65
|
+
--sp-component-input-text-invalid: var(--sp-form-invalid-text);
|
|
66
|
+
--sp-component-input-border-valid: var(--sp-form-valid-border);
|
|
67
|
+
--sp-component-input-bg-valid: var(--sp-form-valid-bg);
|
|
68
|
+
--sp-component-input-text-valid: var(--sp-form-valid-text);
|
|
69
|
+
--sp-component-input-bg-disabled: var(--sp-form-disabled-bg);
|
|
70
|
+
--sp-component-input-text-disabled: var(--sp-form-disabled-text);
|
|
71
|
+
--sp-component-input-border-disabled: var(--sp-form-disabled-border);
|
|
72
|
+
}
|
|
73
|
+
|
|
3
74
|
/* BUTTONS -------------------------------------------------------------- */
|
|
4
75
|
.sp-btn {
|
|
5
76
|
display: inline-flex;
|
|
@@ -8,7 +79,10 @@
|
|
|
8
79
|
gap: var(--sp-space-2xs, 0.25rem);
|
|
9
80
|
padding: var(--sp-space-2xs, 0.25rem) var(--sp-space-md, 1rem);
|
|
10
81
|
border-radius: var(--sp-radius-md, 4px);
|
|
11
|
-
border: 1px solid
|
|
82
|
+
border: 1px solid var(
|
|
83
|
+
--sp-component-button-border-base,
|
|
84
|
+
var(--sp-component-button-ghost-bg, var(--sp-button-ghost-bg))
|
|
85
|
+
);
|
|
12
86
|
font-family: var(--sp-font-family-sans, system-ui);
|
|
13
87
|
font-size: var(--sp-font-md-size, 1rem);
|
|
14
88
|
line-height: 1;
|
|
@@ -48,116 +122,119 @@
|
|
|
48
122
|
|
|
49
123
|
/* primary */
|
|
50
124
|
.sp-btn--primary {
|
|
51
|
-
background-color: var(--sp-button-primary-bg
|
|
52
|
-
color: var(--sp-button-primary-text
|
|
53
|
-
box-shadow: var(
|
|
125
|
+
background-color: var(--sp-component-button-primary-bg);
|
|
126
|
+
color: var(--sp-component-button-primary-text);
|
|
127
|
+
box-shadow: var(
|
|
128
|
+
--sp-component-button-shadow,
|
|
129
|
+
var(--sp-shadow-sm)
|
|
130
|
+
);
|
|
54
131
|
}
|
|
55
132
|
|
|
56
133
|
.sp-btn--primary.sp-btn--hover,
|
|
57
134
|
.sp-btn--primary:hover {
|
|
58
|
-
background-color: var(--sp-button-primary-
|
|
135
|
+
background-color: var(--sp-component-button-primary-bg-hover);
|
|
59
136
|
}
|
|
60
137
|
|
|
61
138
|
.sp-btn--primary.sp-btn--active,
|
|
62
139
|
.sp-btn--primary:active {
|
|
63
|
-
background-color: var(--sp-button-primary-
|
|
140
|
+
background-color: var(--sp-component-button-primary-bg-active);
|
|
64
141
|
}
|
|
65
142
|
|
|
66
143
|
.sp-btn--primary.sp-btn--disabled,
|
|
67
144
|
.sp-btn--primary:disabled {
|
|
68
|
-
background-color: var(--sp-button-primary-
|
|
69
|
-
color: var(--sp-button-primary-
|
|
145
|
+
background-color: var(--sp-component-button-primary-bg-disabled);
|
|
146
|
+
color: var(--sp-component-button-primary-text-disabled);
|
|
70
147
|
box-shadow: none;
|
|
71
148
|
}
|
|
72
149
|
|
|
73
150
|
/* secondary */
|
|
74
151
|
.sp-btn--secondary {
|
|
75
|
-
background-color: var(--sp-button-secondary-bg
|
|
76
|
-
color: var(--sp-button-secondary-text
|
|
77
|
-
border-color: var(--sp-button-secondary-border
|
|
152
|
+
background-color: var(--sp-component-button-secondary-bg);
|
|
153
|
+
color: var(--sp-component-button-secondary-text);
|
|
154
|
+
border-color: var(--sp-component-button-secondary-border);
|
|
78
155
|
}
|
|
79
156
|
|
|
80
157
|
.sp-btn--secondary.sp-btn--hover,
|
|
81
158
|
.sp-btn--secondary:hover {
|
|
82
|
-
background-color: var(--sp-button-secondary-
|
|
159
|
+
background-color: var(--sp-component-button-secondary-bg-hover);
|
|
83
160
|
}
|
|
84
161
|
|
|
85
162
|
.sp-btn--secondary.sp-btn--active,
|
|
86
163
|
.sp-btn--secondary:active {
|
|
87
|
-
background-color: var(--sp-button-secondary-
|
|
164
|
+
background-color: var(--sp-component-button-secondary-bg-active);
|
|
88
165
|
}
|
|
89
166
|
|
|
90
167
|
.sp-btn--secondary.sp-btn--disabled,
|
|
91
168
|
.sp-btn--secondary:disabled {
|
|
92
|
-
background-color: var(--sp-button-secondary-
|
|
93
|
-
color: var(--sp-button-secondary-
|
|
94
|
-
border-color: var(--sp-button-secondary-
|
|
169
|
+
background-color: var(--sp-component-button-secondary-bg-disabled);
|
|
170
|
+
color: var(--sp-component-button-secondary-text-disabled);
|
|
171
|
+
border-color: var(--sp-component-button-secondary-border-disabled);
|
|
95
172
|
}
|
|
96
173
|
|
|
97
174
|
/* ghost */
|
|
98
175
|
.sp-btn--ghost {
|
|
99
|
-
background-color:
|
|
100
|
-
color: var(--sp-button-ghost-text
|
|
176
|
+
background-color: var(--sp-component-button-ghost-bg);
|
|
177
|
+
color: var(--sp-component-button-ghost-text);
|
|
101
178
|
}
|
|
102
179
|
|
|
103
180
|
.sp-btn--ghost.sp-btn--hover,
|
|
104
181
|
.sp-btn--ghost:hover {
|
|
105
|
-
background-color: var(--sp-button-ghost-
|
|
182
|
+
background-color: var(--sp-component-button-ghost-bg-hover);
|
|
106
183
|
}
|
|
107
184
|
|
|
108
185
|
.sp-btn--ghost.sp-btn--active,
|
|
109
186
|
.sp-btn--ghost:active {
|
|
110
|
-
background-color: var(--sp-button-ghost-
|
|
187
|
+
background-color: var(--sp-component-button-ghost-bg-active);
|
|
111
188
|
}
|
|
112
189
|
|
|
113
190
|
.sp-btn--ghost.sp-btn--disabled,
|
|
114
191
|
.sp-btn--ghost:disabled {
|
|
115
|
-
color: var(--sp-button-ghost-
|
|
116
|
-
background-color:
|
|
192
|
+
color: var(--sp-component-button-ghost-text-disabled);
|
|
193
|
+
background-color: var(--sp-component-button-ghost-bg-disabled);
|
|
117
194
|
}
|
|
118
195
|
|
|
119
196
|
/* danger */
|
|
120
197
|
.sp-btn--danger {
|
|
121
|
-
background-color: var(--sp-button-danger-bg
|
|
122
|
-
color: var(--sp-button-danger-text
|
|
198
|
+
background-color: var(--sp-component-button-danger-bg);
|
|
199
|
+
color: var(--sp-component-button-danger-text);
|
|
123
200
|
}
|
|
124
201
|
|
|
125
202
|
.sp-btn--danger.sp-btn--hover,
|
|
126
203
|
.sp-btn--danger:hover {
|
|
127
|
-
background-color: var(--sp-button-danger-
|
|
204
|
+
background-color: var(--sp-component-button-danger-bg-hover);
|
|
128
205
|
}
|
|
129
206
|
|
|
130
207
|
.sp-btn--danger.sp-btn--active,
|
|
131
208
|
.sp-btn--danger:active {
|
|
132
|
-
background-color: var(--sp-button-danger-
|
|
209
|
+
background-color: var(--sp-component-button-danger-bg-active);
|
|
133
210
|
}
|
|
134
211
|
|
|
135
212
|
.sp-btn--danger.sp-btn--disabled,
|
|
136
213
|
.sp-btn--danger:disabled {
|
|
137
|
-
background-color: var(--sp-button-danger-
|
|
138
|
-
color: var(--sp-button-danger-
|
|
214
|
+
background-color: var(--sp-component-button-danger-bg-disabled);
|
|
215
|
+
color: var(--sp-component-button-danger-text-disabled);
|
|
139
216
|
}
|
|
140
217
|
|
|
141
218
|
/* success */
|
|
142
219
|
.sp-btn--success {
|
|
143
|
-
background-color: var(--sp-button-success-bg
|
|
144
|
-
color: var(--sp-button-success-text
|
|
220
|
+
background-color: var(--sp-component-button-success-bg);
|
|
221
|
+
color: var(--sp-component-button-success-text);
|
|
145
222
|
}
|
|
146
223
|
|
|
147
224
|
.sp-btn--success.sp-btn--hover,
|
|
148
225
|
.sp-btn--success:hover {
|
|
149
|
-
background-color: var(--sp-button-success-
|
|
226
|
+
background-color: var(--sp-component-button-success-bg-hover);
|
|
150
227
|
}
|
|
151
228
|
|
|
152
229
|
.sp-btn--success.sp-btn--active,
|
|
153
230
|
.sp-btn--success:active {
|
|
154
|
-
background-color: var(--sp-button-success-
|
|
231
|
+
background-color: var(--sp-component-button-success-bg-active);
|
|
155
232
|
}
|
|
156
233
|
|
|
157
234
|
.sp-btn--success.sp-btn--disabled,
|
|
158
235
|
.sp-btn--success:disabled {
|
|
159
|
-
background-color: var(--sp-button-success-
|
|
160
|
-
color: var(--sp-button-success-
|
|
236
|
+
background-color: var(--sp-component-button-success-bg-disabled);
|
|
237
|
+
color: var(--sp-component-button-success-text-disabled);
|
|
161
238
|
}
|
|
162
239
|
|
|
163
240
|
/* INPUTS --------------------------------------------------------------- */
|
|
@@ -167,9 +244,9 @@
|
|
|
167
244
|
display: block;
|
|
168
245
|
padding: var(--sp-space-2xs, 0.25rem) var(--sp-space-md, 1rem);
|
|
169
246
|
border-radius: var(--sp-radius-md, 4px);
|
|
170
|
-
border: 1px solid var(--sp-form-default-border
|
|
171
|
-
background
|
|
172
|
-
color: var(--sp-form-default-text
|
|
247
|
+
border: 1px solid var(--sp-component-input-border, var(--sp-form-default-border));
|
|
248
|
+
background: var(--sp-component-input-bg, var(--sp-surface-input, var(--sp-form-default-bg)));
|
|
249
|
+
color: var(--sp-component-input-text, var(--sp-text-on-surface-default, var(--sp-form-default-text)));
|
|
173
250
|
font-family: var(--sp-font-family-sans, system-ui);
|
|
174
251
|
font-size: var(--sp-font-md-size, 1rem);
|
|
175
252
|
line-height: var(--sp-font-md-line-height, 1.5rem);
|
|
@@ -180,32 +257,38 @@
|
|
|
180
257
|
}
|
|
181
258
|
|
|
182
259
|
.sp-input::placeholder {
|
|
183
|
-
color: var(--sp-form-default-placeholder
|
|
260
|
+
color: var(--sp-component-input-placeholder, var(--sp-text-on-surface-muted, var(--sp-form-default-placeholder)));
|
|
184
261
|
}
|
|
185
262
|
|
|
186
263
|
.sp-input:focus,
|
|
187
264
|
.sp-input--focus {
|
|
188
|
-
border-color: var(
|
|
189
|
-
|
|
265
|
+
border-color: var(
|
|
266
|
+
--sp-component-input-border-focus,
|
|
267
|
+
var(--sp-component-input-border, var(--sp-form-focus-border))
|
|
268
|
+
);
|
|
269
|
+
box-shadow: 0 0 0 var(--sp-focus-ring-width, 2px) var(
|
|
270
|
+
--sp-component-input-ring,
|
|
271
|
+
var(--sp-form-focus-ring, var(--sp-color-focus-primary))
|
|
272
|
+
);
|
|
190
273
|
outline: none;
|
|
191
274
|
}
|
|
192
275
|
|
|
193
276
|
.sp-input--error {
|
|
194
|
-
border-color: var(--sp-form-invalid-border
|
|
195
|
-
background-color: var(--sp-form-invalid-bg
|
|
196
|
-
color: var(--sp-form-invalid-text
|
|
277
|
+
border-color: var(--sp-component-input-border-invalid, var(--sp-form-invalid-border));
|
|
278
|
+
background-color: var(--sp-component-input-bg-invalid, var(--sp-form-invalid-bg));
|
|
279
|
+
color: var(--sp-component-input-text-invalid, var(--sp-form-invalid-text));
|
|
197
280
|
}
|
|
198
281
|
|
|
199
282
|
.sp-input--success {
|
|
200
|
-
border-color: var(--sp-form-valid-border
|
|
201
|
-
background-color: var(--sp-form-valid-bg
|
|
202
|
-
color: var(--sp-form-valid-text
|
|
283
|
+
border-color: var(--sp-component-input-border-valid, var(--sp-form-valid-border));
|
|
284
|
+
background-color: var(--sp-component-input-bg-valid, var(--sp-form-valid-bg));
|
|
285
|
+
color: var(--sp-component-input-text-valid, var(--sp-form-valid-text));
|
|
203
286
|
}
|
|
204
287
|
|
|
205
288
|
.sp-input--disabled {
|
|
206
|
-
background-color: var(--sp-form-disabled-bg
|
|
207
|
-
color: var(--sp-form-disabled-text
|
|
208
|
-
border-color: var(--sp-form-disabled-border
|
|
289
|
+
background-color: var(--sp-component-input-bg-disabled, var(--sp-form-disabled-bg));
|
|
290
|
+
color: var(--sp-component-input-text-disabled, var(--sp-form-disabled-text));
|
|
291
|
+
border-color: var(--sp-component-input-border-disabled, var(--sp-form-disabled-border));
|
|
209
292
|
}
|
|
210
293
|
|
|
211
294
|
.sp-input--disabled,
|
|
@@ -216,32 +299,40 @@
|
|
|
216
299
|
/* CARDS ---------------------------------------------------------------- */
|
|
217
300
|
|
|
218
301
|
.sp-card {
|
|
219
|
-
background
|
|
220
|
-
color: var(--sp-card-text
|
|
302
|
+
background: var(--sp-component-card-bg);
|
|
303
|
+
color: var(--sp-component-card-text);
|
|
221
304
|
border-radius: var(--sp-radius-lg, 8px);
|
|
222
305
|
padding: var(--sp-space-lg, 1.5rem);
|
|
223
|
-
box-shadow: var(--sp-shadow
|
|
224
|
-
border: 1px solid
|
|
306
|
+
box-shadow: var(--sp-component-card-shadow, var(--sp-shadow-sm));
|
|
307
|
+
border: 1px solid var(
|
|
308
|
+
--sp-component-card-border-base,
|
|
309
|
+
var(--sp-component-card-ghost-border, var(--sp-component-card-bg))
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.sp-card p,
|
|
314
|
+
.sp-card span {
|
|
315
|
+
color: var(--sp-component-card-text-muted);
|
|
225
316
|
}
|
|
226
317
|
|
|
227
318
|
.sp-card--elevated {
|
|
228
|
-
box-shadow: var(--sp-shadow-
|
|
319
|
+
box-shadow: var(--sp-component-card-shadow-elevated, var(--sp-shadow-lg));
|
|
229
320
|
}
|
|
230
321
|
|
|
231
322
|
.sp-card--flat {
|
|
232
|
-
box-shadow: var(--sp-shadow-
|
|
233
|
-
border-color: var(--sp-
|
|
323
|
+
box-shadow: var(--sp-component-card-shadow-flat, var(--sp-shadow-none));
|
|
324
|
+
border-color: var(--sp-component-card-border);
|
|
234
325
|
}
|
|
235
326
|
|
|
236
327
|
.sp-card--outline {
|
|
237
|
-
background-color: var(--sp-card-outline-bg,
|
|
238
|
-
border-color: var(--sp-card-outline-border,
|
|
239
|
-
box-shadow: var(--sp-shadow-
|
|
328
|
+
background-color: var(--sp-component-card-outline-bg, var(--sp-component-card-bg));
|
|
329
|
+
border-color: var(--sp-component-card-outline-border, var(--sp-component-card-border));
|
|
330
|
+
box-shadow: var(--sp-component-card-shadow-outline, var(--sp-shadow-none));
|
|
240
331
|
}
|
|
241
332
|
|
|
242
333
|
.sp-card--ghost {
|
|
243
|
-
background-color:
|
|
244
|
-
border-color:
|
|
245
|
-
box-shadow: none;
|
|
334
|
+
background-color: var(--sp-component-card-ghost-bg);
|
|
335
|
+
border-color: var(--sp-component-card-ghost-border);
|
|
336
|
+
box-shadow: var(--sp-component-card-shadow-ghost, var(--sp-shadow-none));
|
|
246
337
|
}
|
|
247
338
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var plugin = require('tailwindcss/plugin');
|
|
3
4
|
var spectreTokens = require('@phcdevworks/spectre-tokens');
|
|
4
5
|
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
var plugin__default = /*#__PURE__*/_interopDefault(plugin);
|
|
9
|
+
|
|
5
10
|
// src/css-constants.ts
|
|
6
11
|
var spectreBaseStylesPath = "@phcdevworks/spectre-ui/dist/base.css";
|
|
7
12
|
var spectreComponentsStylesPath = "@phcdevworks/spectre-ui/dist/components.css";
|
|
@@ -19,10 +24,44 @@ function createSpectreTailwindTheme(options) {
|
|
|
19
24
|
...tokens,
|
|
20
25
|
...overrides ?? {}
|
|
21
26
|
};
|
|
27
|
+
const mergedColors = mergedTokens.colors ?? {};
|
|
28
|
+
const attachSemanticColors = (existing, semantic) => {
|
|
29
|
+
if (!semantic || Object.keys(semantic).length === 0) {
|
|
30
|
+
return Object.keys(existing).length > 0 ? existing : void 0;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
...existing,
|
|
34
|
+
...semantic
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const themeColors = {
|
|
38
|
+
...mergedColors
|
|
39
|
+
};
|
|
40
|
+
const surfaceColors = attachSemanticColors(
|
|
41
|
+
mergedColors.surface ?? {},
|
|
42
|
+
mergedTokens.surface
|
|
43
|
+
);
|
|
44
|
+
if (surfaceColors) {
|
|
45
|
+
themeColors.surface = surfaceColors;
|
|
46
|
+
}
|
|
47
|
+
const textColors = attachSemanticColors(
|
|
48
|
+
mergedColors.text ?? {},
|
|
49
|
+
mergedTokens.text
|
|
50
|
+
);
|
|
51
|
+
if (textColors) {
|
|
52
|
+
themeColors.text = textColors;
|
|
53
|
+
}
|
|
54
|
+
const componentColors = attachSemanticColors(
|
|
55
|
+
mergedColors.component ?? {},
|
|
56
|
+
mergedTokens.component
|
|
57
|
+
);
|
|
58
|
+
if (componentColors) {
|
|
59
|
+
themeColors.component = componentColors;
|
|
60
|
+
}
|
|
22
61
|
const theme2 = {
|
|
23
62
|
// Safely map core token groups into Tailwind theme fields.
|
|
24
63
|
// Use `as any` where necessary to avoid overfitting types right now.
|
|
25
|
-
colors:
|
|
64
|
+
colors: themeColors,
|
|
26
65
|
spacing: mergedTokens.spacing ?? {},
|
|
27
66
|
borderRadius: mergedTokens.radii ?? {},
|
|
28
67
|
boxShadow: mergedTokens.shadows ?? {},
|
|
@@ -35,11 +74,73 @@ function createSpectreTailwindTheme(options) {
|
|
|
35
74
|
var { theme } = createSpectreTailwindTheme({
|
|
36
75
|
tokens: spectreTokens.tokens
|
|
37
76
|
});
|
|
77
|
+
var resolveTokenValue = (value, fallback) => {
|
|
78
|
+
if (typeof value === "string") {
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
if (value && typeof value === "object") {
|
|
82
|
+
const maybeDefault = value.default;
|
|
83
|
+
if (typeof maybeDefault === "string") {
|
|
84
|
+
return maybeDefault;
|
|
85
|
+
}
|
|
86
|
+
const firstEntry = Object.values(value).find(
|
|
87
|
+
(entry) => typeof entry === "string"
|
|
88
|
+
);
|
|
89
|
+
if (typeof firstEntry === "string") {
|
|
90
|
+
return firstEntry;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return fallback;
|
|
94
|
+
};
|
|
95
|
+
var semanticUtilities = plugin__default.default(({ addUtilities }) => {
|
|
96
|
+
const tokens = spectreTokens.tokens;
|
|
97
|
+
const neutralScale = tokens?.colors?.neutral ?? {};
|
|
98
|
+
const formDefault = tokens?.forms?.default ?? {};
|
|
99
|
+
const surfaceTokens = tokens?.surface ?? {};
|
|
100
|
+
const textTokens = tokens?.text ?? {};
|
|
101
|
+
const surfacePage = resolveTokenValue(
|
|
102
|
+
surfaceTokens.page,
|
|
103
|
+
neutralScale["50"]
|
|
104
|
+
);
|
|
105
|
+
const surfaceCard = resolveTokenValue(
|
|
106
|
+
surfaceTokens.card,
|
|
107
|
+
formDefault.bg ?? surfacePage ?? neutralScale["50"]
|
|
108
|
+
);
|
|
109
|
+
const surfaceInput = resolveTokenValue(
|
|
110
|
+
surfaceTokens.input,
|
|
111
|
+
formDefault.bg ?? surfaceCard ?? surfacePage
|
|
112
|
+
);
|
|
113
|
+
const textOnPage = resolveTokenValue(
|
|
114
|
+
textTokens?.on?.page ?? textTokens?.onPage,
|
|
115
|
+
neutralScale["900"] ?? formDefault.text
|
|
116
|
+
);
|
|
117
|
+
const textOnSurface = resolveTokenValue(
|
|
118
|
+
textTokens?.on?.surface ?? textTokens?.onSurface,
|
|
119
|
+
formDefault.text ?? textOnPage ?? neutralScale["900"]
|
|
120
|
+
);
|
|
121
|
+
const utilities = {};
|
|
122
|
+
if (surfacePage) {
|
|
123
|
+
utilities[".bg-surface-page"] = { backgroundColor: surfacePage };
|
|
124
|
+
}
|
|
125
|
+
if (surfaceCard) {
|
|
126
|
+
utilities[".bg-surface-card"] = { backgroundColor: surfaceCard };
|
|
127
|
+
}
|
|
128
|
+
if (surfaceInput) {
|
|
129
|
+
utilities[".bg-surface-input"] = { backgroundColor: surfaceInput };
|
|
130
|
+
}
|
|
131
|
+
if (textOnPage) {
|
|
132
|
+
utilities[".text-on-page"] = { color: textOnPage };
|
|
133
|
+
}
|
|
134
|
+
if (textOnSurface) {
|
|
135
|
+
utilities[".text-on-surface"] = { color: textOnSurface };
|
|
136
|
+
}
|
|
137
|
+
addUtilities(utilities);
|
|
138
|
+
});
|
|
38
139
|
var spectrePreset = {
|
|
39
140
|
// Required for Tailwind's Config type with exactOptionalPropertyTypes
|
|
40
141
|
content: [],
|
|
41
142
|
theme: theme ?? {},
|
|
42
|
-
plugins: []
|
|
143
|
+
plugins: [semanticUtilities]
|
|
43
144
|
};
|
|
44
145
|
|
|
45
146
|
// src/recipes/button.ts
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/css-constants.ts","../src/tailwind/theme.ts","../src/tailwind/preset.ts","../src/recipes/button.ts","../src/recipes/card.ts","../src/recipes/input.ts"],"names":["theme","spectreTokens"],"mappings":"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","file":"index.cjs","sourcesContent":["export const spectreBaseStylesPath = \"@phcdevworks/spectre-ui/dist/base.css\";\nexport const spectreComponentsStylesPath = \"@phcdevworks/spectre-ui/dist/components.css\";\nexport const spectreUtilitiesStylesPath = \"@phcdevworks/spectre-ui/dist/utilities.css\";\n\nexport const spectreStyles = {\n base: spectreBaseStylesPath,\n components: spectreComponentsStylesPath,\n utilities: spectreUtilitiesStylesPath,\n};\n","import type { Config as TailwindConfig } from 'tailwindcss';\nimport type { SpectreTokens } from '../tokens';\n\nexport interface SpectreTailwindTheme {\n theme: TailwindConfig['theme'];\n}\n\nexport interface CreateSpectreTailwindThemeOptions {\n tokens: SpectreTokens;\n overrides?: Partial<SpectreTokens>;\n}\n\nexport function createSpectreTailwindTheme(\n options: CreateSpectreTailwindThemeOptions,\n): SpectreTailwindTheme {\n const { tokens, overrides } = options;\n\n // Shallow merge overrides into tokens\n const mergedTokens: SpectreTokens = {\n ...tokens,\n ...(overrides ?? {}),\n };\n\n const theme: TailwindConfig['theme'] = {\n // Safely map core token groups into Tailwind theme fields.\n // Use `as any` where necessary to avoid overfitting types right now.\n colors: (mergedTokens as any).colors ?? {},\n spacing: (mergedTokens as any).spacing ?? {},\n borderRadius: (mergedTokens as any).radii ?? {},\n boxShadow: (mergedTokens as any).shadows ?? {},\n fontFamily: (mergedTokens as any).typography?.families ?? {},\n };\n\n return { theme };\n}\n","import type { Config as TailwindConfig } from 'tailwindcss';\nimport { spectreTokens } from '../tokens';\nimport { createSpectreTailwindTheme } from './theme';\n\nconst { theme } = createSpectreTailwindTheme({\n tokens: spectreTokens,\n});\n\nexport const spectrePreset: TailwindConfig = {\n // Required for Tailwind's Config type with exactOptionalPropertyTypes\n content: [],\n theme: theme ?? {},\n plugins: [],\n};\n\nexport const spectreTailwindPreset: TailwindConfig = spectrePreset;\n","export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\nexport type ButtonTone = 'default' | 'success' | 'warning' | 'danger';\n\nexport interface ButtonRecipeOptions {\n variant?: ButtonVariant;\n size?: ButtonSize;\n tone?: ButtonTone;\n fullWidth?: boolean;\n loading?: boolean;\n disabled?: boolean;\n iconOnly?: boolean;\n}\n\n/**\n * Generate Spectre button classes.\n *\n * Rules:\n * - Base: \"sp-btn\"\n * - Variant: \"sp-btn--primary\" / \"sp-btn--secondary\" / \"sp-btn--ghost\" / \"sp-btn--danger\"\n * - default variant is \"primary\"\n * - Size: \"sp-btn--sm\" / \"sp-btn--md\" / \"sp-btn--lg\"\n * - default size is \"md\"\n * - Tone: \"sp-btn--tone-success\" / \"sp-btn--tone-warning\" / \"sp-btn--tone-danger\"\n * - default tone is \"default\" (no tone class)\n * - fullWidth: add \"sp-btn--full\"\n * - loading: add \"sp-btn--loading\"\n * - disabled: add \"sp-btn--disabled\"\n * - iconOnly: add \"sp-btn--icon\"\n *\n * Must return a single space-joined, trimmed class string.\n */\nexport function getButtonClasses(opts: ButtonRecipeOptions = {}): string {\n const {\n variant = 'primary',\n size = 'md',\n tone = 'default',\n fullWidth = false,\n loading = false,\n disabled = false,\n iconOnly = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-btn');\n\n // Variant\n const variantMap: Record<ButtonVariant, string> = {\n primary: 'sp-btn--primary',\n secondary: 'sp-btn--secondary',\n ghost: 'sp-btn--ghost',\n danger: 'sp-btn--danger',\n };\n classes.push(variantMap[variant]);\n\n // Size\n const sizeMap: Record<ButtonSize, string> = {\n sm: 'sp-btn--sm',\n md: 'sp-btn--md',\n lg: 'sp-btn--lg',\n };\n classes.push(sizeMap[size]);\n\n // Tone (optional)\n if (tone !== 'default') {\n const toneMap: Record<Exclude<ButtonTone, 'default'>, string> = {\n success: 'sp-btn--tone-success',\n warning: 'sp-btn--tone-warning',\n danger: 'sp-btn--tone-danger',\n };\n classes.push(toneMap[tone as Exclude<ButtonTone, 'default'>]);\n }\n\n // Flags\n if (fullWidth) classes.push('sp-btn--full');\n if (loading) classes.push('sp-btn--loading');\n if (disabled) classes.push('sp-btn--disabled');\n if (iconOnly) classes.push('sp-btn--icon');\n\n // Final class string\n return classes.filter(Boolean).join(' ').trim();\n}\n","export type CardVariant = 'elevated' | 'outline' | 'ghost';\n\nexport interface CardRecipeOptions {\n variant?: CardVariant;\n interactive?: boolean; // hover/focus styles\n padded?: boolean; // apply default padding\n fullHeight?: boolean;\n}\n\n/**\n * Generate Spectre card classes.\n *\n * Rules:\n * - Base class: \"sp-card\"\n * - Variant (default: elevated):\n * - \"sp-card--elevated\"\n * - \"sp-card--outline\"\n * - \"sp-card--ghost\"\n * - interactive: add \"sp-card--interactive\"\n * - padded: add \"sp-card--padded\"\n * - fullHeight: add \"sp-card--full\"\n */\nexport function getCardClasses(opts: CardRecipeOptions = {}): string {\n const {\n variant = 'elevated',\n interactive = false,\n padded = false,\n fullHeight = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-card');\n\n // Variant\n const variantMap: Record<CardVariant, string> = {\n elevated: 'sp-card--elevated',\n outline: 'sp-card--outline',\n ghost: 'sp-card--ghost',\n };\n classes.push(variantMap[variant]);\n\n // Flags\n if (interactive) classes.push('sp-card--interactive');\n if (padded) classes.push('sp-card--padded');\n if (fullHeight) classes.push('sp-card--full');\n\n return classes.filter(Boolean).join(' ').trim();\n}\n","export type InputState = 'default' | 'error' | 'success';\nexport type InputSize = 'sm' | 'md' | 'lg';\n\nexport interface InputRecipeOptions {\n state?: InputState;\n size?: InputSize;\n fullWidth?: boolean;\n}\n\n/**\n * Generate Spectre input classes.\n *\n * Rules:\n * - Base class: \"sp-input\"\n * - State:\n * - \"default\" => no state modifier\n * - \"error\" => \"sp-input--error\"\n * - \"success\" => \"sp-input--success\"\n * - Size (default: md):\n * - \"sp-input--sm\"\n * - \"sp-input--md\"\n * - \"sp-input--lg\"\n * - fullWidth: add \"sp-input--full\"\n */\nexport function getInputClasses(opts: InputRecipeOptions = {}): string {\n const {\n state = 'default',\n size = 'md',\n fullWidth = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-input');\n\n // State\n if (state === 'error') {\n classes.push('sp-input--error');\n } else if (state === 'success') {\n classes.push('sp-input--success');\n }\n\n // Size\n const sizeMap: Record<InputSize, string> = {\n sm: 'sp-input--sm',\n md: 'sp-input--md',\n lg: 'sp-input--lg',\n };\n classes.push(sizeMap[size]);\n\n // Flags\n if (fullWidth) {\n classes.push('sp-input--full');\n }\n\n return classes.filter(Boolean).join(' ').trim();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/css-constants.ts","../src/tailwind/theme.ts","../src/tailwind/preset.ts","../src/recipes/button.ts","../src/recipes/card.ts","../src/recipes/input.ts"],"names":["theme","spectreTokens","plugin"],"mappings":"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","file":"index.cjs","sourcesContent":["export const spectreBaseStylesPath = \"@phcdevworks/spectre-ui/dist/base.css\";\nexport const spectreComponentsStylesPath = \"@phcdevworks/spectre-ui/dist/components.css\";\nexport const spectreUtilitiesStylesPath = \"@phcdevworks/spectre-ui/dist/utilities.css\";\n\nexport const spectreStyles = {\n base: spectreBaseStylesPath,\n components: spectreComponentsStylesPath,\n utilities: spectreUtilitiesStylesPath,\n};\n","import type { Config as TailwindConfig } from 'tailwindcss';\nimport type { SpectreTokens } from '../tokens';\n\nexport interface SpectreTailwindTheme {\n theme: TailwindConfig['theme'];\n}\n\nexport interface CreateSpectreTailwindThemeOptions {\n tokens: SpectreTokens;\n overrides?: Partial<SpectreTokens>;\n}\n\nexport function createSpectreTailwindTheme(\n options: CreateSpectreTailwindThemeOptions,\n): SpectreTailwindTheme {\n const { tokens, overrides } = options;\n\n // Shallow merge overrides into tokens\n const mergedTokens: SpectreTokens = {\n ...tokens,\n ...(overrides ?? {}),\n };\n\n const mergedColors = (mergedTokens as any).colors ?? {};\n\n const attachSemanticColors = (\n existing: Record<string, any>,\n semantic: Record<string, any> | undefined,\n ) => {\n if (!semantic || Object.keys(semantic).length === 0) {\n return Object.keys(existing).length > 0 ? existing : undefined;\n }\n\n return {\n ...existing,\n ...semantic,\n };\n };\n\n const themeColors: Record<string, any> = {\n ...mergedColors,\n };\n\n const surfaceColors = attachSemanticColors(\n mergedColors.surface ?? {},\n (mergedTokens as any).surface,\n );\n if (surfaceColors) {\n themeColors.surface = surfaceColors;\n }\n\n const textColors = attachSemanticColors(\n mergedColors.text ?? {},\n (mergedTokens as any).text,\n );\n if (textColors) {\n themeColors.text = textColors;\n }\n\n const componentColors = attachSemanticColors(\n mergedColors.component ?? {},\n (mergedTokens as any).component,\n );\n if (componentColors) {\n themeColors.component = componentColors;\n }\n\n const theme: TailwindConfig['theme'] = {\n // Safely map core token groups into Tailwind theme fields.\n // Use `as any` where necessary to avoid overfitting types right now.\n colors: themeColors,\n spacing: (mergedTokens as any).spacing ?? {},\n borderRadius: (mergedTokens as any).radii ?? {},\n boxShadow: (mergedTokens as any).shadows ?? {},\n fontFamily: (mergedTokens as any).typography?.families ?? {},\n };\n\n return { theme };\n}\n","import type { Config as TailwindConfig } from 'tailwindcss';\nimport plugin from 'tailwindcss/plugin';\nimport { spectreTokens } from '../tokens';\nimport { createSpectreTailwindTheme } from './theme';\n\nconst { theme } = createSpectreTailwindTheme({\n tokens: spectreTokens,\n});\n\nconst resolveTokenValue = (value: unknown, fallback?: string): string | undefined => {\n if (typeof value === 'string') {\n return value;\n }\n\n if (value && typeof value === 'object') {\n const maybeDefault = (value as Record<string, unknown>).default;\n if (typeof maybeDefault === 'string') {\n return maybeDefault;\n }\n\n const firstEntry = Object.values(value as Record<string, unknown>).find(\n (entry) => typeof entry === 'string',\n );\n if (typeof firstEntry === 'string') {\n return firstEntry;\n }\n }\n\n return fallback;\n};\n\nconst semanticUtilities = plugin(({ addUtilities }) => {\n const tokens = spectreTokens as any;\n const neutralScale = tokens?.colors?.neutral ?? {};\n const formDefault = tokens?.forms?.default ?? {};\n\n const surfaceTokens = tokens?.surface ?? {};\n const textTokens = tokens?.text ?? {};\n\n const surfacePage = resolveTokenValue(\n surfaceTokens.page,\n neutralScale['50'],\n );\n const surfaceCard = resolveTokenValue(\n surfaceTokens.card,\n formDefault.bg ?? surfacePage ?? neutralScale['50'],\n );\n const surfaceInput = resolveTokenValue(\n surfaceTokens.input,\n formDefault.bg ?? surfaceCard ?? surfacePage,\n );\n\n const textOnPage = resolveTokenValue(\n textTokens?.on?.page ?? textTokens?.onPage,\n neutralScale['900'] ?? formDefault.text,\n );\n const textOnSurface = resolveTokenValue(\n textTokens?.on?.surface ?? textTokens?.onSurface,\n formDefault.text ?? textOnPage ?? neutralScale['900'],\n );\n\n const utilities: Record<string, Record<string, string>> = {};\n\n if (surfacePage) {\n utilities['.bg-surface-page'] = { backgroundColor: surfacePage };\n }\n\n if (surfaceCard) {\n utilities['.bg-surface-card'] = { backgroundColor: surfaceCard };\n }\n\n if (surfaceInput) {\n utilities['.bg-surface-input'] = { backgroundColor: surfaceInput };\n }\n\n if (textOnPage) {\n utilities['.text-on-page'] = { color: textOnPage };\n }\n\n if (textOnSurface) {\n utilities['.text-on-surface'] = { color: textOnSurface };\n }\n\n addUtilities(utilities);\n});\n\nexport const spectrePreset: TailwindConfig = {\n // Required for Tailwind's Config type with exactOptionalPropertyTypes\n content: [],\n theme: theme ?? {},\n plugins: [semanticUtilities],\n};\n\nexport const spectreTailwindPreset: TailwindConfig = spectrePreset;\n","export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\nexport type ButtonTone = 'default' | 'success' | 'warning' | 'danger';\n\nexport interface ButtonRecipeOptions {\n variant?: ButtonVariant;\n size?: ButtonSize;\n tone?: ButtonTone;\n fullWidth?: boolean;\n loading?: boolean;\n disabled?: boolean;\n iconOnly?: boolean;\n}\n\n/**\n * Generate Spectre button classes.\n *\n * Rules:\n * - Base: \"sp-btn\"\n * - Variant: \"sp-btn--primary\" / \"sp-btn--secondary\" / \"sp-btn--ghost\" / \"sp-btn--danger\"\n * - default variant is \"primary\"\n * - Size: \"sp-btn--sm\" / \"sp-btn--md\" / \"sp-btn--lg\"\n * - default size is \"md\"\n * - Tone: \"sp-btn--tone-success\" / \"sp-btn--tone-warning\" / \"sp-btn--tone-danger\"\n * - default tone is \"default\" (no tone class)\n * - fullWidth: add \"sp-btn--full\"\n * - loading: add \"sp-btn--loading\"\n * - disabled: add \"sp-btn--disabled\"\n * - iconOnly: add \"sp-btn--icon\"\n *\n * Must return a single space-joined, trimmed class string.\n */\nexport function getButtonClasses(opts: ButtonRecipeOptions = {}): string {\n const {\n variant = 'primary',\n size = 'md',\n tone = 'default',\n fullWidth = false,\n loading = false,\n disabled = false,\n iconOnly = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-btn');\n\n // Variant\n const variantMap: Record<ButtonVariant, string> = {\n primary: 'sp-btn--primary',\n secondary: 'sp-btn--secondary',\n ghost: 'sp-btn--ghost',\n danger: 'sp-btn--danger',\n };\n classes.push(variantMap[variant]);\n\n // Size\n const sizeMap: Record<ButtonSize, string> = {\n sm: 'sp-btn--sm',\n md: 'sp-btn--md',\n lg: 'sp-btn--lg',\n };\n classes.push(sizeMap[size]);\n\n // Tone (optional)\n if (tone !== 'default') {\n const toneMap: Record<Exclude<ButtonTone, 'default'>, string> = {\n success: 'sp-btn--tone-success',\n warning: 'sp-btn--tone-warning',\n danger: 'sp-btn--tone-danger',\n };\n classes.push(toneMap[tone as Exclude<ButtonTone, 'default'>]);\n }\n\n // Flags\n if (fullWidth) classes.push('sp-btn--full');\n if (loading) classes.push('sp-btn--loading');\n if (disabled) classes.push('sp-btn--disabled');\n if (iconOnly) classes.push('sp-btn--icon');\n\n // Final class string\n return classes.filter(Boolean).join(' ').trim();\n}\n","export type CardVariant = 'elevated' | 'outline' | 'ghost';\n\nexport interface CardRecipeOptions {\n variant?: CardVariant;\n interactive?: boolean; // hover/focus styles\n padded?: boolean; // apply default padding\n fullHeight?: boolean;\n}\n\n/**\n * Generate Spectre card classes.\n *\n * Rules:\n * - Base class: \"sp-card\"\n * - Variant (default: elevated):\n * - \"sp-card--elevated\"\n * - \"sp-card--outline\"\n * - \"sp-card--ghost\"\n * - interactive: add \"sp-card--interactive\"\n * - padded: add \"sp-card--padded\"\n * - fullHeight: add \"sp-card--full\"\n */\nexport function getCardClasses(opts: CardRecipeOptions = {}): string {\n const {\n variant = 'elevated',\n interactive = false,\n padded = false,\n fullHeight = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-card');\n\n // Variant\n const variantMap: Record<CardVariant, string> = {\n elevated: 'sp-card--elevated',\n outline: 'sp-card--outline',\n ghost: 'sp-card--ghost',\n };\n classes.push(variantMap[variant]);\n\n // Flags\n if (interactive) classes.push('sp-card--interactive');\n if (padded) classes.push('sp-card--padded');\n if (fullHeight) classes.push('sp-card--full');\n\n return classes.filter(Boolean).join(' ').trim();\n}\n","export type InputState = 'default' | 'error' | 'success';\nexport type InputSize = 'sm' | 'md' | 'lg';\n\nexport interface InputRecipeOptions {\n state?: InputState;\n size?: InputSize;\n fullWidth?: boolean;\n}\n\n/**\n * Generate Spectre input classes.\n *\n * Rules:\n * - Base class: \"sp-input\"\n * - State:\n * - \"default\" => no state modifier\n * - \"error\" => \"sp-input--error\"\n * - \"success\" => \"sp-input--success\"\n * - Size (default: md):\n * - \"sp-input--sm\"\n * - \"sp-input--md\"\n * - \"sp-input--lg\"\n * - fullWidth: add \"sp-input--full\"\n */\nexport function getInputClasses(opts: InputRecipeOptions = {}): string {\n const {\n state = 'default',\n size = 'md',\n fullWidth = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-input');\n\n // State\n if (state === 'error') {\n classes.push('sp-input--error');\n } else if (state === 'success') {\n classes.push('sp-input--success');\n }\n\n // Size\n const sizeMap: Record<InputSize, string> = {\n sm: 'sp-input--sm',\n md: 'sp-input--md',\n lg: 'sp-input--lg',\n };\n classes.push(sizeMap[size]);\n\n // Flags\n if (fullWidth) {\n classes.push('sp-input--full');\n }\n\n return classes.filter(Boolean).join(' ').trim();\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import plugin from 'tailwindcss/plugin';
|
|
1
2
|
import { tokens } from '@phcdevworks/spectre-tokens';
|
|
2
3
|
export { tokens as spectreTokens } from '@phcdevworks/spectre-tokens';
|
|
3
4
|
|
|
@@ -18,10 +19,44 @@ function createSpectreTailwindTheme(options) {
|
|
|
18
19
|
...tokens,
|
|
19
20
|
...overrides ?? {}
|
|
20
21
|
};
|
|
22
|
+
const mergedColors = mergedTokens.colors ?? {};
|
|
23
|
+
const attachSemanticColors = (existing, semantic) => {
|
|
24
|
+
if (!semantic || Object.keys(semantic).length === 0) {
|
|
25
|
+
return Object.keys(existing).length > 0 ? existing : void 0;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
...existing,
|
|
29
|
+
...semantic
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
const themeColors = {
|
|
33
|
+
...mergedColors
|
|
34
|
+
};
|
|
35
|
+
const surfaceColors = attachSemanticColors(
|
|
36
|
+
mergedColors.surface ?? {},
|
|
37
|
+
mergedTokens.surface
|
|
38
|
+
);
|
|
39
|
+
if (surfaceColors) {
|
|
40
|
+
themeColors.surface = surfaceColors;
|
|
41
|
+
}
|
|
42
|
+
const textColors = attachSemanticColors(
|
|
43
|
+
mergedColors.text ?? {},
|
|
44
|
+
mergedTokens.text
|
|
45
|
+
);
|
|
46
|
+
if (textColors) {
|
|
47
|
+
themeColors.text = textColors;
|
|
48
|
+
}
|
|
49
|
+
const componentColors = attachSemanticColors(
|
|
50
|
+
mergedColors.component ?? {},
|
|
51
|
+
mergedTokens.component
|
|
52
|
+
);
|
|
53
|
+
if (componentColors) {
|
|
54
|
+
themeColors.component = componentColors;
|
|
55
|
+
}
|
|
21
56
|
const theme2 = {
|
|
22
57
|
// Safely map core token groups into Tailwind theme fields.
|
|
23
58
|
// Use `as any` where necessary to avoid overfitting types right now.
|
|
24
|
-
colors:
|
|
59
|
+
colors: themeColors,
|
|
25
60
|
spacing: mergedTokens.spacing ?? {},
|
|
26
61
|
borderRadius: mergedTokens.radii ?? {},
|
|
27
62
|
boxShadow: mergedTokens.shadows ?? {},
|
|
@@ -34,11 +69,73 @@ function createSpectreTailwindTheme(options) {
|
|
|
34
69
|
var { theme } = createSpectreTailwindTheme({
|
|
35
70
|
tokens: tokens
|
|
36
71
|
});
|
|
72
|
+
var resolveTokenValue = (value, fallback) => {
|
|
73
|
+
if (typeof value === "string") {
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
if (value && typeof value === "object") {
|
|
77
|
+
const maybeDefault = value.default;
|
|
78
|
+
if (typeof maybeDefault === "string") {
|
|
79
|
+
return maybeDefault;
|
|
80
|
+
}
|
|
81
|
+
const firstEntry = Object.values(value).find(
|
|
82
|
+
(entry) => typeof entry === "string"
|
|
83
|
+
);
|
|
84
|
+
if (typeof firstEntry === "string") {
|
|
85
|
+
return firstEntry;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return fallback;
|
|
89
|
+
};
|
|
90
|
+
var semanticUtilities = plugin(({ addUtilities }) => {
|
|
91
|
+
const tokens$1 = tokens;
|
|
92
|
+
const neutralScale = tokens$1?.colors?.neutral ?? {};
|
|
93
|
+
const formDefault = tokens$1?.forms?.default ?? {};
|
|
94
|
+
const surfaceTokens = tokens$1?.surface ?? {};
|
|
95
|
+
const textTokens = tokens$1?.text ?? {};
|
|
96
|
+
const surfacePage = resolveTokenValue(
|
|
97
|
+
surfaceTokens.page,
|
|
98
|
+
neutralScale["50"]
|
|
99
|
+
);
|
|
100
|
+
const surfaceCard = resolveTokenValue(
|
|
101
|
+
surfaceTokens.card,
|
|
102
|
+
formDefault.bg ?? surfacePage ?? neutralScale["50"]
|
|
103
|
+
);
|
|
104
|
+
const surfaceInput = resolveTokenValue(
|
|
105
|
+
surfaceTokens.input,
|
|
106
|
+
formDefault.bg ?? surfaceCard ?? surfacePage
|
|
107
|
+
);
|
|
108
|
+
const textOnPage = resolveTokenValue(
|
|
109
|
+
textTokens?.on?.page ?? textTokens?.onPage,
|
|
110
|
+
neutralScale["900"] ?? formDefault.text
|
|
111
|
+
);
|
|
112
|
+
const textOnSurface = resolveTokenValue(
|
|
113
|
+
textTokens?.on?.surface ?? textTokens?.onSurface,
|
|
114
|
+
formDefault.text ?? textOnPage ?? neutralScale["900"]
|
|
115
|
+
);
|
|
116
|
+
const utilities = {};
|
|
117
|
+
if (surfacePage) {
|
|
118
|
+
utilities[".bg-surface-page"] = { backgroundColor: surfacePage };
|
|
119
|
+
}
|
|
120
|
+
if (surfaceCard) {
|
|
121
|
+
utilities[".bg-surface-card"] = { backgroundColor: surfaceCard };
|
|
122
|
+
}
|
|
123
|
+
if (surfaceInput) {
|
|
124
|
+
utilities[".bg-surface-input"] = { backgroundColor: surfaceInput };
|
|
125
|
+
}
|
|
126
|
+
if (textOnPage) {
|
|
127
|
+
utilities[".text-on-page"] = { color: textOnPage };
|
|
128
|
+
}
|
|
129
|
+
if (textOnSurface) {
|
|
130
|
+
utilities[".text-on-surface"] = { color: textOnSurface };
|
|
131
|
+
}
|
|
132
|
+
addUtilities(utilities);
|
|
133
|
+
});
|
|
37
134
|
var spectrePreset = {
|
|
38
135
|
// Required for Tailwind's Config type with exactOptionalPropertyTypes
|
|
39
136
|
content: [],
|
|
40
137
|
theme: theme ?? {},
|
|
41
|
-
plugins: []
|
|
138
|
+
plugins: [semanticUtilities]
|
|
42
139
|
};
|
|
43
140
|
|
|
44
141
|
// src/recipes/button.ts
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/css-constants.ts","../src/tailwind/theme.ts","../src/tailwind/preset.ts","../src/recipes/button.ts","../src/recipes/card.ts","../src/recipes/input.ts"],"names":["theme","spectreTokens"],"mappings":"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","file":"index.js","sourcesContent":["export const spectreBaseStylesPath = \"@phcdevworks/spectre-ui/dist/base.css\";\nexport const spectreComponentsStylesPath = \"@phcdevworks/spectre-ui/dist/components.css\";\nexport const spectreUtilitiesStylesPath = \"@phcdevworks/spectre-ui/dist/utilities.css\";\n\nexport const spectreStyles = {\n base: spectreBaseStylesPath,\n components: spectreComponentsStylesPath,\n utilities: spectreUtilitiesStylesPath,\n};\n","import type { Config as TailwindConfig } from 'tailwindcss';\nimport type { SpectreTokens } from '../tokens';\n\nexport interface SpectreTailwindTheme {\n theme: TailwindConfig['theme'];\n}\n\nexport interface CreateSpectreTailwindThemeOptions {\n tokens: SpectreTokens;\n overrides?: Partial<SpectreTokens>;\n}\n\nexport function createSpectreTailwindTheme(\n options: CreateSpectreTailwindThemeOptions,\n): SpectreTailwindTheme {\n const { tokens, overrides } = options;\n\n // Shallow merge overrides into tokens\n const mergedTokens: SpectreTokens = {\n ...tokens,\n ...(overrides ?? {}),\n };\n\n const theme: TailwindConfig['theme'] = {\n // Safely map core token groups into Tailwind theme fields.\n // Use `as any` where necessary to avoid overfitting types right now.\n colors: (mergedTokens as any).colors ?? {},\n spacing: (mergedTokens as any).spacing ?? {},\n borderRadius: (mergedTokens as any).radii ?? {},\n boxShadow: (mergedTokens as any).shadows ?? {},\n fontFamily: (mergedTokens as any).typography?.families ?? {},\n };\n\n return { theme };\n}\n","import type { Config as TailwindConfig } from 'tailwindcss';\nimport { spectreTokens } from '../tokens';\nimport { createSpectreTailwindTheme } from './theme';\n\nconst { theme } = createSpectreTailwindTheme({\n tokens: spectreTokens,\n});\n\nexport const spectrePreset: TailwindConfig = {\n // Required for Tailwind's Config type with exactOptionalPropertyTypes\n content: [],\n theme: theme ?? {},\n plugins: [],\n};\n\nexport const spectreTailwindPreset: TailwindConfig = spectrePreset;\n","export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\nexport type ButtonTone = 'default' | 'success' | 'warning' | 'danger';\n\nexport interface ButtonRecipeOptions {\n variant?: ButtonVariant;\n size?: ButtonSize;\n tone?: ButtonTone;\n fullWidth?: boolean;\n loading?: boolean;\n disabled?: boolean;\n iconOnly?: boolean;\n}\n\n/**\n * Generate Spectre button classes.\n *\n * Rules:\n * - Base: \"sp-btn\"\n * - Variant: \"sp-btn--primary\" / \"sp-btn--secondary\" / \"sp-btn--ghost\" / \"sp-btn--danger\"\n * - default variant is \"primary\"\n * - Size: \"sp-btn--sm\" / \"sp-btn--md\" / \"sp-btn--lg\"\n * - default size is \"md\"\n * - Tone: \"sp-btn--tone-success\" / \"sp-btn--tone-warning\" / \"sp-btn--tone-danger\"\n * - default tone is \"default\" (no tone class)\n * - fullWidth: add \"sp-btn--full\"\n * - loading: add \"sp-btn--loading\"\n * - disabled: add \"sp-btn--disabled\"\n * - iconOnly: add \"sp-btn--icon\"\n *\n * Must return a single space-joined, trimmed class string.\n */\nexport function getButtonClasses(opts: ButtonRecipeOptions = {}): string {\n const {\n variant = 'primary',\n size = 'md',\n tone = 'default',\n fullWidth = false,\n loading = false,\n disabled = false,\n iconOnly = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-btn');\n\n // Variant\n const variantMap: Record<ButtonVariant, string> = {\n primary: 'sp-btn--primary',\n secondary: 'sp-btn--secondary',\n ghost: 'sp-btn--ghost',\n danger: 'sp-btn--danger',\n };\n classes.push(variantMap[variant]);\n\n // Size\n const sizeMap: Record<ButtonSize, string> = {\n sm: 'sp-btn--sm',\n md: 'sp-btn--md',\n lg: 'sp-btn--lg',\n };\n classes.push(sizeMap[size]);\n\n // Tone (optional)\n if (tone !== 'default') {\n const toneMap: Record<Exclude<ButtonTone, 'default'>, string> = {\n success: 'sp-btn--tone-success',\n warning: 'sp-btn--tone-warning',\n danger: 'sp-btn--tone-danger',\n };\n classes.push(toneMap[tone as Exclude<ButtonTone, 'default'>]);\n }\n\n // Flags\n if (fullWidth) classes.push('sp-btn--full');\n if (loading) classes.push('sp-btn--loading');\n if (disabled) classes.push('sp-btn--disabled');\n if (iconOnly) classes.push('sp-btn--icon');\n\n // Final class string\n return classes.filter(Boolean).join(' ').trim();\n}\n","export type CardVariant = 'elevated' | 'outline' | 'ghost';\n\nexport interface CardRecipeOptions {\n variant?: CardVariant;\n interactive?: boolean; // hover/focus styles\n padded?: boolean; // apply default padding\n fullHeight?: boolean;\n}\n\n/**\n * Generate Spectre card classes.\n *\n * Rules:\n * - Base class: \"sp-card\"\n * - Variant (default: elevated):\n * - \"sp-card--elevated\"\n * - \"sp-card--outline\"\n * - \"sp-card--ghost\"\n * - interactive: add \"sp-card--interactive\"\n * - padded: add \"sp-card--padded\"\n * - fullHeight: add \"sp-card--full\"\n */\nexport function getCardClasses(opts: CardRecipeOptions = {}): string {\n const {\n variant = 'elevated',\n interactive = false,\n padded = false,\n fullHeight = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-card');\n\n // Variant\n const variantMap: Record<CardVariant, string> = {\n elevated: 'sp-card--elevated',\n outline: 'sp-card--outline',\n ghost: 'sp-card--ghost',\n };\n classes.push(variantMap[variant]);\n\n // Flags\n if (interactive) classes.push('sp-card--interactive');\n if (padded) classes.push('sp-card--padded');\n if (fullHeight) classes.push('sp-card--full');\n\n return classes.filter(Boolean).join(' ').trim();\n}\n","export type InputState = 'default' | 'error' | 'success';\nexport type InputSize = 'sm' | 'md' | 'lg';\n\nexport interface InputRecipeOptions {\n state?: InputState;\n size?: InputSize;\n fullWidth?: boolean;\n}\n\n/**\n * Generate Spectre input classes.\n *\n * Rules:\n * - Base class: \"sp-input\"\n * - State:\n * - \"default\" => no state modifier\n * - \"error\" => \"sp-input--error\"\n * - \"success\" => \"sp-input--success\"\n * - Size (default: md):\n * - \"sp-input--sm\"\n * - \"sp-input--md\"\n * - \"sp-input--lg\"\n * - fullWidth: add \"sp-input--full\"\n */\nexport function getInputClasses(opts: InputRecipeOptions = {}): string {\n const {\n state = 'default',\n size = 'md',\n fullWidth = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-input');\n\n // State\n if (state === 'error') {\n classes.push('sp-input--error');\n } else if (state === 'success') {\n classes.push('sp-input--success');\n }\n\n // Size\n const sizeMap: Record<InputSize, string> = {\n sm: 'sp-input--sm',\n md: 'sp-input--md',\n lg: 'sp-input--lg',\n };\n classes.push(sizeMap[size]);\n\n // Flags\n if (fullWidth) {\n classes.push('sp-input--full');\n }\n\n return classes.filter(Boolean).join(' ').trim();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/css-constants.ts","../src/tailwind/theme.ts","../src/tailwind/preset.ts","../src/recipes/button.ts","../src/recipes/card.ts","../src/recipes/input.ts"],"names":["theme","spectreTokens","tokens"],"mappings":"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","file":"index.js","sourcesContent":["export const spectreBaseStylesPath = \"@phcdevworks/spectre-ui/dist/base.css\";\nexport const spectreComponentsStylesPath = \"@phcdevworks/spectre-ui/dist/components.css\";\nexport const spectreUtilitiesStylesPath = \"@phcdevworks/spectre-ui/dist/utilities.css\";\n\nexport const spectreStyles = {\n base: spectreBaseStylesPath,\n components: spectreComponentsStylesPath,\n utilities: spectreUtilitiesStylesPath,\n};\n","import type { Config as TailwindConfig } from 'tailwindcss';\nimport type { SpectreTokens } from '../tokens';\n\nexport interface SpectreTailwindTheme {\n theme: TailwindConfig['theme'];\n}\n\nexport interface CreateSpectreTailwindThemeOptions {\n tokens: SpectreTokens;\n overrides?: Partial<SpectreTokens>;\n}\n\nexport function createSpectreTailwindTheme(\n options: CreateSpectreTailwindThemeOptions,\n): SpectreTailwindTheme {\n const { tokens, overrides } = options;\n\n // Shallow merge overrides into tokens\n const mergedTokens: SpectreTokens = {\n ...tokens,\n ...(overrides ?? {}),\n };\n\n const mergedColors = (mergedTokens as any).colors ?? {};\n\n const attachSemanticColors = (\n existing: Record<string, any>,\n semantic: Record<string, any> | undefined,\n ) => {\n if (!semantic || Object.keys(semantic).length === 0) {\n return Object.keys(existing).length > 0 ? existing : undefined;\n }\n\n return {\n ...existing,\n ...semantic,\n };\n };\n\n const themeColors: Record<string, any> = {\n ...mergedColors,\n };\n\n const surfaceColors = attachSemanticColors(\n mergedColors.surface ?? {},\n (mergedTokens as any).surface,\n );\n if (surfaceColors) {\n themeColors.surface = surfaceColors;\n }\n\n const textColors = attachSemanticColors(\n mergedColors.text ?? {},\n (mergedTokens as any).text,\n );\n if (textColors) {\n themeColors.text = textColors;\n }\n\n const componentColors = attachSemanticColors(\n mergedColors.component ?? {},\n (mergedTokens as any).component,\n );\n if (componentColors) {\n themeColors.component = componentColors;\n }\n\n const theme: TailwindConfig['theme'] = {\n // Safely map core token groups into Tailwind theme fields.\n // Use `as any` where necessary to avoid overfitting types right now.\n colors: themeColors,\n spacing: (mergedTokens as any).spacing ?? {},\n borderRadius: (mergedTokens as any).radii ?? {},\n boxShadow: (mergedTokens as any).shadows ?? {},\n fontFamily: (mergedTokens as any).typography?.families ?? {},\n };\n\n return { theme };\n}\n","import type { Config as TailwindConfig } from 'tailwindcss';\nimport plugin from 'tailwindcss/plugin';\nimport { spectreTokens } from '../tokens';\nimport { createSpectreTailwindTheme } from './theme';\n\nconst { theme } = createSpectreTailwindTheme({\n tokens: spectreTokens,\n});\n\nconst resolveTokenValue = (value: unknown, fallback?: string): string | undefined => {\n if (typeof value === 'string') {\n return value;\n }\n\n if (value && typeof value === 'object') {\n const maybeDefault = (value as Record<string, unknown>).default;\n if (typeof maybeDefault === 'string') {\n return maybeDefault;\n }\n\n const firstEntry = Object.values(value as Record<string, unknown>).find(\n (entry) => typeof entry === 'string',\n );\n if (typeof firstEntry === 'string') {\n return firstEntry;\n }\n }\n\n return fallback;\n};\n\nconst semanticUtilities = plugin(({ addUtilities }) => {\n const tokens = spectreTokens as any;\n const neutralScale = tokens?.colors?.neutral ?? {};\n const formDefault = tokens?.forms?.default ?? {};\n\n const surfaceTokens = tokens?.surface ?? {};\n const textTokens = tokens?.text ?? {};\n\n const surfacePage = resolveTokenValue(\n surfaceTokens.page,\n neutralScale['50'],\n );\n const surfaceCard = resolveTokenValue(\n surfaceTokens.card,\n formDefault.bg ?? surfacePage ?? neutralScale['50'],\n );\n const surfaceInput = resolveTokenValue(\n surfaceTokens.input,\n formDefault.bg ?? surfaceCard ?? surfacePage,\n );\n\n const textOnPage = resolveTokenValue(\n textTokens?.on?.page ?? textTokens?.onPage,\n neutralScale['900'] ?? formDefault.text,\n );\n const textOnSurface = resolveTokenValue(\n textTokens?.on?.surface ?? textTokens?.onSurface,\n formDefault.text ?? textOnPage ?? neutralScale['900'],\n );\n\n const utilities: Record<string, Record<string, string>> = {};\n\n if (surfacePage) {\n utilities['.bg-surface-page'] = { backgroundColor: surfacePage };\n }\n\n if (surfaceCard) {\n utilities['.bg-surface-card'] = { backgroundColor: surfaceCard };\n }\n\n if (surfaceInput) {\n utilities['.bg-surface-input'] = { backgroundColor: surfaceInput };\n }\n\n if (textOnPage) {\n utilities['.text-on-page'] = { color: textOnPage };\n }\n\n if (textOnSurface) {\n utilities['.text-on-surface'] = { color: textOnSurface };\n }\n\n addUtilities(utilities);\n});\n\nexport const spectrePreset: TailwindConfig = {\n // Required for Tailwind's Config type with exactOptionalPropertyTypes\n content: [],\n theme: theme ?? {},\n plugins: [semanticUtilities],\n};\n\nexport const spectreTailwindPreset: TailwindConfig = spectrePreset;\n","export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\nexport type ButtonTone = 'default' | 'success' | 'warning' | 'danger';\n\nexport interface ButtonRecipeOptions {\n variant?: ButtonVariant;\n size?: ButtonSize;\n tone?: ButtonTone;\n fullWidth?: boolean;\n loading?: boolean;\n disabled?: boolean;\n iconOnly?: boolean;\n}\n\n/**\n * Generate Spectre button classes.\n *\n * Rules:\n * - Base: \"sp-btn\"\n * - Variant: \"sp-btn--primary\" / \"sp-btn--secondary\" / \"sp-btn--ghost\" / \"sp-btn--danger\"\n * - default variant is \"primary\"\n * - Size: \"sp-btn--sm\" / \"sp-btn--md\" / \"sp-btn--lg\"\n * - default size is \"md\"\n * - Tone: \"sp-btn--tone-success\" / \"sp-btn--tone-warning\" / \"sp-btn--tone-danger\"\n * - default tone is \"default\" (no tone class)\n * - fullWidth: add \"sp-btn--full\"\n * - loading: add \"sp-btn--loading\"\n * - disabled: add \"sp-btn--disabled\"\n * - iconOnly: add \"sp-btn--icon\"\n *\n * Must return a single space-joined, trimmed class string.\n */\nexport function getButtonClasses(opts: ButtonRecipeOptions = {}): string {\n const {\n variant = 'primary',\n size = 'md',\n tone = 'default',\n fullWidth = false,\n loading = false,\n disabled = false,\n iconOnly = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-btn');\n\n // Variant\n const variantMap: Record<ButtonVariant, string> = {\n primary: 'sp-btn--primary',\n secondary: 'sp-btn--secondary',\n ghost: 'sp-btn--ghost',\n danger: 'sp-btn--danger',\n };\n classes.push(variantMap[variant]);\n\n // Size\n const sizeMap: Record<ButtonSize, string> = {\n sm: 'sp-btn--sm',\n md: 'sp-btn--md',\n lg: 'sp-btn--lg',\n };\n classes.push(sizeMap[size]);\n\n // Tone (optional)\n if (tone !== 'default') {\n const toneMap: Record<Exclude<ButtonTone, 'default'>, string> = {\n success: 'sp-btn--tone-success',\n warning: 'sp-btn--tone-warning',\n danger: 'sp-btn--tone-danger',\n };\n classes.push(toneMap[tone as Exclude<ButtonTone, 'default'>]);\n }\n\n // Flags\n if (fullWidth) classes.push('sp-btn--full');\n if (loading) classes.push('sp-btn--loading');\n if (disabled) classes.push('sp-btn--disabled');\n if (iconOnly) classes.push('sp-btn--icon');\n\n // Final class string\n return classes.filter(Boolean).join(' ').trim();\n}\n","export type CardVariant = 'elevated' | 'outline' | 'ghost';\n\nexport interface CardRecipeOptions {\n variant?: CardVariant;\n interactive?: boolean; // hover/focus styles\n padded?: boolean; // apply default padding\n fullHeight?: boolean;\n}\n\n/**\n * Generate Spectre card classes.\n *\n * Rules:\n * - Base class: \"sp-card\"\n * - Variant (default: elevated):\n * - \"sp-card--elevated\"\n * - \"sp-card--outline\"\n * - \"sp-card--ghost\"\n * - interactive: add \"sp-card--interactive\"\n * - padded: add \"sp-card--padded\"\n * - fullHeight: add \"sp-card--full\"\n */\nexport function getCardClasses(opts: CardRecipeOptions = {}): string {\n const {\n variant = 'elevated',\n interactive = false,\n padded = false,\n fullHeight = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-card');\n\n // Variant\n const variantMap: Record<CardVariant, string> = {\n elevated: 'sp-card--elevated',\n outline: 'sp-card--outline',\n ghost: 'sp-card--ghost',\n };\n classes.push(variantMap[variant]);\n\n // Flags\n if (interactive) classes.push('sp-card--interactive');\n if (padded) classes.push('sp-card--padded');\n if (fullHeight) classes.push('sp-card--full');\n\n return classes.filter(Boolean).join(' ').trim();\n}\n","export type InputState = 'default' | 'error' | 'success';\nexport type InputSize = 'sm' | 'md' | 'lg';\n\nexport interface InputRecipeOptions {\n state?: InputState;\n size?: InputSize;\n fullWidth?: boolean;\n}\n\n/**\n * Generate Spectre input classes.\n *\n * Rules:\n * - Base class: \"sp-input\"\n * - State:\n * - \"default\" => no state modifier\n * - \"error\" => \"sp-input--error\"\n * - \"success\" => \"sp-input--success\"\n * - Size (default: md):\n * - \"sp-input--sm\"\n * - \"sp-input--md\"\n * - \"sp-input--lg\"\n * - fullWidth: add \"sp-input--full\"\n */\nexport function getInputClasses(opts: InputRecipeOptions = {}): string {\n const {\n state = 'default',\n size = 'md',\n fullWidth = false,\n } = opts;\n\n const classes: string[] = [];\n\n // Base\n classes.push('sp-input');\n\n // State\n if (state === 'error') {\n classes.push('sp-input--error');\n } else if (state === 'success') {\n classes.push('sp-input--success');\n }\n\n // Size\n const sizeMap: Record<InputSize, string> = {\n sm: 'sp-input--sm',\n md: 'sp-input--md',\n lg: 'sp-input--lg',\n };\n classes.push(sizeMap[size]);\n\n // Flags\n if (fullWidth) {\n classes.push('sp-input--full');\n }\n\n return classes.filter(Boolean).join(' ').trim();\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,20 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phcdevworks/spectre-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Framework-agnostic UI layer for the Spectre design system. Provides base CSS, component classes, utilities, and a Tailwind preset powered by @phcdevworks/spectre-tokens.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"phcdevworks",
|
|
7
|
+
"spectre",
|
|
8
|
+
"spectre-ui",
|
|
9
|
+
"design-system",
|
|
10
|
+
"design-tokens",
|
|
11
|
+
"component-library",
|
|
12
|
+
"ui-library",
|
|
13
|
+
"ui-components",
|
|
14
|
+
"tailwindcss",
|
|
15
|
+
"css-utilities",
|
|
16
|
+
"css-framework",
|
|
17
|
+
"tokens",
|
|
18
|
+
"utilities"
|
|
19
|
+
],
|
|
20
|
+
"author": "PHCDevworks",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"funding": [
|
|
23
|
+
{
|
|
24
|
+
"type": "github",
|
|
25
|
+
"url": "https://github.com/sponsors/phcdevworks"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "buymeacoffee",
|
|
29
|
+
"url": "https://buymeacoffee.com/phcdevworks"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/phcdevworks/spectre-ui.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/phcdevworks/spectre-ui/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/phcdevworks/spectre-ui#readme",
|
|
40
|
+
"type": "module",
|
|
5
41
|
"main": "./dist/index.cjs",
|
|
6
42
|
"module": "./dist/index.js",
|
|
7
43
|
"types": "./dist/index.d.ts",
|
|
8
|
-
"type": "module",
|
|
9
44
|
"exports": {
|
|
10
45
|
".": {
|
|
11
46
|
"types": "./dist/index.d.ts",
|
|
12
47
|
"import": "./dist/index.js",
|
|
13
48
|
"require": "./dist/index.cjs"
|
|
14
49
|
},
|
|
15
|
-
"./dist/base.css": "./dist/base.css",
|
|
16
|
-
"./dist/components.css": "./dist/components.css",
|
|
17
|
-
"./dist/utilities.css": "./dist/utilities.css",
|
|
18
50
|
"./base.css": "./dist/base.css",
|
|
19
51
|
"./components.css": "./dist/components.css",
|
|
20
52
|
"./utilities.css": "./dist/utilities.css"
|
|
@@ -30,26 +62,6 @@
|
|
|
30
62
|
"dev": "tsup --config tsup.config.ts --watch",
|
|
31
63
|
"clean": "rm -rf dist"
|
|
32
64
|
},
|
|
33
|
-
"repository": {
|
|
34
|
-
"type": "git",
|
|
35
|
-
"url": "git+https://github.com/phcdevworks/spectre-ui.git"
|
|
36
|
-
},
|
|
37
|
-
"keywords": [
|
|
38
|
-
"spectre",
|
|
39
|
-
"design-system",
|
|
40
|
-
"tailwindcss",
|
|
41
|
-
"components",
|
|
42
|
-
"utilities",
|
|
43
|
-
"tokens",
|
|
44
|
-
"ui-library",
|
|
45
|
-
"phcdevworks"
|
|
46
|
-
],
|
|
47
|
-
"author": "PHCDevworks",
|
|
48
|
-
"license": "MIT",
|
|
49
|
-
"bugs": {
|
|
50
|
-
"url": "https://github.com/phcdevworks/spectre-ui/issues"
|
|
51
|
-
},
|
|
52
|
-
"homepage": "https://github.com/phcdevworks/spectre-ui#readme",
|
|
53
65
|
"publishConfig": {
|
|
54
66
|
"access": "public"
|
|
55
67
|
},
|
|
@@ -57,8 +69,7 @@
|
|
|
57
69
|
"tailwindcss": "^3.4.0 || ^4.0.0"
|
|
58
70
|
},
|
|
59
71
|
"dependencies": {
|
|
60
|
-
"@phcdevworks/spectre-tokens": "^0.0.
|
|
61
|
-
"user": "^0.0.0"
|
|
72
|
+
"@phcdevworks/spectre-tokens": "^0.0.3"
|
|
62
73
|
},
|
|
63
74
|
"devDependencies": {
|
|
64
75
|
"autoprefixer": "^10.4.20",
|