@pyreon/styler 0.11.5 → 0.11.6

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.
Files changed (36) hide show
  1. package/README.md +27 -23
  2. package/lib/index.d.ts +9 -2
  3. package/lib/index.js +47 -4
  4. package/package.json +22 -22
  5. package/src/ThemeProvider.ts +10 -3
  6. package/src/__tests__/ThemeProvider.test.ts +21 -21
  7. package/src/__tests__/benchmark.bench.ts +56 -45
  8. package/src/__tests__/composition-chain.test.ts +200 -151
  9. package/src/__tests__/forward.test.ts +122 -122
  10. package/src/__tests__/globalStyle.test.ts +18 -18
  11. package/src/__tests__/hash.test.ts +27 -27
  12. package/src/__tests__/hybrid-injection.test.ts +83 -59
  13. package/src/__tests__/index.ts +10 -10
  14. package/src/__tests__/insertion-effect.test.ts +45 -32
  15. package/src/__tests__/integration.test.ts +81 -51
  16. package/src/__tests__/keyframes.test.ts +13 -13
  17. package/src/__tests__/memory-growth.test.ts +21 -21
  18. package/src/__tests__/p3-features.test.ts +162 -104
  19. package/src/__tests__/shared.test.ts +51 -33
  20. package/src/__tests__/sheet-advanced.test.ts +227 -227
  21. package/src/__tests__/sheet-split-atrules.test.ts +85 -85
  22. package/src/__tests__/sheet.test.ts +69 -69
  23. package/src/__tests__/styled-ssr.test.ts +36 -28
  24. package/src/__tests__/styled.test.ts +214 -145
  25. package/src/__tests__/theme.test.ts +11 -11
  26. package/src/__tests__/useCSS.test.ts +89 -59
  27. package/src/css.ts +1 -1
  28. package/src/forward.ts +187 -187
  29. package/src/globalStyle.ts +5 -5
  30. package/src/index.ts +15 -15
  31. package/src/keyframes.ts +3 -3
  32. package/src/resolve.ts +14 -14
  33. package/src/shared.ts +2 -2
  34. package/src/sheet.ts +26 -26
  35. package/src/styled.tsx +145 -100
  36. package/src/useCSS.ts +4 -4
@@ -10,11 +10,11 @@
10
10
  * *, *::before, *::after { box-sizing: border-box; }
11
11
  * `
12
12
  */
13
- import type { ComponentFn } from "@pyreon/core"
14
- import { type Interpolation, normalizeCSS, resolve } from "./resolve"
15
- import { isDynamic } from "./shared"
16
- import { sheet } from "./sheet"
17
- import { useTheme } from "./ThemeProvider"
13
+ import type { ComponentFn } from '@pyreon/core'
14
+ import { type Interpolation, normalizeCSS, resolve } from './resolve'
15
+ import { isDynamic } from './shared'
16
+ import { sheet } from './sheet'
17
+ import { useTheme } from './ThemeProvider'
18
18
 
19
19
  export const createGlobalStyle = (
20
20
  strings: TemplateStringsArray,
package/src/index.ts CHANGED
@@ -1,15 +1,15 @@
1
- export { css } from "./css"
2
- export { buildProps, filterProps } from "./forward"
3
- export { createGlobalStyle } from "./globalStyle"
4
- export { HASH_INIT, hash, hashFinalize, hashUpdate } from "./hash"
5
- export { keyframes } from "./keyframes"
6
- export type { CSSResult, Interpolation } from "./resolve"
7
- export { clearNormCache, normalizeCSS, resolve, resolveValue } from "./resolve"
8
- export { isDynamic } from "./shared"
9
- export type { StyleSheetOptions } from "./sheet"
10
- export { createSheet, StyleSheet, sheet } from "./sheet"
11
- export type { StyledFunction, StyledOptions } from "./styled"
12
- export { styled } from "./styled"
13
- export type { DefaultTheme } from "./ThemeProvider"
14
- export { ThemeContext, ThemeProvider, useTheme } from "./ThemeProvider"
15
- export { useCSS } from "./useCSS"
1
+ export { css } from './css'
2
+ export { buildProps, filterProps } from './forward'
3
+ export { createGlobalStyle } from './globalStyle'
4
+ export { HASH_INIT, hash, hashFinalize, hashUpdate } from './hash'
5
+ export { keyframes } from './keyframes'
6
+ export type { CSSResult, Interpolation } from './resolve'
7
+ export { clearNormCache, normalizeCSS, resolve, resolveValue } from './resolve'
8
+ export { isDynamic } from './shared'
9
+ export type { StyleSheetOptions } from './sheet'
10
+ export { createSheet, StyleSheet, sheet } from './sheet'
11
+ export type { StyledFunction, StyledOptions } from './styled'
12
+ export { styled } from './styled'
13
+ export type { DefaultTheme } from './ThemeProvider'
14
+ export { ThemeContext, ThemeProvider, useTheme } from './ThemeProvider'
15
+ export { useCSS } from './useCSS'
package/src/keyframes.ts CHANGED
@@ -9,9 +9,9 @@
9
9
  * `
