typewritingclass 0.2.0 → 0.2.2

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 CHANGED
@@ -10,6 +10,20 @@ bun add typewritingclass
10
10
 
11
11
  ## Usage
12
12
 
13
+ ### Chainable API (recommended)
14
+
15
+ ```ts
16
+ import { tw } from 'typewritingclass'
17
+
18
+ const card = tw
19
+ .bg('white').rounded('lg').p(6).flex.gap(4)
20
+ .hover(tw.bg('blue-50'))
21
+ .md.p(8)
22
+ .dark(tw.bg('slate-800'))
23
+ ```
24
+
25
+ ### Individual imports
26
+
13
27
  ```ts
14
28
  import { cx, p, bg, textColor, rounded, flex, gap, when } from 'typewritingclass'
15
29
  import { hover, md, dark } from 'typewritingclass'
@@ -26,6 +40,14 @@ const card = cx(
26
40
 
27
41
  ## API
28
42
 
43
+ ### Chainable builder
44
+
45
+ - **`tw`** — proxy-based chainable API with access to all utilities and modifiers via a single import
46
+ - Property syntax for modifiers: `tw.hover.bg('blue-500')`
47
+ - Function syntax for multi-utility modifiers: `tw.hover(tw.bg('blue-500').textColor('white'))`
48
+ - Value-less utilities as properties: `tw.flex.flexCol.relative`
49
+ - Resolves to class string via `.toString()`, `.value`, `.className`, or template literals
50
+
29
51
  ### Composition
30
52
 
31
53
  - **`cx(...rules)`** — compose utilities into a single class name
@@ -76,10 +98,10 @@ const theme = createTheme({
76
98
  ### Dynamic values
77
99
 
78
100
  ```ts
79
- import { dynamic } from 'typewritingclass/runtime'
101
+ import { dcx, bg, p, dynamic } from 'typewritingclass'
80
102
 
