@pyreon/unistyle 0.24.5 → 0.24.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.
- package/package.json +7 -9
- package/src/__tests__/alignContent.test.ts +0 -121
- package/src/__tests__/borderRadius.test.ts +0 -125
- package/src/__tests__/camelToKebab.test.ts +0 -44
- package/src/__tests__/context.test.ts +0 -147
- package/src/__tests__/createMediaQueries.test.ts +0 -98
- package/src/__tests__/edge.test.ts +0 -164
- package/src/__tests__/enrichTheme.test.ts +0 -56
- package/src/__tests__/extendCss.test.ts +0 -45
- package/src/__tests__/index.test.ts +0 -79
- package/src/__tests__/makeItResponsive.test.ts +0 -431
- package/src/__tests__/manifest-snapshot.test.ts +0 -34
- package/src/__tests__/native-marker.test.ts +0 -9
- package/src/__tests__/optimizeBreakpointDeltas.test.ts +0 -124
- package/src/__tests__/processDescriptor.test.ts +0 -322
- package/src/__tests__/responsive.test.ts +0 -221
- package/src/__tests__/special-keys.test.ts +0 -120
- package/src/__tests__/styles.test.ts +0 -273
- package/src/__tests__/unistyle.browser.test.tsx +0 -169
- package/src/__tests__/units.test.ts +0 -134
- package/src/context.tsx +0 -44
- package/src/enrichTheme.ts +0 -42
- package/src/env.d.ts +0 -6
- package/src/index.ts +0 -91
- package/src/manifest.ts +0 -197
- package/src/responsive/breakpoints.ts +0 -15
- package/src/responsive/createMediaQueries.ts +0 -43
- package/src/responsive/index.ts +0 -15
- package/src/responsive/makeItResponsive.ts +0 -223
- package/src/responsive/normalizeTheme.ts +0 -79
- package/src/responsive/optimizeBreakpointDeltas.ts +0 -190
- package/src/responsive/optimizeTheme.ts +0 -60
- package/src/responsive/sortBreakpoints.ts +0 -10
- package/src/responsive/transformTheme.ts +0 -54
- package/src/styles/alignContent.ts +0 -62
- package/src/styles/extendCss.ts +0 -26
- package/src/styles/index.ts +0 -16
- package/src/styles/shorthands/borderRadius.ts +0 -89
- package/src/styles/shorthands/edge.ts +0 -108
- package/src/styles/shorthands/index.ts +0 -4
- package/src/styles/styles/camelToKebab.ts +0 -3
- package/src/styles/styles/index.ts +0 -132
- package/src/styles/styles/processDescriptor.ts +0 -136
- package/src/styles/styles/propertyMap.ts +0 -438
- package/src/styles/styles/types.ts +0 -368
- package/src/types.ts +0 -175
- package/src/units/index.ts +0 -6
- package/src/units/stripUnit.ts +0 -25
- package/src/units/value.ts +0 -47
- package/src/units/values.ts +0 -40
package/src/index.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import type { TProvider } from './context'
|
|
2
|
-
import Provider, { context } from './context'
|
|
3
|
-
import type { PyreonTheme } from './enrichTheme'
|
|
4
|
-
import { enrichTheme } from './enrichTheme'
|
|
5
|
-
import type {
|
|
6
|
-
Breakpoints,
|
|
7
|
-
CreateMediaQueries,
|
|
8
|
-
MakeItResponsive,
|
|
9
|
-
MakeItResponsiveStyles,
|
|
10
|
-
NormalizeTheme,
|
|
11
|
-
SortBreakpoints,
|
|
12
|
-
TransformTheme,
|
|
13
|
-
} from './responsive'
|
|
14
|
-
import {
|
|
15
|
-
breakpoints,
|
|
16
|
-
createMediaQueries,
|
|
17
|
-
makeItResponsive,
|
|
18
|
-
normalizeTheme,
|
|
19
|
-
sortBreakpoints,
|
|
20
|
-
transformTheme,
|
|
21
|
-
} from './responsive'
|
|
22
|
-
import type {
|
|
23
|
-
AlignContent,
|
|
24
|
-
AlignContentAlignXKeys,
|
|
25
|
-
AlignContentAlignYKeys,
|
|
26
|
-
AlignContentDirectionKeys,
|
|
27
|
-
ExtendCss,
|
|
28
|
-
ITheme,
|
|
29
|
-
Styles,
|
|
30
|
-
StylesTheme,
|
|
31
|
-
} from './styles'
|
|
32
|
-
import {
|
|
33
|
-
ALIGN_CONTENT_DIRECTION,
|
|
34
|
-
ALIGN_CONTENT_MAP_X,
|
|
35
|
-
ALIGN_CONTENT_MAP_Y,
|
|
36
|
-
alignContent,
|
|
37
|
-
extendCss,
|
|
38
|
-
styles,
|
|
39
|
-
} from './styles'
|
|
40
|
-
import type { BrowserColors, Color, Defaults, PropertyValue, UnitValue } from './types'
|
|
41
|
-
import type { StripUnit, Value, Values } from './units'
|
|
42
|
-
import { stripUnit, value, values } from './units'
|
|
43
|
-
|
|
44
|
-
export type {
|
|
45
|
-
AlignContent,
|
|
46
|
-
AlignContentAlignXKeys,
|
|
47
|
-
AlignContentAlignYKeys,
|
|
48
|
-
AlignContentDirectionKeys,
|
|
49
|
-
Breakpoints,
|
|
50
|
-
BrowserColors,
|
|
51
|
-
Color,
|
|
52
|
-
CreateMediaQueries,
|
|
53
|
-
Defaults,
|
|
54
|
-
ExtendCss,
|
|
55
|
-
ITheme,
|
|
56
|
-
MakeItResponsive,
|
|
57
|
-
MakeItResponsiveStyles,
|
|
58
|
-
NormalizeTheme,
|
|
59
|
-
PropertyValue,
|
|
60
|
-
PyreonTheme,
|
|
61
|
-
SortBreakpoints,
|
|
62
|
-
StripUnit,
|
|
63
|
-
Styles,
|
|
64
|
-
StylesTheme,
|
|
65
|
-
TProvider,
|
|
66
|
-
TransformTheme,
|
|
67
|
-
UnitValue,
|
|
68
|
-
Value,
|
|
69
|
-
Values,
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export {
|
|
73
|
-
ALIGN_CONTENT_DIRECTION,
|
|
74
|
-
ALIGN_CONTENT_MAP_X,
|
|
75
|
-
ALIGN_CONTENT_MAP_Y,
|
|
76
|
-
alignContent,
|
|
77
|
-
breakpoints,
|
|
78
|
-
context,
|
|
79
|
-
createMediaQueries,
|
|
80
|
-
enrichTheme,
|
|
81
|
-
extendCss,
|
|
82
|
-
makeItResponsive,
|
|
83
|
-
normalizeTheme,
|
|
84
|
-
Provider,
|
|
85
|
-
sortBreakpoints,
|
|
86
|
-
stripUnit,
|
|
87
|
-
styles,
|
|
88
|
-
transformTheme,
|
|
89
|
-
value,
|
|
90
|
-
values,
|
|
91
|
-
}
|
package/src/manifest.ts
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { defineManifest } from '@pyreon/manifest'
|
|
2
|
-
|
|
3
|
-
export default defineManifest({
|
|
4
|
-
name: '@pyreon/unistyle',
|
|
5
|
-
title: 'Responsive CSS Utilities',
|
|
6
|
-
tagline:
|
|
7
|
-
'Responsive breakpoints, CSS property mappings, unit utilities, theme enrichment',
|
|
8
|
-
description:
|
|
9
|
-
'Foundational responsive-style layer that powers every visual package above it (`elements`, `rocketstyle`, `coolgrid`, `kinetic`). `enrichTheme()` merges a partial user theme with the default breakpoints / spacing / unit utilities so the rest of the system has a complete theme to read. `makeItResponsive()` turns a value or per-breakpoint map into the right CSS for the current screen. `createMediaQueries()` builds breakpoint-keyed media queries; `styles()` generates CSS from a theme; `alignContent()` resolves alignment shorthand to flex / grid CSS. The package is the single source of truth for responsive prop semantics across the UI system.',
|
|
10
|
-
category: 'browser',
|
|
11
|
-
features: [
|
|
12
|
-
'enrichTheme(theme) — merge a partial theme with default breakpoints / spacing / units',
|
|
13
|
-
'breakpoints() — default responsive breakpoint set',
|
|
14
|
-
'createMediaQueries(breakpoints) — build breakpoint-keyed media query strings',
|
|
15
|
-
'makeItResponsive() — resolve a value / array / breakpoint object to CSS for the current screen',
|
|
16
|
-
'styles(theme) — generate CSS from a theme',
|
|
17
|
-
'alignContent() — resolve alignX / alignY / direction to flex CSS',
|
|
18
|
-
'extendCss() — extend a CSS definition with overrides',
|
|
19
|
-
'stripUnit / value / values — unit-utility helpers',
|
|
20
|
-
'Provider / context — React-style provider for the theme (used internally by PyreonUI)',
|
|
21
|
-
],
|
|
22
|
-
longExample: `import { enrichTheme, makeItResponsive, createMediaQueries, alignContent } from '@pyreon/unistyle'
|
|
23
|
-
|
|
24
|
-
// 1. Enrich a partial user theme with defaults — required before passing to PyreonUI
|
|
25
|
-
const theme = enrichTheme({
|
|
26
|
-
colors: { primary: '#3b82f6', secondary: '#6366f1' },
|
|
27
|
-
fonts: { body: 'Inter, sans-serif' },
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
// 2. Build media queries keyed by breakpoint name
|
|
31
|
-
const queries = createMediaQueries(theme.breakpoints)
|
|
32
|
-
// → { xs: '@media (min-width: 0)', sm: '@media (min-width: 640px)', md: '...', ... }
|
|
33
|
-
|
|
34
|
-
// 3. Responsive props — single value, mobile-first array, or breakpoint object
|
|
35
|
-
const padding = makeItResponsive({ value: [8, 12, 16], property: 'padding', theme })
|
|
36
|
-
// → 'padding: 8px; @media (...) { padding: 12px } @media (...) { padding: 16px }'
|
|
37
|
-
|
|
38
|
-
const padding2 = makeItResponsive({
|
|
39
|
-
value: { xs: 8, md: 16, xl: 24 },
|
|
40
|
-
property: 'padding',
|
|
41
|
-
theme,
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
// 4. alignContent maps shorthand to flex CSS
|
|
45
|
-
const flexCss = alignContent({ alignX: 'center', alignY: 'start', direction: 'row' })
|
|
46
|
-
// → 'justify-content: center; align-items: flex-start;'`,
|
|
47
|
-
api: [
|
|
48
|
-
{
|
|
49
|
-
name: 'enrichTheme',
|
|
50
|
-
kind: 'function',
|
|
51
|
-
signature: 'enrichTheme(theme: PartialTheme): Theme',
|
|
52
|
-
summary:
|
|
53
|
-
'Merge a partial theme with the full default theme (breakpoints, spacing, unit utilities, fallback colors). Always call this before passing a user theme to `PyreonUI` — raw theme objects miss the default breakpoints and spacing scale that the rest of the UI system reads from. Idempotent: enriching an already-enriched theme is a no-op.',
|
|
54
|
-
example: `import { enrichTheme } from "@pyreon/unistyle"
|
|
55
|
-
|
|
56
|
-
const theme = enrichTheme({
|
|
57
|
-
colors: { primary: "#3b82f6", secondary: "#6366f1" },
|
|
58
|
-
fonts: { body: "Inter, sans-serif" },
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
// Merges user overrides with default breakpoints, spacing, and units`,
|
|
62
|
-
mistakes: [
|
|
63
|
-
'Passing the raw partial theme to `<PyreonUI theme={...}>` without enriching — `theme.breakpoints` is undefined and every responsive prop falls back to the desktop value',
|
|
64
|
-
'Mutating the theme after passing it to `PyreonUI` — the styler resolver caches off the theme identity; clone + re-enrich for whole-theme swaps',
|
|
65
|
-
],
|
|
66
|
-
seeAlso: ['breakpoints', 'createMediaQueries'],
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
name: 'breakpoints',
|
|
70
|
-
kind: 'function',
|
|
71
|
-
signature: 'breakpoints(): Breakpoints',
|
|
72
|
-
summary:
|
|
73
|
-
'Return the default breakpoint set keyed by name (`xs`, `sm`, `md`, `lg`, `xl`, `xxl`) with min-width values in pixels. The same map is folded into `enrichTheme()` output, so most consumers read `theme.breakpoints` rather than calling this directly. Use it when you need the defaults outside a theme context (e.g. building a custom theme programmatically).',
|
|
74
|
-
example: `import { breakpoints } from '@pyreon/unistyle'
|
|
75
|
-
|
|
76
|
-
const bp = breakpoints()
|
|
77
|
-
// { xs: 0, sm: 640, md: 768, lg: 1024, xl: 1280, xxl: 1536 }`,
|
|
78
|
-
seeAlso: ['enrichTheme', 'createMediaQueries'],
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
name: 'createMediaQueries',
|
|
82
|
-
kind: 'function',
|
|
83
|
-
signature: 'createMediaQueries(breakpoints: Breakpoints): Record<string, string>',
|
|
84
|
-
summary:
|
|
85
|
-
'Build a record of media-query strings keyed by breakpoint name. Each value is a `min-width` query — `xs` is `(min-width: 0)`, `sm` becomes `(min-width: 640px)`, and so on. Used internally by `makeItResponsive()`; expose to consumers when they need to compose custom CSS-in-JS rules outside the responsive-prop pipeline.',
|
|
86
|
-
example: `import { createMediaQueries, breakpoints } from '@pyreon/unistyle'
|
|
87
|
-
|
|
88
|
-
const queries = createMediaQueries(breakpoints())
|
|
89
|
-
// { xs: '@media (min-width: 0)', sm: '@media (min-width: 640px)', md: '@media (min-width: 768px)', ... }`,
|
|
90
|
-
seeAlso: ['breakpoints', 'makeItResponsive'],
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
name: 'makeItResponsive',
|
|
94
|
-
kind: 'function',
|
|
95
|
-
signature:
|
|
96
|
-
'makeItResponsive<T>(options: { value: T | T[] | Record<string, T>; property: string; theme: Theme }): string',
|
|
97
|
-
summary:
|
|
98
|
-
'Resolve a responsive prop value to CSS for the current screen. Accepts three input shapes: single value (applies at all breakpoints), mobile-first array `[xs, sm, md, lg]` (each entry maps to the next breakpoint), or breakpoint object `{ xs: ..., md: ..., xl: ... }` (named keys map directly). The output is a CSS string with media queries already embedded; insert into a styled component template literal.',
|
|
99
|
-
example: `import { makeItResponsive } from '@pyreon/unistyle'
|
|
100
|
-
|
|
101
|
-
makeItResponsive({ value: 16, property: 'padding', theme })
|
|
102
|
-
// → 'padding: 16px;'
|
|
103
|
-
|
|
104
|
-
makeItResponsive({ value: [8, 12, 16], property: 'padding', theme })
|
|
105
|
-
// → 'padding: 8px; @media (min-width: 640px) { padding: 12px } @media (min-width: 768px) { padding: 16px }'
|
|
106
|
-
|
|
107
|
-
makeItResponsive({ value: { xs: 8, md: 16, xl: 24 }, property: 'padding', theme })
|
|
108
|
-
// → '@media (min-width: 0) { padding: 8px } @media (min-width: 768px) { padding: 16px } @media (min-width: 1280px) { padding: 24px }'`,
|
|
109
|
-
mistakes: [
|
|
110
|
-
'Passing CSS-spec property names (`borderTopWidth`) — unistyle uses property-first naming (`borderWidthTop`); the responsive transformer expects the unistyle convention',
|
|
111
|
-
'Forgetting to pass an enriched theme — without `theme.breakpoints`, the array form falls back to the first value at every breakpoint',
|
|
112
|
-
],
|
|
113
|
-
seeAlso: ['createMediaQueries', 'styles'],
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
name: 'styles',
|
|
117
|
-
kind: 'function',
|
|
118
|
-
signature: 'styles(theme: Theme): string',
|
|
119
|
-
summary:
|
|
120
|
-
'Generate the CSS string for a complete theme — colors, spacing, fonts, breakpoints, the works. Used to produce the cascade of CSS variables / global declarations that backs every styled component. Most consumers don\\\'t call this directly; the `PyreonUI` provider invokes it internally on theme mount.',
|
|
121
|
-
example: `import { styles, enrichTheme } from '@pyreon/unistyle'
|
|
122
|
-
|
|
123
|
-
const theme = enrichTheme({ colors: { primary: '#3b82f6' } })
|
|
124
|
-
const css = styles(theme)
|
|
125
|
-
// → ':root { --color-primary: #3b82f6; --spacing-xs: 4px; ... }'`,
|
|
126
|
-
seeAlso: ['enrichTheme', 'extendCss'],
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
name: 'alignContent',
|
|
130
|
-
kind: 'function',
|
|
131
|
-
signature:
|
|
132
|
-
"alignContent(options: { alignX?: AlignXKey; alignY?: AlignYKey; direction?: 'row' | 'column' | 'inline' | 'rows' }): string",
|
|
133
|
-
summary:
|
|
134
|
-
'Resolve `alignX` / `alignY` / `direction` shorthand to the matching flex / grid CSS (`justify-content`, `align-items`). The Element / Row / Column primitives use this internally — it\\\'s exposed for custom layout components that want the same alignment semantics. `direction: "inline"` maps to `row`; `direction: "rows"` maps to `column`.',
|
|
135
|
-
example: `import { alignContent } from '@pyreon/unistyle'
|
|
136
|
-
|
|
137
|
-
alignContent({ alignX: 'center', alignY: 'start', direction: 'row' })
|
|
138
|
-
// → 'justify-content: center; align-items: flex-start;'
|
|
139
|
-
|
|
140
|
-
alignContent({ alignX: 'spaceBetween', direction: 'inline' })
|
|
141
|
-
// → 'justify-content: space-between;'`,
|
|
142
|
-
seeAlso: ['makeItResponsive'],
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
name: 'extendCss',
|
|
146
|
-
kind: 'function',
|
|
147
|
-
signature: 'extendCss(base: ExtendCss, override?: ExtendCss): ExtendCss',
|
|
148
|
-
summary:
|
|
149
|
-
'Extend a CSS definition (theme block, style descriptor) with overrides — deep-merges nested objects without losing the base. Used by rocketstyle dimension chains to layer dimension-specific CSS over a baseline. The base is not mutated; the result is a new object.',
|
|
150
|
-
example: `import { extendCss } from '@pyreon/unistyle'
|
|
151
|
-
|
|
152
|
-
const base = { color: 'red', hover: { color: 'darkred' } }
|
|
153
|
-
const extended = extendCss(base, { hover: { background: 'pink' } })
|
|
154
|
-
// → { color: 'red', hover: { color: 'darkred', background: 'pink' } }`,
|
|
155
|
-
seeAlso: ['styles'],
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
name: 'stripUnit',
|
|
159
|
-
kind: 'function',
|
|
160
|
-
signature: 'stripUnit(value: string | number): number',
|
|
161
|
-
summary:
|
|
162
|
-
'Strip the unit suffix from a CSS value and return the numeric part (`"16px"` → `16`, `"1.5rem"` → `1.5`). Returns the input unchanged when already a number. Useful for arithmetic on theme values declared as strings (`"16px"`) without manually parsing.',
|
|
163
|
-
example: `import { stripUnit } from '@pyreon/unistyle'
|
|
164
|
-
|
|
165
|
-
stripUnit('16px') // → 16
|
|
166
|
-
stripUnit('1.5rem') // → 1.5
|
|
167
|
-
stripUnit(16) // → 16`,
|
|
168
|
-
seeAlso: ['value', 'values'],
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
name: 'value',
|
|
172
|
-
kind: 'function',
|
|
173
|
-
signature: 'value(input: PropertyValue, fallback?: PropertyValue): UnitValue',
|
|
174
|
-
summary:
|
|
175
|
-
'Parse and validate a single property value into a `UnitValue` shape (`{ value, unit }`). Accepts numbers (treated as pixels), strings with units (`"16px"`, `"1rem"`, `"50%"`), or objects already in `UnitValue` form. Optional `fallback` is returned when the input is invalid. The companion `values()` does the same over an array.',
|
|
176
|
-
example: `import { value } from '@pyreon/unistyle'
|
|
177
|
-
|
|
178
|
-
value(16) // → { value: 16, unit: 'px' }
|
|
179
|
-
value('1.5rem') // → { value: 1.5, unit: 'rem' }
|
|
180
|
-
value('50%') // → { value: 50, unit: '%' }
|
|
181
|
-
value('garbage', 0) // → { value: 0, unit: 'px' }`,
|
|
182
|
-
seeAlso: ['stripUnit', 'values'],
|
|
183
|
-
},
|
|
184
|
-
],
|
|
185
|
-
gotchas: [
|
|
186
|
-
{
|
|
187
|
-
label: 'Single source for responsive semantics',
|
|
188
|
-
note:
|
|
189
|
-
'Every visual package (`elements`, `rocketstyle`, `coolgrid`, `kinetic`) reads breakpoints / spacing / unit conventions from this package. Override defaults via `enrichTheme()` once at the app root rather than per-component.',
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
label: 'CSS property naming',
|
|
193
|
-
note:
|
|
194
|
-
'Unistyle uses property-first naming (`borderWidthTop`, `borderColorLeft`) rather than CSS-spec order (`borderTopWidth`, `borderLeftColor`). Stick to the unistyle convention when authoring components — the responsive transformer expects it.',
|
|
195
|
-
},
|
|
196
|
-
],
|
|
197
|
-
})
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
type Css = (strings: TemplateStringsArray, ...values: any[]) => any
|
|
2
|
-
|
|
3
|
-
export type CreateMediaQueries = <
|
|
4
|
-
B extends Record<string, number>,
|
|
5
|
-
R extends number,
|
|
6
|
-
C extends Css,
|
|
7
|
-
>(props: {
|
|
8
|
-
breakpoints: B
|
|
9
|
-
rootSize: R
|
|
10
|
-
css: C
|
|
11
|
-
}) => Record<keyof B, (...args: any[]) => string>
|
|
12
|
-
|
|
13
|
-
// Implementation uses Record<string, ...> which is widened from Record<keyof B, ...>;
|
|
14
|
-
// the generic constraint on CreateMediaQueries ensures callers get the narrower type.
|
|
15
|
-
const createMediaQueries: CreateMediaQueries = ((props: {
|
|
16
|
-
breakpoints: Record<string, number>
|
|
17
|
-
rootSize: number
|
|
18
|
-
css: Css
|
|
19
|
-
}) => {
|
|
20
|
-
const { breakpoints, rootSize, css } = props
|
|
21
|
-
|
|
22
|
-
// Direct for-in + mutation. The prior `Object.keys.reduce` allocated the
|
|
23
|
-
// keys array and paid reduce-callback overhead per iteration. Hot at
|
|
24
|
-
// PyreonUI mount and on any theme/rootSize change. Ported from
|
|
25
|
-
// vitus-labs `e573e6c4`; measured upstream: +15.9%.
|
|
26
|
-
const acc: Record<string, (...args: [TemplateStringsArray, ...any[]]) => string> = {}
|
|
27
|
-
for (const key in breakpoints) {
|
|
28
|
-
const breakpointValue = breakpoints[key]
|
|
29
|
-
if (breakpointValue === 0) {
|
|
30
|
-
acc[key] = (...args: [TemplateStringsArray, ...any[]]) => css(...args)
|
|
31
|
-
} else if (breakpointValue != null) {
|
|
32
|
-
const emSize = breakpointValue / rootSize
|
|
33
|
-
acc[key] = (...args: [TemplateStringsArray, ...any[]]) => css`
|
|
34
|
-
@media only screen and (min-width: ${emSize}em) {
|
|
35
|
-
${css(...args)};
|
|
36
|
-
}
|
|
37
|
-
`
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return acc
|
|
41
|
-
}) as CreateMediaQueries
|
|
42
|
-
|
|
43
|
-
export default createMediaQueries
|
package/src/responsive/index.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export type { Breakpoints } from './breakpoints'
|
|
2
|
-
export { default as breakpoints } from './breakpoints'
|
|
3
|
-
export type { CreateMediaQueries } from './createMediaQueries'
|
|
4
|
-
export { default as createMediaQueries } from './createMediaQueries'
|
|
5
|
-
export type { MakeItResponsive, MakeItResponsiveStyles } from './makeItResponsive'
|
|
6
|
-
export { default as makeItResponsive } from './makeItResponsive'
|
|
7
|
-
export type { NormalizeTheme } from './normalizeTheme'
|
|
8
|
-
export { default as normalizeTheme } from './normalizeTheme'
|
|
9
|
-
export { default as optimizeBreakpointDeltas } from './optimizeBreakpointDeltas'
|
|
10
|
-
export type { OptimizeTheme } from './optimizeTheme'
|
|
11
|
-
export { default as optimizeTheme } from './optimizeTheme'
|
|
12
|
-
export type { SortBreakpoints } from './sortBreakpoints'
|
|
13
|
-
export { default as sortBreakpoints } from './sortBreakpoints'
|
|
14
|
-
export type { TransformTheme } from './transformTheme'
|
|
15
|
-
export { default as transformTheme } from './transformTheme'
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { isEmpty } from '@pyreon/ui-core'
|
|
2
|
-
import type createMediaQueries from './createMediaQueries'
|
|
3
|
-
import normalizeTheme from './normalizeTheme'
|
|
4
|
-
import optimizeBreakpointDeltas from './optimizeBreakpointDeltas'
|
|
5
|
-
import optimizeTheme from './optimizeTheme'
|
|
6
|
-
import type sortBreakpoints from './sortBreakpoints'
|
|
7
|
-
import transformTheme from './transformTheme'
|
|
8
|
-
|
|
9
|
-
type Css = (strings: TemplateStringsArray, ...values: any[]) => any
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Coerce a styles-callback result to a CSS string for delta optimization.
|
|
13
|
-
* Returns null when the engine's result type can't be stringified cleanly
|
|
14
|
-
* (e.g. styled-components / Emotion objects whose default toString() yields
|
|
15
|
-
* "[object Object]") — caller falls back to the unoptimized path.
|
|
16
|
-
*
|
|
17
|
-
* Styler's CSSResult provides toString() that resolves with empty props,
|
|
18
|
-
* so any function interpolation that needs render-time props must come from
|
|
19
|
-
* the styles-callback closure (theme is destructured at call time, not
|
|
20
|
-
* resolved later). Verified across the project's styles callbacks.
|
|
21
|
-
*/
|
|
22
|
-
const stringifyResult = (result: unknown): string | null => {
|
|
23
|
-
if (result == null) return ''
|
|
24
|
-
if (typeof result === 'string') return result
|
|
25
|
-
// CSSResult duck-type fast path: has `strings` (TemplateStringsArray) and
|
|
26
|
-
// `values`. We know its toString() resolves to clean CSS, so we can skip
|
|
27
|
-
// the "[object Foo]" validation for the common path.
|
|
28
|
-
if (typeof result === 'object' && 'strings' in result && 'values' in result) {
|
|
29
|
-
return String(result)
|
|
30
|
-
}
|
|
31
|
-
// Foreign engine result — coerce and validate. Default
|
|
32
|
-
// Object.prototype.toString → "[object Foo]" → bail out so caller can fall
|
|
33
|
-
// back to the unoptimized path.
|
|
34
|
-
const text = String(result)
|
|
35
|
-
return text.includes('[object ') ? null : text
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
type CustomTheme = Record<string, unknown>
|
|
39
|
-
|
|
40
|
-
type Theme = Partial<{
|
|
41
|
-
rootSize: number
|
|
42
|
-
breakpoints: Record<string, number>
|
|
43
|
-
__PYREON__: Partial<{
|
|
44
|
-
media: ReturnType<typeof createMediaQueries>
|
|
45
|
-
sortedBreakpoints: ReturnType<typeof sortBreakpoints>
|
|
46
|
-
}>
|
|
47
|
-
}> &
|
|
48
|
-
CustomTheme
|
|
49
|
-
|
|
50
|
-
export type MakeItResponsiveStyles<T extends Partial<Record<string, any>> = any> = ({
|
|
51
|
-
theme,
|
|
52
|
-
css,
|
|
53
|
-
rootSize,
|
|
54
|
-
globalTheme,
|
|
55
|
-
}: {
|
|
56
|
-
theme: T
|
|
57
|
-
css: Css
|
|
58
|
-
rootSize?: number | undefined
|
|
59
|
-
globalTheme?: Record<string, any> | undefined
|
|
60
|
-
}) => ReturnType<typeof css> | string | any
|
|
61
|
-
|
|
62
|
-
export type MakeItResponsive = ({
|
|
63
|
-
theme,
|
|
64
|
-
key,
|
|
65
|
-
css,
|
|
66
|
-
styles,
|
|
67
|
-
normalize,
|
|
68
|
-
}: {
|
|
69
|
-
theme?: CustomTheme
|
|
70
|
-
key?: string
|
|
71
|
-
css: any
|
|
72
|
-
styles: MakeItResponsiveStyles
|
|
73
|
-
normalize?: boolean
|
|
74
|
-
}) => (props: { theme?: Theme; [prop: string]: any }) => any
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Per-internal-theme cache:
|
|
78
|
-
* - `optimized`: the per-breakpoint theme object (`{ xs: {...}, md: {...} }`)
|
|
79
|
-
* after `normalize → transform → optimize`. Reused as long as the same
|
|
80
|
-
* `sortedBreakpoints` reference is passed in.
|
|
81
|
-
* - `rendered`: memoized FINAL output (array of media-wrapped CSSResults),
|
|
82
|
-
* keyed by the outer `theme` reference. Hit when the same internal theme
|
|
83
|
-
* AND the same outer theme render again — which is the common case when
|
|
84
|
-
* the provider value is stable. Avoids re-running renderStyles +
|
|
85
|
-
* optimizeBreakpointDeltas on every parent re-render.
|
|
86
|
-
*/
|
|
87
|
-
interface ThemeCacheEntry {
|
|
88
|
-
breakpoints: unknown
|
|
89
|
-
optimized: Record<string, Record<string, unknown>>
|
|
90
|
-
rendered?: WeakMap<object, unknown[]> | undefined
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const themeCache = new WeakMap<object, ThemeCacheEntry>()
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Core responsive engine used by every styled component in the system.
|
|
97
|
-
*
|
|
98
|
-
* Returns a styled-components interpolation function that:
|
|
99
|
-
* 1. Reads the component's theme prop (via `key` or direct `theme`)
|
|
100
|
-
* 2. Without breakpoints → renders plain CSS
|
|
101
|
-
* 3. With breakpoints → normalizes, transforms (property-per-breakpoint →
|
|
102
|
-
* breakpoint-per-property), optimizes (deduplicates identical breakpoints),
|
|
103
|
-
* deltas the per-breakpoint output against the mobile-first cascade
|
|
104
|
-
* (drops re-emitted unchanged declarations), and wraps each non-empty
|
|
105
|
-
* breakpoint's deltas in the appropriate `@media` query. Falls back to
|
|
106
|
-
* the unoptimized path if any breakpoint's render result can't be
|
|
107
|
-
* cleanly stringified.
|
|
108
|
-
*/
|
|
109
|
-
const makeItResponsive: MakeItResponsive =
|
|
110
|
-
({ theme: customTheme, key = '', css, styles, normalize = true }) =>
|
|
111
|
-
({ theme = {}, ...props }) => {
|
|
112
|
-
const internalTheme = customTheme || props[key]
|
|
113
|
-
|
|
114
|
-
// if no theme is defined, return empty object
|
|
115
|
-
if (isEmpty(internalTheme)) return ''
|
|
116
|
-
|
|
117
|
-
const { rootSize, breakpoints, __PYREON__, ...restTheme } = theme as Theme
|
|
118
|
-
|
|
119
|
-
const renderStyles = (styleTheme: Record<string, unknown>): ReturnType<typeof styles> =>
|
|
120
|
-
styles({ theme: styleTheme, css, rootSize, globalTheme: restTheme })
|
|
121
|
-
|
|
122
|
-
// if there are no breakpoints, return just standard css
|
|
123
|
-
if (isEmpty(breakpoints) || isEmpty(__PYREON__)) {
|
|
124
|
-
return css`
|
|
125
|
-
${renderStyles(internalTheme)}
|
|
126
|
-
`
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// isEmpty guard above ensures __PYREON__ is defined here
|
|
130
|
-
const { media, sortedBreakpoints } = __PYREON__ as NonNullable<typeof __PYREON__>
|
|
131
|
-
|
|
132
|
-
let optimizedTheme: Record<string, Record<string, unknown>>
|
|
133
|
-
const entry = themeCache.get(internalTheme)
|
|
134
|
-
const breakpointsMatch = entry?.breakpoints === sortedBreakpoints
|
|
135
|
-
|
|
136
|
-
// Full-render cache: same internal theme + same outer theme → return
|
|
137
|
-
// the previous render's output verbatim. CSSResult instances are
|
|
138
|
-
// immutable so reusing them is safe.
|
|
139
|
-
if (entry && breakpointsMatch && entry.rendered) {
|
|
140
|
-
const memoized = entry.rendered.get(theme as object)
|
|
141
|
-
if (memoized) return memoized
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (entry && breakpointsMatch) {
|
|
145
|
-
optimizedTheme = entry.optimized
|
|
146
|
-
} else {
|
|
147
|
-
let helperTheme = internalTheme
|
|
148
|
-
|
|
149
|
-
if (normalize) {
|
|
150
|
-
helperTheme = normalizeTheme({
|
|
151
|
-
theme: internalTheme,
|
|
152
|
-
breakpoints: sortedBreakpoints ?? [],
|
|
153
|
-
})
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const transformedTheme = transformTheme({
|
|
157
|
-
theme: helperTheme,
|
|
158
|
-
breakpoints: sortedBreakpoints ?? [],
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
optimizedTheme = optimizeTheme({
|
|
162
|
-
theme: transformedTheme,
|
|
163
|
-
breakpoints: sortedBreakpoints ?? [],
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
themeCache.set(internalTheme, {
|
|
167
|
-
breakpoints: sortedBreakpoints,
|
|
168
|
-
optimized: optimizedTheme,
|
|
169
|
-
// Preserve any pre-existing rendered cache when re-entering with a
|
|
170
|
-
// changed sortedBreakpoints reference — usually unreachable because
|
|
171
|
-
// breakpoints come from a stable provider value, but the explicit
|
|
172
|
-
// handling avoids a memory cliff in tests / HMR.
|
|
173
|
-
rendered: entry?.rendered,
|
|
174
|
-
})
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const bps = sortedBreakpoints ?? []
|
|
178
|
-
|
|
179
|
-
// Resolve each per-breakpoint render to a string so the delta optimizer
|
|
180
|
-
// can diff at the property level. If any breakpoint's result can't be
|
|
181
|
-
// cleanly stringified (foreign engine result), fall back to the original
|
|
182
|
-
// unoptimized path that lets the engine resolve interpolations itself.
|
|
183
|
-
const renderedTexts: (string | null)[] = bps.map((item: string) => {
|
|
184
|
-
const breakpointTheme = optimizedTheme[item]
|
|
185
|
-
if (!breakpointTheme || !media) return ''
|
|
186
|
-
return stringifyResult(renderStyles(breakpointTheme))
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
const canOptimize = renderedTexts.every((t) => t !== null)
|
|
190
|
-
let result: unknown[]
|
|
191
|
-
if (canOptimize) {
|
|
192
|
-
const deltas = optimizeBreakpointDeltas(renderedTexts as string[])
|
|
193
|
-
result = bps.map((item: string, i: number) => {
|
|
194
|
-
const cssText = deltas[i]
|
|
195
|
-
if (!cssText || !media) return ''
|
|
196
|
-
return (media as Record<string, any>)[item]`${cssText}`
|
|
197
|
-
})
|
|
198
|
-
} else {
|
|
199
|
-
result = bps.map((item: string) => {
|
|
200
|
-
const breakpointTheme = optimizedTheme[item]
|
|
201
|
-
if (!breakpointTheme || !media) return ''
|
|
202
|
-
const r = renderStyles(breakpointTheme)
|
|
203
|
-
return (media as Record<string, any>)[item]`
|
|
204
|
-
${r};
|
|
205
|
-
`
|
|
206
|
-
})
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Memoize the final rendered output by outer theme reference. Stable
|
|
210
|
-
// theme + stable internal theme → future renders return immediately.
|
|
211
|
-
// Invariant: by this point themeCache always has an entry for
|
|
212
|
-
// internalTheme — earlier paths either hit the rendered-cache and
|
|
213
|
-
// returned, or wrote one via themeCache.set above.
|
|
214
|
-
const cacheEntry = themeCache.get(internalTheme)
|
|
215
|
-
if (cacheEntry) {
|
|
216
|
-
if (!cacheEntry.rendered) cacheEntry.rendered = new WeakMap()
|
|
217
|
-
cacheEntry.rendered.set(theme as object, result)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return result
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
export default makeItResponsive
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
type AssignToBreakpointKey = (
|
|
2
|
-
breakpoints: string[],
|
|
3
|
-
) => (
|
|
4
|
-
valueFn: (breakpoint: string, i: number, bps: string[], result: Record<string, unknown>) => void,
|
|
5
|
-
) => Record<string, unknown>
|
|
6
|
-
|
|
7
|
-
const assignToBreakpointKey: AssignToBreakpointKey = (breakpoints) => (valueFn) => {
|
|
8
|
-
const result: Record<string, unknown> = {}
|
|
9
|
-
breakpoints.forEach((item, i) => {
|
|
10
|
-
result[item] = valueFn(item, i, breakpoints, result)
|
|
11
|
-
})
|
|
12
|
-
return result
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const handleArrayCb = (arr: (string | number)[]) => (_: unknown, i: number) => {
|
|
16
|
-
const currentValue = arr[i]
|
|
17
|
-
const lastValue = arr[arr.length - 1]
|
|
18
|
-
return currentValue ?? lastValue
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const handleObjectCb =
|
|
22
|
-
(obj: Record<string, unknown>) =>
|
|
23
|
-
(bp: string, i: number, bps: string[], res: Record<string, unknown>) => {
|
|
24
|
-
const currentValue = obj[bp]
|
|
25
|
-
const prevBp = bps[i - 1]
|
|
26
|
-
const previousValue = prevBp != null ? res[prevBp] : undefined
|
|
27
|
-
if (currentValue != null) return currentValue
|
|
28
|
-
return previousValue
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const handleValueCb = (value: unknown) => () => value
|
|
32
|
-
|
|
33
|
-
// for-in early-exit avoids the `Object.values(props)` array allocation
|
|
34
|
-
// that the prior `.some()` paid on every theme normalization decision.
|
|
35
|
-
// Fires once per per-breakpoint theme transform; the early `return true`
|
|
36
|
-
// is hit by any responsive token, so most calls bail out quickly. Ported
|
|
37
|
-
// from vitus-labs `e573e6c4`; measured upstream: +20.3%.
|
|
38
|
-
const shouldNormalize = (props: Record<string, any>) => {
|
|
39
|
-
for (const key in props) {
|
|
40
|
-
const item = props[key]
|
|
41
|
-
if (typeof item === 'object' || Array.isArray(item)) return true
|
|
42
|
-
}
|
|
43
|
-
return false
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export type NormalizeTheme = ({
|
|
47
|
-
theme,
|
|
48
|
-
breakpoints,
|
|
49
|
-
}: {
|
|
50
|
-
theme: Record<string, unknown>
|
|
51
|
-
breakpoints: string[]
|
|
52
|
-
}) => Record<string, unknown>
|
|
53
|
-
|
|
54
|
-
const normalizeTheme: NormalizeTheme = ({ theme, breakpoints }) => {
|
|
55
|
-
if (!shouldNormalize(theme)) return theme
|
|
56
|
-
|
|
57
|
-
const getBpValues = assignToBreakpointKey(breakpoints)
|
|
58
|
-
const result: Record<string, unknown> = {}
|
|
59
|
-
|
|
60
|
-
// for-in instead of Object.entries.forEach — avoids the entries-tuple
|
|
61
|
-
// array allocation per theme normalization (one outer alloc + one inner
|
|
62
|
-
// [k,v] tuple per property dropped). Ported from vitus-labs `e573e6c4`.
|
|
63
|
-
for (const key in theme) {
|
|
64
|
-
const value = theme[key]
|
|
65
|
-
if (value == null) continue
|
|
66
|
-
|
|
67
|
-
if (Array.isArray(value)) {
|
|
68
|
-
result[key] = getBpValues(handleArrayCb(value as (string | number)[]))
|
|
69
|
-
} else if (typeof value === 'object') {
|
|
70
|
-
result[key] = getBpValues(handleObjectCb(value as Record<string, any>))
|
|
71
|
-
} else {
|
|
72
|
-
result[key] = getBpValues(handleValueCb(value))
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return result
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export default normalizeTheme
|