@purestack/ts-css 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ahmed Yasin Koculu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,301 @@
1
+ # @purestack/ts-css
2
+
3
+ Type-safe CSS builder for TypeScript. `ts-css` lets you define selectors, declarations, media queries, and CSS variables with a fluent API, then serialize to CSS (optionally via Prettier). It is designed for generating styles in build tools or server-side environments with no DOM dependency.
4
+
5
+ ## Why this package exists
6
+
7
+ - Author CSS as TypeScript instead of strings.
8
+ - Use typed properties via `CSSProps` for safer style authoring.
9
+ - Compose selectors and media queries programmatically.
10
+ - Produce deterministic CSS output you can prettify.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @purestack/ts-css
16
+ ```
17
+
18
+ ```bash
19
+ yarn add @purestack/ts-css
20
+ ```
21
+
22
+ ```bash
23
+ pnpm add @purestack/ts-css
24
+ ```
25
+
26
+ ## Quick Example
27
+
28
+ ```ts
29
+ import { s } from '@purestack/ts-css'
30
+
31
+ const style = s()
32
+
33
+ style
34
+ .select('body')
35
+ .css({
36
+ margin: '0',
37
+ fontFamily: "system-ui, -apple-system, 'Segoe UI', sans-serif",
38
+ })
39
+
40
+ style
41
+ .select('.button')
42
+ .css({
43
+ background: '#1e90ff',
44
+ color: '#fff',
45
+ padding: '0.5rem 1rem',
46
+ borderRadius: '0.5rem',
47
+ })
48
+
49
+ const css = style.toPrettyCSS()
50
+ console.log(await css)
51
+ ```
52
+
53
+ ## Core Concepts
54
+
55
+ ### `s(selector?)`
56
+
57
+ Creates a root `Style` instance. If you pass a selector, it becomes the root selector; otherwise it starts empty.
58
+
59
+ ```ts
60
+ const root = s()
61
+ const button = root.select('.button')
62
+ ```
63
+
64
+ ### Fluent Rule Building
65
+
66
+ Rules are created via `.select()` and values are set by `.css()` or `.set()`.
67
+
68
+ ```ts
69
+ const style = s()
70
+ style.select('.card').css({
71
+ padding: '1rem',
72
+ border: '1px solid #ddd',
73
+ })
74
+ ```
75
+
76
+ ### Selector Composition
77
+
78
+ `.select()` automatically inserts a space unless you use a combinator or a leading pseudo selector.
79
+
80
+ ```ts
81
+ const root = s('.card')
82
+ root.select('> .title') // ".card > .title"
83
+ root.select(':hover') // ".card:hover"
84
+ root.select('.icon') // ".card .icon"
85
+ ```
86
+
87
+ ### Media Queries
88
+
89
+ Use `.media()` to scope rules under `@media`.
90
+
91
+ ```ts
92
+ const style = s('.layout')
93
+ style.css({ display: 'grid', gap: '1rem' })
94
+ style.media('max-width: 720px').css({ display: 'block' })
95
+ ```
96
+
97
+ ### CSS Variables via `autoVar`
98
+
99
+ Values beginning with `$name` or `--name` are automatically converted to `var(...)`.
100
+
101
+ ```ts
102
+ const style = s('.btn').css({
103
+ color: '$text',
104
+ background: '--brand, #ff44aa',
105
+ })
106
+ // => color: var(--text); background: var(--brand, #ff44aa);
107
+ ```
108
+
109
+ ### Reuse Styles
110
+
111
+ Use `.use()` to merge declarations from another style into the current one.
112
+
113
+ ```ts
114
+ const base = s().css({ fontSize: '14px', lineHeight: '1.4' })
115
+ const item = s('.item').use(base).css({ color: '#333' })
116
+ ```
117
+
118
+ ## Extended Examples
119
+
120
+ ### Nested Selectors + Components
121
+
122
+ ```ts
123
+ import { s } from '@purestack/ts-css'
124
+
125
+ const style = s('.card')
126
+ style.css({
127
+ borderRadius: '12px',
128
+ border: '1px solid #e5e7eb',
129
+ padding: '1rem',
130
+ })
131
+
132
+ style.select('> .title').css({
133
+ fontWeight: '600',
134
+ marginBottom: '0.5rem',
135
+ })
136
+
137
+ style.select('.actions').css({
138
+ display: 'flex',
139
+ gap: '0.5rem',
140
+ })
141
+
142
+ style.select('.actions > .btn').css({
143
+ borderRadius: '999px',
144
+ padding: '0.4rem 0.9rem',
145
+ })
146
+ ```
147
+
148
+ ### Media Queries + Reuse
149
+
150
+ ```ts
151
+ import { s } from '@purestack/ts-css'
152
+
153
+ const baseText = s().css({
154
+ fontSize: '16px',
155
+ lineHeight: '1.5',
156
+ })
157
+
158
+ const layout = s('.layout').use(baseText).css({
159
+ display: 'grid',
160
+ gridTemplateColumns: '1fr 1fr',
161
+ gap: '1rem',
162
+ })
163
+
164
+ layout.media('max-width: 800px').css({
165
+ gridTemplateColumns: '1fr',
166
+ })
167
+ ```
168
+
169
+ ### Theming with CSS Variables
170
+
171
+ ```ts
172
+ import { s } from '@purestack/ts-css'
173
+
174
+ const theme = s(':root').css({
175
+ '--brand': '#ff44aa',
176
+ '--bg': '#111827',
177
+ '--fg': '#f9fafb',
178
+ })
179
+
180
+ const button = s('.button').css({
181
+ background: '$brand',
182
+ color: '$fg',
183
+ border: '1px solid --brand, #ff44aa',
184
+ })
185
+ ```
186
+
187
+ ## How It Works
188
+
189
+ - `Style` extends `BaseStyle` and stores declarations in a map and nested selectors as children.
190
+ - `.select()` creates a child style using the parent selector + the new selector (with automatic spacing unless a combinator or `:` is used).
191
+ - `.media()` creates a sibling style under `@media(...)` and targets the current selector inside that media block.
192
+ - `.toCSS()` serializes rules in a deterministic order: normal selectors first, then `@media` blocks, preserving creation order via internal IDs.
193
+ - `.toPrettyCSS()` runs the output through Prettier (`parser: css`) with default formatting options.
194
+
195
+ ## API Reference
196
+
197
+ ### `s(selector?) -> Style`
198
+
199
+ Creates a `Style` instance. If a selector is provided, it becomes the root selector.
200
+
201
+ ### `Style` / `BaseStyle` methods
202
+
203
+ - `set(name, value)` - set a single property (camelCase or kebab-case).
204
+ - `css(object)` - set many properties at once using `CSSProps`.
205
+ - `select(selector)` - create or access a nested selector.
206
+ - `media(query)` - create or access a `@media(...)` block scoped to this selector.
207
+ - `use(style)` - shallow-merge declarations from another style into this one.
208
+ - `toCSS()` - serialize to CSS string.
209
+ - `toPrettyCSS(options?)` - serialize and format using Prettier.
210
+
211
+ ## Gotchas / Notes
212
+
213
+ - `use()` merges only property declarations, not child selectors.
214
+ - `select()` preserves insertion order; repeated calls to the same selector return the same node.
215
+ - `media()` uses `@media(${query})` if you pass a bare query (without `@media`).
216
+ - `autoVar()` converts `$name` and `--name` values to `var(...)`; other values are untouched.
217
+ - Output uses Windows-style CRLF in some internal joins; `toPrettyCSS()` normalizes to `lf`.
218
+
219
+ ## Integration with ts-html / ts-ssg
220
+
221
+ `ts-css` is designed to pair with `ts-html` and `ts-ssg`:
222
+
223
+ ```ts
224
+ import { s } from '@purestack/ts-css'
225
+ import { h } from '@purestack/ts-html'
226
+
227
+ const style = s()
228
+ style.select('.hero').css({
229
+ fontSize: '32px',
230
+ fontWeight: '700',
231
+ })
232
+
233
+ const page = h('html')
234
+ .push(
235
+ h('head').push(h('style').raw(style.toCSS())),
236
+ h('body').push(h('div').class('hero').text('Hello')),
237
+ )
238
+
239
+ console.log(page.toHtml())
240
+ ```
241
+
242
+ ## Output
243
+
244
+ ### `toCSS()`
245
+
246
+ Returns raw CSS as a string.
247
+
248
+ ### `toPrettyCSS(options?)`
249
+
250
+ Formats output using Prettier (parser: `css`) with defaults:
251
+
252
+ - `tabWidth: 2`
253
+ - `endOfLine: 'lf'`
254
+
255
+ ## API Overview
256
+
257
+ Exports:
258
+
259
+ - `s(selector?)` -> `Style`
260
+ - `Style` (extends `BaseStyle`)
261
+ - `getColors`, `getGradient` (color utilities)
262
+
263
+ Key `BaseStyle` methods:
264
+
265
+ - `set(name, value)`
266
+ - `css({...})`
267
+ - `select(selector)`
268
+ - `media(query)`
269
+ - `use(style)`
270
+ - `toCSS()`
271
+ - `toPrettyCSS(options?)`
272
+
273
+ ## Color Utilities
274
+
275
+ `ts-css` provides helpers for color conversions and gradients:
276
+
277
+ ```ts
278
+ import { getColors, getGradient } from '@purestack/ts-css'
279
+
280
+ const shades = getColors('#1e90ff', 30, 20, 5)
281
+ const stops = getGradient('#21a8c3', '#a50d60', 6, 'hsl')
282
+ ```
283
+
284
+ ## Type Safety
285
+
286
+ `CSSProps` is a large type union of CSS properties used by `.css()` and property-specific methods on `Style`. It provides autocomplete and helps catch invalid property names or values.
287
+
288
+ ## Tests
289
+
290
+ ```bash
291
+ yarn workspace @purestack/ts-css test
292
+ ```
293
+
294
+ ## Related Packages
295
+
296
+ - `@purestack/ts-html` for type-safe HTML generation
297
+ - `@purestack/ts-ssg` for a minimal static-site composition layer
298
+
299
+ ## License
300
+
301
+ MIT