10
10
  * // fadeIn === "pyr-kf-abc123" (deterministic, hash-based)
11
11
  */
12
- import { hash } from "./hash"
13
- import { type Interpolation, normalizeCSS, resolve } from "./resolve"
14
- import { sheet } from "./sheet"
12
+ import { hash } from './hash'
13
+ import { type Interpolation, normalizeCSS, resolve } from './resolve'
14
+ import { sheet } from './sheet'
15
15
 
16
16
  class KeyframesResult {
17
17
  readonly name: string
package/src/resolve.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * primitive values.
5
5
  */
6
6
 
7
- import type { DefaultTheme } from "./ThemeProvider"
7
+ import type { DefaultTheme } from './ThemeProvider'
8
8
 
9
9
  export type Interpolation =
10
10
  | string
@@ -47,19 +47,19 @@ export const resolve = (
47
47
  const v = values[i]
48
48
  const s = strings[i + 1] as string
49
49
  // Inline the most common value types to avoid function call overhead.
50
- if (typeof v === "function") {
50
+ if (typeof v === 'function') {
51
51
  const r = v(props)
52
52
  result +=
53
- (typeof r === "string"
53
+ (typeof r === 'string'
54
54
  ? r
55
55
  : r == null || r === false || r === true
56
- ? ""
56
+ ? ''
57
57
  : resolveValue(r as Interpolation, props)) + s
58
58
  } else if (v == null || v === false || v === true) {
59
59
  result += s
60
- } else if (typeof v === "string") {
60
+ } else if (typeof v === 'string') {
61
61
  result += v + s
62
- } else if (typeof v === "number") {
62
+ } else if (typeof v === 'number') {
63
63
  result += v + s
64
64
  } else {
65
65
  result += resolveValue(v, props) + s
@@ -87,7 +87,7 @@ export const normalizeCSS = (css: string): string => {
87
87
  if (cached !== undefined) return cached
88
88
 
89
89
  const len = css.length
90
- let out = ""
90
+ let out = ''
91
91
  let space = false // pending space to emit before next non-whitespace char
92
92
  let last = 0 // charCode of last char written to output (0 = nothing yet)
93
93
 
@@ -96,7 +96,7 @@ export const normalizeCSS = (css: string): string => {
96
96
 
97
97
  // /* block comment */
98
98
  if (c === 47 /* / */ && css.charCodeAt(i + 1) === 42 /* * */) {
99
- const end = css.indexOf("*/", i + 2)
99
+ const end = css.indexOf('*/', i + 2)
100
100
  i = end === -1 ? len : end + 1
101
101
  space = true
102
102
  continue
@@ -104,7 +104,7 @@ export const normalizeCSS = (css: string): string => {
104
104
 
105
105
  // // line comment (but not :// in URLs)
106
106
  if (c === 47 /* / */ && css.charCodeAt(i + 1) === 47 /* / */ && last !== 58 /* : */) {
107
- const nl = css.indexOf("\n", i + 2)
107
+ const nl = css.indexOf('\n', i + 2)
108
108
  i = nl === -1 ? len : nl
109
109
  space = true
110
110
  continue
@@ -122,13 +122,13 @@ export const normalizeCSS = (css: string): string => {
122
122
  continue
123
123
  }
124
124
  space = false
125
- out += ";"
125
+ out += ';'
126
126
  last = 59
127
127
  continue
128
128
  }
129
129
 
130
130
  // Regular char — emit pending space (but not at start of output)
131
- if (space && last !== 0) out += " "
131
+ if (space && last !== 0) out += ' '
132
132
  space = false
133
133
 
134
134
  out += css[i]
@@ -151,17 +151,17 @@ export const normalizeCSS = (css: string): string => {
151
151
 
152
152
  export const resolveValue = (value: Interpolation, props: Record<string, any>): string => {
153
153
  // null, undefined, false, true → empty (enables conditional: ${cond && css`...`})
154
- if (value == null || value === false || value === true) return ""
154
+ if (value == null || value === false || value === true) return ''
155
155
 
156
156
  // function interpolation → call with props/theme context, resolve result
157
- if (typeof value === "function") return resolveValue(value(props) as Interpolation, props)
157
+ if (typeof value === 'function') return resolveValue(value(props) as Interpolation, props)
158
158
 
159
159
  // nested CSSResult → recursively resolve
160
160
  if (value instanceof CSSResult) return resolve(value.strings, value.values, props)
161
161
 
162
162
  // array of results (e.g. from makeItResponsive's breakpoints.map())
163
163
  if (Array.isArray(value)) {
164
- let arrayResult = ""
164
+ let arrayResult = ''
165
165
  for (let i = 0; i < value.length; i++) {
166
166
  arrayResult += resolveValue(value[i], props)
167
167
  }
package/src/shared.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Shared utilities used across multiple modules.
3
3
  */
4
- import { CSSResult, type Interpolation } from "./resolve"
4
+ import { CSSResult, type Interpolation } from './resolve'
5
5
 
6
6
  /** Check if an interpolation value is dynamic (contains functions or nested dynamic CSSResults). */
7
7
  export const isDynamic = (v: Interpolation): boolean => {
8
- if (typeof v === "function") return true
8
+ if (typeof v === 'function') return true
9
9
  if (Array.isArray(v)) return v.some(isDynamic)
10
10
  if (v instanceof CSSResult) return v.values.some(isDynamic)
11
11
  return false
package/src/sheet.ts CHANGED
@@ -5,11 +5,11 @@
5
5
  * Media queries (@media), @supports, and @container blocks nested inside
6
6
  * component CSS are automatically extracted into separate top-level rules.
7
7
  */
8
- import { hash } from "./hash"
9
- import { clearNormCache } from "./resolve"
8
+ import { hash } from './hash'
9
+ import { clearNormCache } from './resolve'
10
10
 
11
- const PREFIX = "pyr"
12
- const ATTR = "data-pyreon-styler"
11
+ const PREFIX = 'pyr'
12
+ const ATTR = 'data-pyreon-styler'
13
13
  const DEFAULT_MAX_CACHE_SIZE = 10000
14
14
 
15
15
  export interface StyleSheetOptions {
@@ -31,7 +31,7 @@ export class StyleSheet {
31
31
  constructor(options: StyleSheetOptions = {}) {
32
32
  this.maxCacheSize = options.maxCacheSize ?? DEFAULT_MAX_CACHE_SIZE
33
33
  this.layer = options.layer
34
- this.isSSR = typeof document === "undefined"
34
+ this.isSSR = typeof document === 'undefined'
35
35
  if (!this.isSSR) this.mount()
36
36
  }
37
37
 
@@ -43,8 +43,8 @@ export class StyleSheet {
43
43
  this.sheet = existing.sheet ?? null
44
44
  this.hydrateFromTag(existing)
45
45
  } else {
46
- const el = document.createElement("style")
47
- el.setAttribute(ATTR, "")
46
+ const el = document.createElement('style')
47
+ el.setAttribute(ATTR, '')
48
48
  document.head.appendChild(el)
49
49
  this.sheet = el.sheet ?? null
50
50
  }
@@ -61,8 +61,8 @@ export class StyleSheet {
61
61
 
62
62
  /** Extract className from a selector like ".pyr-abc" or ".pyr-abc.pyr-abc" → "pyr-abc" */
63
63
  private extractClassName(selectorText: string): string | null {
64
- if (selectorText[0] !== ".") return null
65
- const dotIdx = selectorText.indexOf(".", 1)
64
+ if (selectorText[0] !== '.') return null
65
+ const dotIdx = selectorText.indexOf('.', 1)
66
66
  return dotIdx > 0 ? selectorText.slice(1, dotIdx) : selectorText.slice(1)
67
67
  }
68
68
 
@@ -81,7 +81,7 @@ export class StyleSheet {
81
81
  }
82
82
 
83
83
  // Handle split @media rules that wrap our selectors
84
- if (typeof CSSMediaRule !== "undefined" && rule instanceof CSSMediaRule) {
84
+ if (typeof CSSMediaRule !== 'undefined' && rule instanceof CSSMediaRule) {
85
85
  for (let j = 0; j < rule.cssRules.length; j++) {
86
86
  const inner = rule.cssRules[j]
87
87
  if (inner instanceof CSSStyleRule) {
@@ -114,7 +114,7 @@ export class StyleSheet {
114
114
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: complex logic is inherent to this function
115
115
  private splitAtRules(cssText: string, selector: string): { base: string; atRules: string[] } {
116
116
  // Fast path: no at-rules to split
117
- if (cssText.indexOf("@") === -1) return { base: cssText, atRules: [] }
117
+ if (cssText.indexOf('@') === -1) return { base: cssText, atRules: [] }
118
118
 
119
119
  const atRules: string[] = []
120
120
  const baseParts: string[] = []
@@ -125,13 +125,13 @@ export class StyleSheet {
125
125
  for (let i = 0; i < cssText.length; i++) {
126
126
  const ch = cssText[i]
127
127
 
128
- if (ch === "{") {
128
+ if (ch === '{') {
129
129
  depth++
130
- } else if (ch === "}") {
130
+ } else if (ch === '}') {
131
131
  depth--
132
132
  if (depth === 0 && atStart >= 0) {
133
133
  // End of a tracked at-rule block — extract and wrap with selector
134
- const openBrace = cssText.indexOf("{", atStart)
134
+ const openBrace = cssText.indexOf('{', atStart)
135
135
  const atPrefix = cssText.slice(atStart, openBrace).trim()
136
136
  const innerCSS = cssText.slice(openBrace + 1, i).trim()
137
137
  if (innerCSS) {
@@ -140,7 +140,7 @@ export class StyleSheet {
140
140
  atStart = -1
141
141
  lastBase = i + 1
142
142
  }
143
- } else if (depth === 0 && ch === "@" && atStart < 0) {
143
+ } else if (depth === 0 && ch === '@' && atStart < 0) {
144
144
  // Check if this starts a splittable at-rule (not @keyframes, @font-face, etc.)
145
145
  const remaining = cssText.slice(i, i + 20)
146
146
  if (/^@(?:media|supports|container)\b/.test(remaining)) {
@@ -161,7 +161,7 @@ export class StyleSheet {
161
161
  // If no at-rules were found, return original unchanged
162
162
  if (atRules.length === 0) return { base: cssText, atRules: [] }
163
163
 
164
- return { base: baseParts.join(" "), atRules }
164
+ return { base: baseParts.join(' '), atRules }
165
165
  }
166
166
 
167
167
  /**
@@ -221,9 +221,9 @@ export class StyleSheet {
221
221
  try {
222
222
  this.sheet.insertRule(rule, this.sheet.cssRules.length)
223
223
  } catch (_e) {
224
- if (process.env.NODE_ENV !== "production") {
224
+ if (process.env.NODE_ENV !== 'production') {
225
225
  // biome-ignore lint/suspicious/noConsole: dev-only CSS rule insertion warning
226
- console.warn("[styler] Failed to insert CSS rule:", rule, _e)
226
+ console.warn('[styler] Failed to insert CSS rule:', rule, _e)
227
227
  }
228
228
  }
229
229
  }
@@ -248,7 +248,7 @@ export class StyleSheet {
248
248
  try {
249
249
  this.sheet.insertRule(rule, this.sheet.cssRules.length)
250
250
  } catch (_e) {
251
- if (process.env.NODE_ENV !== "production") {
251
+ if (process.env.NODE_ENV !== 'production') {
252
252
  // silently ignore invalid CSS rules in production
253
253
  }
254
254
  }
@@ -266,8 +266,8 @@ export class StyleSheet {
266
266
 
267
267
  for (let i = 0; i < cssText.length; i++) {
268
268
  const ch = cssText[i]
269
- if (ch === "{") depth++
270
- else if (ch === "}") {
269
+ if (ch === '{') depth++
270
+ else if (ch === '}') {
271
271
  depth--
272
272
  if (depth === 0) {
273
273
  const rule = cssText.slice(start, i + 1).trim()
@@ -298,9 +298,9 @@ export class StyleSheet {
298
298
  try {
299
299
  this.sheet.insertRule(rule, this.sheet.cssRules.length)
300
300
  } catch (_e) {
301
- if (process.env.NODE_ENV !== "production") {
301
+ if (process.env.NODE_ENV !== 'production') {
302
302
  // biome-ignore lint/suspicious/noConsole: dev-only CSS rule insertion warning
303
- console.warn("[styler] Failed to insert global CSS rule:", rule, _e)
303
+ console.warn('[styler] Failed to insert global CSS rule:', rule, _e)
304
304
  }
305
305
  }
306
306
  }
@@ -309,13 +309,13 @@ export class StyleSheet {
309
309
 
310
310
  /** Returns collected CSS for SSR as a complete `<style>` tag string. */
311
311
  getStyleTag(): string {
312
- const css = this.ssrBuffer.join("").replace(/<\/style/gi, "<\\/style")
312
+ const css = this.ssrBuffer.join('').replace(/<\/style/gi, '<\\/style')
313
313
  return `<style ${ATTR}="">${css}</style>`
314
314
  }
315
315
 
316
316
  /** Returns collected CSS rules as a raw string (useful for streaming SSR). */
317
317
  getStyles(): string {
318
- return this.ssrBuffer.join("")
318
+ return this.ssrBuffer.join('')
319
319
  }
320
320
 
321
321
  /** Reset SSR buffer and cache (call between server requests). */
@@ -363,7 +363,7 @@ export class StyleSheet {
363
363
 
364
364
  const finalRules = this.layer ? allRules.map((r) => `@layer ${this.layer}{${r}}`) : allRules
365
365
 
366
- return { className, rules: finalRules.join("") }
366
+ return { className, rules: finalRules.join('') }
367
367
  }
368
368
 
369
369
  /** Check if a className is already in the cache. O(1) Map lookup. */
package/src/styled.tsx CHANGED
@@ -15,13 +15,14 @@
15
15
  * through without transformation, so `&:hover`, `&::before`, etc. work
16
16
  * as-is in browsers supporting CSS Nesting (all modern browsers).
17
17
  */
18
- import type { ComponentFn, VNode } from "@pyreon/core"
19
- import { h } from "@pyreon/core"
20
- import { buildProps } from "./forward"
21
- import { type Interpolation, normalizeCSS, resolve } from "./resolve"
22
- import { isDynamic } from "./shared"
23
- import { sheet } from "./sheet"
24
- import { useTheme } from "./ThemeProvider"
18
+ import type { ComponentFn, VNode } from '@pyreon/core'
19
+ import { h } from '@pyreon/core'
20
+ import { effect } from '@pyreon/reactivity'
21
+ import { buildProps } from './forward'
22
+ import { type Interpolation, normalizeCSS, resolve } from './resolve'
23
+ import { isDynamic } from './shared'
24
+ import { sheet } from './sheet'
25
+ import { useTheme } from './ThemeProvider'
25
26
 
26
27
  type Tag = string | ComponentFn<any>
27
28
 
@@ -37,9 +38,9 @@ export interface StyledOptions {
37
38
  }
38
39
 
39
40
  const getDisplayName = (tag: Tag): string =>
40
- typeof tag === "string"
41
+ typeof tag === 'string'
41
42
  ? tag
42
- : (tag as ComponentFn<any> & { displayName?: string }).displayName || tag.name || "Component"
43
+ : (tag as ComponentFn<any> & { displayName?: string }).displayName || tag.name || 'Component'
43
44
 
44
45
  // Component cache: same template literal + tag + no options → same component.
45
46
  // WeakMap on `strings` (TemplateStringsArray is object-identity per source location).
@@ -86,11 +87,11 @@ const createStyledComponent = (
86
87
  const cssText = normalizeCSS(raw)
87
88
  const hasCss = cssText.length > 0
88
89
 
89
- const staticClassName = hasCss ? sheet.insert(cssText, boost) : ""
90
+ const staticClassName = hasCss ? sheet.insert(cssText, boost) : ''
90
91
 
91
92
  const StaticStyled: ComponentFn = (rawProps: Record<string, any>): VNode | null => {
92
93
  const finalTag = rawProps.as || tag
93
- const isDOM = typeof finalTag === "string"
94
+ const isDOM = typeof finalTag === 'string'
94
95
  const finalProps = buildProps(rawProps, staticClassName, isDOM, customFilter)
95
96
 
96
97
  return h(
@@ -124,17 +125,61 @@ const createStyledComponent = (
124
125
  }
125
126
 
126
127
  // DYNAMIC PATH: resolve CSS on every render with theme/props.
128
+ // When $rocketstyle is a function accessor (from rocketstyle's
129
+ // EnhancedComponent), we resolve it initially for the first class,
130
+ // then set up an effect to reactively swap classes when mode changes.
131
+ // This avoids VNode remounting — only classList updates on the DOM element.
127
132
  const DynamicStyled: ComponentFn = (rawProps: Record<string, any>): VNode | null => {
128
133
  const theme = useTheme()
129
- const allProps = { ...rawProps, theme }
130
- const cssText = normalizeCSS(resolve(strings, values, allProps))
134
+ const $rs = rawProps.$rocketstyle
135
+ const isReactiveRS = typeof $rs === 'function'
131
136
 
132
- const className = cssText.length > 0 ? sheet.insert(cssText, boost) : ""
137
+ // Resolve initial $rocketstyle value
138
+ const resolvedRS = isReactiveRS ? $rs() : $rs
139
+ const initialProps = isReactiveRS ? { ...rawProps, $rocketstyle: resolvedRS } : rawProps
140
+ const cssText = normalizeCSS(resolve(strings, values, { ...initialProps, theme }))
141
+ const initialClassName = cssText.length > 0 ? sheet.insert(cssText, boost) : ''
133
142
 
134
143
  const finalTag = rawProps.as || tag
135
- const isDOM = typeof finalTag === "string"
136
- const finalProps = buildProps(rawProps, className, isDOM, customFilter)
144
+ const isDOM = typeof finalTag === 'string'
137
145
 
146
+ // Track mounted element for reactive class updates
147
+ let el: Element | null = null
148
+ let currentClassName = initialClassName
149
+
150
+ const originalRef = rawProps.ref
151
+ const refCallback = (node: Element | null) => {
152
+ el = node
153
+ if (originalRef) {
154
+ if (typeof originalRef === 'function') originalRef(node)
155
+ else if (originalRef && typeof originalRef === 'object') originalRef.current = node
156
+ }
157
+ }
158
+
159
+ const finalProps = buildProps(
160
+ { ...rawProps, ref: isReactiveRS ? refCallback : rawProps.ref },
161
+ initialClassName,
162
+ isDOM,
163
+ customFilter,
164
+ )
165
+
166
+ // Set up reactive class swap when $rocketstyle is a function accessor
167
+ if (isReactiveRS) {
168
+ effect(() => {
169
+ const newRS = $rs() // reactive read — tracks mode dependency
170
+ const newResolvedProps = { ...rawProps, $rocketstyle: newRS }
171
+ const newCss = normalizeCSS(resolve(strings, values, { ...newResolvedProps, theme }))
172
+ const newClass = newCss.length > 0 ? sheet.insert(newCss, boost) : ''
173
+
174
+ if (el && newClass !== currentClassName) {
175
+ if (currentClassName) el.classList.remove(currentClassName)
176
+ if (newClass) el.classList.add(newClass)
177
+ currentClassName = newClass
178
+ }
179
+ })
180
+ }
181
+
182
+ // STATIC VNode — created once, never remounted on mode change
138
183
  return h(
139
184
  finalTag as string,
140
185
  finalProps,
@@ -171,89 +216,89 @@ const proxyCache = new Map<string, (...args: any[]) => any>()
171
216
  type TagTemplateFn = (strings: TemplateStringsArray, ...values: Interpolation[]) => ComponentFn
172
217
 
173
218
  type HtmlTags =
174
- | "a"
175
- | "abbr"
176
- | "address"
177
- | "article"
178
- | "aside"
179
- | "audio"
180
- | "b"
181
- | "blockquote"
182
- | "body"
183
- | "br"
184
- | "button"
185
- | "canvas"
186
- | "caption"
187
- | "code"
188
- | "col"
189
- | "colgroup"
190
- | "dd"
191
- | "details"
192
- | "div"
193
- | "dl"
194
- | "dt"
195
- | "em"
196
- | "fieldset"
197
- | "figcaption"
198
- | "figure"
199
- | "footer"
200
- | "form"
201
- | "h1"
202
- | "h2"
203
- | "h3"
204
- | "h4"
205
- | "h5"
206
- | "h6"
207
- | "head"
208
- | "header"
209
- | "hr"
210
- | "html"
211
- | "i"
212
- | "iframe"
213
- | "img"
214
- | "input"
215
- | "label"
216
- | "legend"
217
- | "li"
218
- | "link"
219
- | "main"
220
- | "mark"
221
- | "menu"
222
- | "meta"
223
- | "nav"
224
- | "ol"
225
- | "optgroup"
226
- | "option"
227
- | "output"
228
- | "p"
229
- | "picture"
230
- | "pre"
231
- | "progress"
232
- | "q"
233
- | "section"
234
- | "select"
235
- | "small"
236
- | "source"
237
- | "span"
238
- | "strong"
239
- | "style"
240
- | "sub"
241
- | "summary"
242
- | "sup"
243
- | "svg"
244
- | "table"
245
- | "tbody"
246
- | "td"
247
- | "template"
248
- | "textarea"
249
- | "tfoot"
250
- | "th"
251
- | "thead"
252
- | "time"
253
- | "tr"
254
- | "u"
255
- | "ul"
256
- | "video"
219
+ | 'a'
220
+ | 'abbr'
221
+ | 'address'
222
+ | 'article'
223
+ | 'aside'
224
+ | 'audio'
225
+ | 'b'
226
+ | 'blockquote'
227
+ | 'body'
228
+ | 'br'
229
+ | 'button'
230
+ | 'canvas'
231
+ | 'caption'
232
+ | 'code'
233
+ | 'col'
234
+ | 'colgroup'
235
+ | 'dd'
236
+ | 'details'
237
+ | 'div'
238
+ | 'dl'
239
+ | 'dt'
240
+ | 'em'
241
+ | 'fieldset'
242
+ | 'figcaption'
243
+ | 'figure'
244
+ | 'footer'
245
+ | 'form'
246
+ | 'h1'
247
+ | 'h2'
248
+ | 'h3'
249
+ | 'h4'
250
+ | 'h5'
251
+ | 'h6'
252
+ | 'head'
253
+ | 'header'
254
+ | 'hr'
255
+ | 'html'
256
+ | 'i'
257
+ | 'iframe'
258
+ | 'img'
259
+ | 'input'
260
+ | 'label'
261
+ | 'legend'
262
+ | 'li'
263
+ | 'link'
264
+ | 'main'
265
+ | 'mark'
266
+ | 'menu'
267
+ | 'meta'
268
+ | 'nav'
269
+ | 'ol'
270
+ | 'optgroup'
271
+ | 'option'
272
+ | 'output'
273
+ | 'p'
274
+ | 'picture'
275
+ | 'pre'
276
+ | 'progress'
277
+ | 'q'
278
+ | 'section'
279
+ | 'select'
280
+ | 'small'
281
+ | 'source'
282
+ | 'span'
283
+ | 'strong'
284
+ | 'style'
285
+ | 'sub'
286
+ | 'summary'
287
+ | 'sup'
288
+ | 'svg'
289
+ | 'table'
290
+ | 'tbody'
291
+ | 'td'
292
+ | 'template'
293
+ | 'textarea'
294
+ | 'tfoot'
295
+ | 'th'
296
+ | 'thead'
297
+ | 'time'
298
+ | 'tr'
299
+ | 'u'
300
+ | 'ul'
301
+ | 'video'
257
302
 
258
303
  export type StyledFunction = ((tag: Tag, options?: StyledOptions) => TagTemplateFn) & {
259
304
  [K in HtmlTags]: TagTemplateFn
@@ -264,7 +309,7 @@ export type StyledFunction = ((tag: Tag, options?: StyledOptions) => TagTemplate
264
309
  // Proxy target uses `as any` because TS can't resolve Proxy<StyledFunction> with mapped types
265
310
  export const styled: StyledFunction = new Proxy(styledFactory as any, {
266
311
  get(_target: unknown, prop: string) {
267
- if (prop === "prototype" || prop === "$$typeof") return undefined
312
+ if (prop === 'prototype' || prop === '$$typeof') return undefined
268
313
  // styled.div`...`, styled.span`...`, etc.
269
314
  let fn = proxyCache.get(prop)
270
315
  if (!fn) {
package/src/useCSS.ts CHANGED
@@ -5,16 +5,16 @@
5
5
  * Use this when you need computed CSS class names on plain elements
6
6
  * without the overhead of a styled component layer.
7
7
  */
8
- import { type CSSResult, normalizeCSS, resolve } from "./resolve"
9
- import { sheet } from "./sheet"
10
- import { useTheme } from "./ThemeProvider"
8
+ import { type CSSResult, normalizeCSS, resolve } from './resolve'
9
+ import { sheet } from './sheet'
10
+ import { useTheme } from './ThemeProvider'
11
11
 
12
12
  export function useCSS(template: CSSResult, props?: Record<string, any>, boost?: boolean): string {
13
13
  const theme = useTheme()
14
14
  const allProps = theme ? { ...props, theme } : (props ?? {})
15
15
  const cssText = normalizeCSS(resolve(template.strings, template.values, allProps))
16
16
 
17
- if (!cssText.trim()) return ""
17
+ if (!cssText.trim()) return ''
18
18
 
19
19
  return sheet.insert(cssText, boost)
20
20
  }