@pyreon/unistyle 0.24.0 → 0.24.1

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/lib/index.js CHANGED
@@ -19,7 +19,8 @@ const breakpoints = {
19
19
  //#region src/responsive/createMediaQueries.ts
20
20
  const createMediaQueries = ((props) => {
21
21
  const { breakpoints, rootSize, css } = props;
22
- return Object.keys(breakpoints).reduce((acc, key) => {
22
+ const acc = {};
23
+ for (const key in breakpoints) {
23
24
  const breakpointValue = breakpoints[key];
24
25
  if (breakpointValue === 0) acc[key] = (...args) => css(...args);
25
26
  else if (breakpointValue != null) {
@@ -30,8 +31,8 @@ const createMediaQueries = ((props) => {
30
31
  }
31
32
  `;
32
33
  }
33
- return acc;
34
- }, {});
34
+ }
35
+ return acc;
35
36
  });
36
37
 
37
38
  //#endregion
@@ -56,17 +57,24 @@ const handleObjectCb = (obj) => (bp, i, bps, res) => {
56
57
  return previousValue;
57
58
  };
58
59
  const handleValueCb = (value) => () => value;
59
- const shouldNormalize = (props) => Object.values(props).some((item) => typeof item === "object" || Array.isArray(item));
60
+ const shouldNormalize = (props) => {
61
+ for (const key in props) {
62
+ const item = props[key];
63
+ if (typeof item === "object" || Array.isArray(item)) return true;
64
+ }
65
+ return false;
66
+ };
60
67
  const normalizeTheme = ({ theme, breakpoints }) => {
61
68
  if (!shouldNormalize(theme)) return theme;
62
69
  const getBpValues = assignToBreakpointKey(breakpoints);
63
70
  const result = {};
64
- Object.entries(theme).forEach(([key, value]) => {
65
- if (value == null) return;
71
+ for (const key in theme) {
72
+ const value = theme[key];
73
+ if (value == null) continue;
66
74
  if (Array.isArray(value)) result[key] = getBpValues(handleArrayCb(value));
67
75
  else if (typeof value === "object") result[key] = getBpValues(handleObjectCb(value));
68
76
  else result[key] = getBpValues(handleValueCb(value));
69
- });
77
+ }
70
78
  return result;
71
79
  };
72
80
 
@@ -196,11 +204,14 @@ const optimizeBreakpointDeltas = (cssStrings) => {
196
204
  const shallowEqual = (a, b) => {
197
205
  if (a === b) return true;
198
206
  if (!a || !b) return false;
199
- const keysA = Object.keys(a);
200
- const keysB = Object.keys(b);
201
- if (keysA.length !== keysB.length) return false;
202
- for (const key of keysA) if (a[key] !== b[key]) return false;
203
- return true;
207
+ let aCount = 0;
208
+ for (const key in a) {
209
+ aCount++;
210
+ if (a[key] !== b[key]) return false;
211
+ }
212
+ let bCount = 0;
213
+ for (const _ in b) bCount++;
214
+ return aCount === bCount;
204
215
  };
205
216
  /**
206
217
  * Removes breakpoints whose full-object styles are identical to the
@@ -242,21 +253,22 @@ const removeUnexpectedKeys = (obj, keys) => {
242
253
  const transformTheme = ({ theme, breakpoints }) => {
243
254
  const result = {};
244
255
  if (isEmpty(theme) || isEmpty(breakpoints)) return result;
245
- Object.entries(theme).forEach(([key, value]) => {
246
- if (Array.isArray(value) && value.length > 0) value.forEach((child, i) => {
256
+ for (const key in theme) {
257
+ const value = theme[key];
258
+ if (Array.isArray(value) && value.length > 0) for (let i = 0; i < value.length; i++) {
247
259
  const indexBreakpoint = breakpoints[i];
248
- if (indexBreakpoint == null) return;
249
- set(result, [indexBreakpoint, key], child);
250
- });
251
- else if (typeof value === "object" && value !== null) Object.entries(value).forEach(([childKey, childValue]) => {
252
- set(result, [childKey, key], childValue);
253
- });
254
- else if (value != null) {
260
+ if (indexBreakpoint == null) continue;
261
+ set(result, [indexBreakpoint, key], value[i]);
262
+ }
263
+ else if (typeof value === "object" && value !== null) {
264
+ const obj = value;
265
+ for (const childKey in obj) set(result, [childKey, key], obj[childKey]);
266
+ } else if (value != null) {
255
267
  const firstBreakpoint = breakpoints[0];
256
- if (firstBreakpoint == null) return;
268
+ if (firstBreakpoint == null) continue;
257
269
  set(result, [firstBreakpoint, key], value);
258
270
  }
259
- });
271
+ }
260
272
  return removeUnexpectedKeys(result, breakpoints);
261
273
  };
262
274
 
@@ -454,7 +466,7 @@ const ALIGN_CONTENT_DIRECTION = {
454
466
  const alignContent = (attrs) => {
455
467
  const { direction, alignX, alignY } = attrs;
456
468
  if (isEmpty(attrs) || !direction || !alignX || !alignY) return null;
457
- const isReverted = ["inline", "reverseInline"].includes(direction);
469
+ const isReverted = direction === "inline" || direction === "reverseInline";
458
470
  const dir = ALIGN_CONTENT_DIRECTION[direction];
459
471
  const x = ALIGN_CONTENT_MAP_X[alignX];
460
472
  const y = ALIGN_CONTENT_MAP_Y[alignY];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/unistyle",
3
- "version": "0.24.0",
3
+ "version": "0.24.1",
4
4
  "description": "Responsive theming and breakpoint utilities for Pyreon",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -44,7 +44,7 @@
44
44
  "devDependencies": {
45
45
  "@pyreon/manifest": "0.13.1",
46
46
  "@pyreon/test-utils": "^0.13.11",
47
- "@pyreon/typescript": "^0.24.0",
47
+ "@pyreon/typescript": "^0.24.1",
48
48
  "@vitest/browser-playwright": "^4.1.4",
49
49
  "@vitus-labs/tools-rolldown": "^2.4.0"
50
50
  },
@@ -52,9 +52,9 @@
52
52
  "node": ">= 22"
53
53
  },
54
54
  "dependencies": {
55
- "@pyreon/core": "^0.24.0",
56
- "@pyreon/reactivity": "^0.24.0",
57
- "@pyreon/styler": "^0.24.0",
58
- "@pyreon/ui-core": "^0.24.0"
55
+ "@pyreon/core": "^0.24.1",
56
+ "@pyreon/reactivity": "^0.24.1",
57
+ "@pyreon/styler": "^0.24.1",
58
+ "@pyreon/ui-core": "^0.24.1"
59
59
  }
60
60
  }
@@ -19,25 +19,25 @@ const createMediaQueries: CreateMediaQueries = ((props: {
19
19
  }) => {
20
20
  const { breakpoints, rootSize, css } = props
21
21
 
22
- return Object.keys(breakpoints).reduce<
23
- Record<string, (...args: [TemplateStringsArray, ...any[]]) => string>
24
- >((acc, key) => {
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) {
25
28
  const breakpointValue = breakpoints[key]
26
-
27
29
  if (breakpointValue === 0) {
28
30
  acc[key] = (...args: [TemplateStringsArray, ...any[]]) => css(...args)
29
31
  } else if (breakpointValue != null) {
30
32
  const emSize = breakpointValue / rootSize
31
-
32
33
  acc[key] = (...args: [TemplateStringsArray, ...any[]]) => css`
33
34
  @media only screen and (min-width: ${emSize}em) {
34
35
  ${css(...args)};
35
36
  }
36
37
  `
37
38
  }
38
-
39
- return acc
40
- }, {})
39
+ }
40
+ return acc
41
41
  }) as CreateMediaQueries
42
42
 
43
43
  export default createMediaQueries
@@ -30,8 +30,18 @@ const handleObjectCb =
30
30
 
31
31
  const handleValueCb = (value: unknown) => () => value
32
32
 
33
- const shouldNormalize = (props: Record<string, any>) =>
34
- Object.values(props).some((item) => typeof item === 'object' || Array.isArray(item))
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
+ }
35
45
 
36
46
  export type NormalizeTheme = ({
37
47
  theme,
@@ -47,8 +57,12 @@ const normalizeTheme: NormalizeTheme = ({ theme, breakpoints }) => {
47
57
  const getBpValues = assignToBreakpointKey(breakpoints)
48
58
  const result: Record<string, unknown> = {}
49
59
 
50
- Object.entries(theme).forEach(([key, value]) => {
51
- if (value == null) return
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
52
66
 
53
67
  if (Array.isArray(value)) {
54
68
  result[key] = getBpValues(handleArrayCb(value as (string | number)[]))
@@ -57,7 +71,7 @@ const normalizeTheme: NormalizeTheme = ({ theme, breakpoints }) => {
57
71
  } else {
58
72
  result[key] = getBpValues(handleValueCb(value))
59
73
  }
60
- })
74
+ }
61
75
 
62
76
  return result
63
77
  }
@@ -12,13 +12,18 @@ const shallowEqual = (
12
12
  ): boolean => {
13
13
  if (a === b) return true
14
14
  if (!a || !b) return false
15
- const keysA = Object.keys(a)
16
- const keysB = Object.keys(b)
17
- if (keysA.length !== keysB.length) return false
18
- for (const key of keysA) {
15
+ // for-in + counting avoids the two `Object.keys` array allocations the
16
+ // prior implementation paid on every breakpoint optimization step.
17
+ // Ported from vitus-labs `e573e6c4`; measured upstream: +4.0% on the
18
+ // EQUAL hot path (the common case in steady-state renders).
19
+ let aCount = 0
20
+ for (const key in a) {
21
+ aCount++
19
22
  if (a[key] !== b[key]) return false
20
23
  }
21
- return true
24
+ let bCount = 0
25
+ for (const _ in b) bCount++
26
+ return aCount === bCount
22
27
  }
23
28
 
24
29
  /**
@@ -24,23 +24,29 @@ const transformTheme: TransformTheme = ({ theme, breakpoints }) => {
24
24
 
25
25
  if (isEmpty(theme) || isEmpty(breakpoints)) return result
26
26
 
27
- Object.entries(theme).forEach(([key, value]) => {
27
+ // for-in + nested for-in avoids the two `Object.entries(...)` array
28
+ // allocations (outer + inner per object value) the prior forEach paid.
29
+ // Same for `value.forEach((child, i) => ...)` → indexed for-loop.
30
+ // Ported from vitus-labs `e573e6c4`.
31
+ for (const key in theme) {
32
+ const value = theme[key]
28
33
  if (Array.isArray(value) && value.length > 0) {
29
- value.forEach((child, i) => {
34
+ for (let i = 0; i < value.length; i++) {
30
35
  const indexBreakpoint = breakpoints[i]
31
- if (indexBreakpoint == null) return
32
- set(result, [indexBreakpoint, key], child)
33
- })
36
+ if (indexBreakpoint == null) continue
37
+ set(result, [indexBreakpoint, key], value[i])
38
+ }
34
39
  } else if (typeof value === 'object' && value !== null) {
35
- Object.entries(value).forEach(([childKey, childValue]) => {
36
- set(result, [childKey, key], childValue)
37
- })
40
+ const obj = value as Record<string, unknown>
41
+ for (const childKey in obj) {
42
+ set(result, [childKey, key], obj[childKey])
43
+ }
38
44
  } else if (value != null) {
39
45
  const firstBreakpoint = breakpoints[0]
40
- if (firstBreakpoint == null) return
46
+ if (firstBreakpoint == null) continue
41
47
  set(result, [firstBreakpoint, key], value)
42
48
  }
43
- })
49
+ }
44
50
 
45
51
  return removeUnexpectedKeys(result, breakpoints)
46
52
  }
@@ -47,7 +47,11 @@ const alignContent: AlignContent = (attrs) => {
47
47
  return null
48
48
  }
49
49
 
50
- const isReverted = ['inline', 'reverseInline'].includes(direction)
50
+ // Direct comparisons avoid the per-call 2-element array allocation that
51
+ // `['inline', 'reverseInline'].includes(direction)` paid. Hot path: fires
52
+ // for every styled component with a `direction` prop. Ported from
53
+ // vitus-labs `e573e6c4`.
54
+ const isReverted = direction === 'inline' || direction === 'reverseInline'
51
55
  const dir = ALIGN_CONTENT_DIRECTION[direction]
52
56
  const x = ALIGN_CONTENT_MAP_X[alignX]
53
57
  const y = ALIGN_CONTENT_MAP_Y[alignY]