81
- // Returns { className, style } for runtime CSS custom properties
82
- const result = dynamic(bg(userColor))
103
+ // Wrap a runtime value with dynamic(), then compose via dcx()
104
+ const { className, style } = dcx(p(4), bg(dynamic(userColor)))
83
105
  ```
84
106
 
85
107
  ### Raw CSS escape hatch
@@ -100,8 +122,10 @@ cx(p(4), css({ transition: 'all 200ms ease' }))
100
122
  | `typewritingclass/theme/typography` | Font sizes, weights, line heights |
101
123
  | `typewritingclass/theme/shadows` | Shadow presets |
102
124
  | `typewritingclass/theme/borders` | Border radius tokens |
103
- | `typewritingclass/theme/spacing` | Spacing scale |
104
125
  | `typewritingclass/theme/sizes` | Named sizes |
126
+ | `typewritingclass/theme/animations` | Animation keyframe presets |
127
+ | `typewritingclass/theme/filters` | Filter presets |
105
128
  | `typewritingclass/theme/createTheme` | `createTheme()` |
106
- | `typewritingclass/inject` | `injectTheme()`, `setTheme()` |
107
- | `typewritingclass/runtime` | `dynamic()`, `isDynamic()` |
129
+ | `typewritingclass/inject` | Runtime style injection (auto-initializing side-effect import) |
130
+ | `typewritingclass/runtime` | `__twcDynamic()` (internal compiler helper) |
131
+ | `typewritingclass/rule` | `createRule()`, `createDynamicRule()`, `wrapWithSelector()`, `wrapWithMediaQuery()` |
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "typewritingclass",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/corysimmons/typewritingclass",
8
+ "directory": "packages/typewritingclass"
9
+ },
5
10
  "exports": {
6
11
  ".": {
7
12
  "types": "./src/index.ts",
@@ -56,16 +61,14 @@
56
61
  "default": "./src/rule.ts"
57
62
  }
58
63
  },
59
- "files": [
60
- "src"
61
- ],
62
- "devDependencies": {
63
- "vitest": "^3.0.4",
64
- "typescript": "^5.7.3"
65
- },
64
+ "files": ["src"],
66
65
  "scripts": {
67
66
  "test": "vitest run",
68
67
  "test:watch": "vitest",
69
68
  "bench": "tsx benchmarks/bench.ts"
69
+ },
70
+ "devDependencies": {
71
+ "vitest": "^3.0.4",
72
+ "typescript": "^5.7.3"
70
73
  }
71
- }
74
+ }
package/src/hash.ts CHANGED
@@ -48,6 +48,7 @@ export function generateHash(rule: StyleRule, layer: number): string {
48
48
  JSON.stringify(rule.declarations) +
49
49
  JSON.stringify(rule.selectors) +
50
50
  JSON.stringify(rule.mediaQueries) +
51
+ JSON.stringify(rule.supportsQueries) +
51
52
  String(layer) +
52
53
  (rule.selectorTemplate ?? '')
53
54
  return '_' + djb2(input).toString(36)
package/src/index.ts CHANGED
@@ -6,9 +6,11 @@ export { css } from './css.ts'
6
6
  export { dynamic, isDynamic } from './dynamic.ts'
7
7
  export { layer } from './layer.ts'
8
8
  export { generateCSS } from './registry.ts'
9
+ export { tw } from './tw.ts'
9
10
 
10
11
  // Types
11
12
  export type { StyleRule, Utility, Modifier, DynamicResult } from './types.ts'
13
+ export type { TwChain } from './tw.ts'
12
14
  export type {
13
15
  Brand, CSSColor, CSSLength, CSSShadow, CSSFontWeight,
14
16
  ColorInput, SpacingInput, SizeInput, RadiusInput, ShadowInput,
package/src/rule.ts CHANGED
@@ -88,27 +88,27 @@ export function createDynamicRule(
88
88
  */
89
89
  export function combineRules(rules: StyleRule[]): StyleRule {
90
90
  const merged: Record<string, string> = {}
91
- const selectors: string[] = []
92
- const mediaQueries: string[] = []
93
- const supportsQueries: string[] = []
91
+ const selectorSet = new Set<string>()
92
+ const mediaQuerySet = new Set<string>()
93
+ const supportsQuerySet = new Set<string>()
94
94
  let dynamicBindings: Record<string, string> | undefined
95
95
  for (const rule of rules) {
96
96
  Object.assign(merged, rule.declarations)
97
- for (const s of rule.selectors) {
98
- if (!selectors.includes(s)) selectors.push(s)
99
- }
100
- for (const mq of rule.mediaQueries) {
101
- if (!mediaQueries.includes(mq)) mediaQueries.push(mq)
102
- }
103
- for (const sq of rule.supportsQueries) {
104
- if (!supportsQueries.includes(sq)) supportsQueries.push(sq)
105
- }
97
+ for (const s of rule.selectors) selectorSet.add(s)
98
+ for (const mq of rule.mediaQueries) mediaQuerySet.add(mq)
99
+ for (const sq of rule.supportsQueries) supportsQuerySet.add(sq)
106
100
  if (rule.dynamicBindings) {
107
101
  if (!dynamicBindings) dynamicBindings = {}
108
102
  Object.assign(dynamicBindings, rule.dynamicBindings)
109
103
  }
110
104
  }
111
- const result: StyleRule = { _tag: 'StyleRule', declarations: merged, selectors, mediaQueries, supportsQueries }
105
+ const result: StyleRule = {
106
+ _tag: 'StyleRule',
107
+ declarations: merged,
108
+ selectors: [...selectorSet],
109
+ mediaQueries: [...mediaQuerySet],
110
+ supportsQueries: [...supportsQuerySet],
111
+ }
112
112
  if (dynamicBindings) result.dynamicBindings = dynamicBindings
113
113
  return result
114
114
  }