@niibase/uniwind 1.6.2 → 1.6.3

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 (41) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/common/common/utils.js +9 -2
  3. package/dist/common/core/config/config.common.js +4 -7
  4. package/dist/common/core/config/config.js +42 -23
  5. package/dist/common/core/config/config.native.js +1 -3
  6. package/dist/common/core/web/cssListener.js +1 -1
  7. package/dist/common/hooks/useCSSVariable/useCSSVariable.js +2 -7
  8. package/dist/metro/index.cjs +10 -4
  9. package/dist/metro/index.mjs +11 -5
  10. package/dist/metro/metro-transformer.cjs +2 -4
  11. package/dist/metro/metro-transformer.mjs +2 -4
  12. package/dist/module/common/utils.d.ts +1 -0
  13. package/dist/module/common/utils.js +6 -0
  14. package/dist/module/core/config/config.common.d.ts +1 -1
  15. package/dist/module/core/config/config.common.js +3 -4
  16. package/dist/module/core/config/config.d.ts +4 -4
  17. package/dist/module/core/config/config.js +44 -25
  18. package/dist/module/core/config/config.native.js +1 -3
  19. package/dist/module/core/web/cssListener.js +1 -1
  20. package/dist/module/hooks/useCSSVariable/useCSSVariable.js +1 -6
  21. package/package.json +3 -3
  22. package/src/common/utils.ts +8 -0
  23. package/src/core/config/config.common.ts +4 -7
  24. package/src/core/config/config.native.ts +1 -3
  25. package/src/core/config/config.ts +61 -29
  26. package/src/core/logger.ts +0 -2
  27. package/src/core/native/parsers/transforms.ts +0 -1
  28. package/src/core/native/store.ts +0 -1
  29. package/src/core/web/cssListener.ts +2 -3
  30. package/src/hoc/withUniwind.native.tsx +0 -1
  31. package/src/hooks/useCSSVariable/useCSSVariable.ts +1 -8
  32. package/src/metro/addMetaToStylesTemplate.ts +1 -2
  33. package/src/metro/logger.ts +0 -2
  34. package/src/metro/metro-css-patches.ts +1 -2
  35. package/src/metro/metro-transformer.ts +1 -1
  36. package/src/metro/processor/css.ts +0 -1
  37. package/src/metro/processor/functions.ts +0 -1
  38. package/src/metro/resolvers.ts +12 -13
  39. package/src/metro/utils/common.ts +0 -1
  40. package/src/metro/utils/serialize.ts +0 -1
  41. package/src/types.ts +0 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## What's Changed in 1.6.3
2
+
3
+
4
+
5
+ ### 🐛 Bug Fixes
6
+
7
+ * use node resolver to prevent escaped traversal errors (#506) by @Brentlok
8
+ * updateCSSVariable inside scoped theme (#502) by @Brentlok
9
+ * inject cjs instead of esm to initialize (#501) by @Brentlok
10
+
11
+ ### 🏠 Chores
12
+
13
+ * update config attributes and lint rules (#504) by @Brentlok
14
+ * use oxlint instead of eslint (#503) by @Brentlok
15
+
16
+ ### 📦 Other
17
+
18
+ * Merge branch 'pre-release' by @divineniiquaye
19
+
20
+
21
+ **Full Changelog**: https://github.com/divineniiquaye/uniwind/compare/v1.6.2...v1.6.3
22
+
23
+
1
24
  ## What's Changed in 1.6.2
2
25
 
3
26
 
@@ -3,6 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isDefined = void 0;
6
+ exports.isDefined = exports.arrayEquals = void 0;
7
7
  const isDefined = value => value !== void 0 && value !== null;
8
- exports.isDefined = isDefined;
8
+ exports.isDefined = isDefined;
9
+ const arrayEquals = (a, b) => {
10
+ if (a.length !== b.length) {
11
+ return false;
12
+ }
13
+ return a.every((value, index) => value === b[index]);
14
+ };
15
+ exports.arrayEquals = arrayEquals;
@@ -84,13 +84,10 @@ class UniwindConfigBuilder {
84
84
  }
85
85
  }
86
86
  }
87
- updateCSSVariables(theme, variables) {
88
- theme;
89
- variables;
90
- }
91
- updateInsets(insets) {
92
- insets;
93
- }
87
+ // oxlint-disable-next-line typescript/no-unused-vars
88
+ updateCSSVariables(theme, cssVariables) {}
89
+ // oxlint-disable-next-line typescript/no-unused-vars
90
+ updateInsets(insets) {}
94
91
  __reinit(_, themes) {
95
92
  this._themes = themes;
96
93
  }
@@ -4,50 +4,69 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.Uniwind = void 0;
7
+ var _utils = require("../../common/utils");
7
8
  var _types = require("../../types");
8
9
  var _listener = require("../listener");
9
10
  var _logger = require("../logger");
11
+ var _web = require("../web");
10
12
  var _config = require("./config.common");
11
13
  class UniwindConfigBuilder extends _config.UniwindConfigBuilder {
12
- runtimeCSSVariables = /* @__PURE__ */new Map();
14
+ cssRules;
13
15
  constructor() {
14
16
  super();
15
17
  }
16
18
  updateCSSVariables(theme, variables) {
19
+ if (typeof document === "undefined") {
20
+ return;
21
+ }
22
+ const uniwindRules = this.getUniwindDynamicCSSRules();
17
23
  Object.entries(variables).forEach(([varName, varValue]) => {
18
24
  if (!varName.startsWith("--") && __DEV__) {
19
25
  _logger.Logger.error(`CSS variable name must start with "--", instead got: ${varName}`);
20
- return;
21
- }
22
- const runtimeCSSVariables = this.runtimeCSSVariables.get(theme) ?? {};
23
- runtimeCSSVariables[varName] = varValue;
24
- this.runtimeCSSVariables.set(theme, runtimeCSSVariables);
25
- if (theme === this.currentTheme) {
26
- this.applyCSSVariable(varName, varValue);
27
26
  }
27
+ const existingRules = Object.fromEntries(uniwindRules.map(rule => [rule.theme, (0, _web.getWebVariable)(varName, {
28
+ scopedTheme: rule.theme
29
+ })]));
30
+ uniwindRules.forEach(rule => {
31
+ if (rule.theme === theme) {
32
+ rule.style.setProperty(varName, typeof varValue === "number" ? `${varValue}px` : varValue);
33
+ return;
34
+ }
35
+ rule.style.setProperty(varName, existingRules[rule.theme] ?? null);
36
+ });
28
37
  });
29
- if (theme === this.currentTheme) {
30
- _listener.UniwindListener.notify([_types.StyleDependency.Variables]);
31
- }
38
+ _listener.UniwindListener.notify([_types.StyleDependency.Variables]);
32
39
  }
33
- onThemeChange() {
34
- if (typeof document === "undefined") {
40
+ __reinit(generateStyleSheetCallback, themes) {
41
+ const oldThemes = this.themes;
42
+ super.__reinit(generateStyleSheetCallback, themes);
43
+ if ((0, _utils.arrayEquals)(themes, oldThemes)) {
35
44
  return;
36
45
  }
37
- document.documentElement.removeAttribute("style");
38
- const runtimeCSSVariables = this.runtimeCSSVariables.get(this.currentTheme);
39
- if (!runtimeCSSVariables) {
40
- return;
46
+ this.cssRules = void 0;
47
+ if (typeof document !== "undefined") {
48
+ document.querySelector("#uniwind-dynamic-styles")?.remove();
41
49
  }
42
- Object.entries(runtimeCSSVariables).forEach(([varName, varValue]) => {
43
- this.applyCSSVariable(varName, varValue);
44
- });
45
50
  }
46
- applyCSSVariable(varName, varValue) {
51
+ getUniwindDynamicCSSRules() {
52
+ if (this.cssRules) {
53
+ return this.cssRules;
54
+ }
47
55
  if (typeof document === "undefined") {
48
- return;
56
+ return [];
49
57
  }
50
- document.documentElement.style.setProperty(varName, typeof varValue === "number" ? `${varValue}px` : varValue);
58
+ const styleElement = document.createElement("style");
59
+ styleElement.innerText = this.themes.reduce((acc, theme) => {
60
+ return `${acc}.${theme}{}`;
61
+ }, "");
62
+ styleElement.setAttribute("id", "uniwind-dynamic-styles");
63
+ document.head.appendChild(styleElement);
64
+ const cssRules = Array.from(styleElement.sheet?.cssRules ?? []).filter(rule => "selectorText" in rule && "style" in rule).map(rule => ({
65
+ style: rule.style,
66
+ theme: rule.selectorText.replace(".", "")
67
+ }));
68
+ this.cssRules = cssRules;
69
+ return cssRules;
51
70
  }
52
71
  }
53
72
  const Uniwind = exports.Uniwind = new UniwindConfigBuilder();
@@ -37,9 +37,7 @@ class UniwindConfigBuilder extends _config.UniwindConfigBuilder {
37
37
  get: getValue
38
38
  });
39
39
  });
40
- if (theme === this.currentTheme) {
41
- _listener.UniwindListener.notify([_types.StyleDependency.Variables]);
42
- }
40
+ _listener.UniwindListener.notify([_types.StyleDependency.Variables]);
43
41
  }
44
42
  updateInsets(insets) {
45
43
  _native.UniwindStore.runtime.insets.bottom = insets.bottom ?? 0;
@@ -54,7 +54,7 @@ class CSSListenerBuilder {
54
54
  listeners?.add(listener);
55
55
  disposables.push(() => listeners?.delete(listener));
56
56
  });
57
- const disposeThemeListener = _listener.UniwindListener.subscribe(listener, [_types.StyleDependency.Theme]);
57
+ const disposeThemeListener = _listener.UniwindListener.subscribe(listener, [_types.StyleDependency.Theme, _types.StyleDependency.Variables]);
58
58
  return () => {
59
59
  disposables.forEach(disposable => disposable());
60
60
  disposeThemeListener();
@@ -5,18 +5,13 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.useCSSVariable = void 0;
7
7
  var _react = require("react");
8
+ var _utils = require("../../common/utils");
8
9
  var _context = require("../../core/context");
9
10
  var _listener = require("../../core/listener");
10
11
  var _logger = require("../../core/logger");
11
12
  var _types = require("../../types");
12
13
  var _getVariableValue = require("./getVariableValue");
13
14
  const getValue = (name, uniwindContext) => Array.isArray(name) ? name.map(name2 => (0, _getVariableValue.getVariableValue)(name2, uniwindContext)) : (0, _getVariableValue.getVariableValue)(name, uniwindContext);
14
- const arrayEquals = (a, b) => {
15
- if (a.length !== b.length) {
16
- return false;
17
- }
18
- return a.every((value, index) => value === b[index]);
19
- };
20
15
  let warned = false;
21
16
  const logDevError = name => {
22
17
  warned = true;
@@ -28,7 +23,7 @@ const useCSSVariable = name => {
28
23
  const nameRef = (0, _react.useRef)(name);
29
24
  (0, _react.useLayoutEffect)(() => {
30
25
  if (Array.isArray(name) && Array.isArray(nameRef.current)) {
31
- if (arrayEquals(name, nameRef.current)) {
26
+ if ((0, _utils.arrayEquals)(name, nameRef.current)) {
32
27
  return;
33
28
  }
34
29
  setValue(getValue(name, uniwindContext));
@@ -78,8 +78,11 @@ const nativeResolver = (extraComponents) => ({
78
78
  }) => {
79
79
  const resolution = resolver(context, moduleName, platform);
80
80
  if (cachedInternalBasePath === null) {
81
- const componentsResolution = resolver(context, `${common.name}/components`, platform);
82
- cachedInternalBasePath = componentsResolution.type === "sourceFile" ? node_path.join(node_path.dirname(componentsResolution.filePath), "../..") : "";
81
+ try {
82
+ cachedInternalBasePath = node_path.dirname(require.resolve(`${common.name}/package.json`));
83
+ } catch {
84
+ cachedInternalBasePath = "";
85
+ }
83
86
  }
84
87
  const isInternal = cachedInternalBasePath !== "" && context.originModulePath.startsWith(cachedInternalBasePath);
85
88
  const isFromNodeModules = context.originModulePath.includes(`${node_path.sep}node_modules${node_path.sep}`);
@@ -115,8 +118,11 @@ const webResolver = (extraComponents) => ({
115
118
  }) => {
116
119
  const resolution = resolver(context, moduleName, platform);
117
120
  if (cachedInternalBasePath === null) {
118
- const componentsResolution = resolver(context, `${common.name}/components`, platform);
119
- cachedInternalBasePath = componentsResolution.type === "sourceFile" ? node_path.join(node_path.dirname(componentsResolution.filePath), "../../../..") : "";
121
+ try {
122
+ cachedInternalBasePath = node_path.dirname(require.resolve(`${common.name}/package.json`));
123
+ } catch {
124
+ cachedInternalBasePath = "";
125
+ }
120
126
  }
121
127
  if (cachedInternalBasePath !== "" && context.originModulePath.startsWith(cachedInternalBasePath) || resolution.type !== "sourceFile" || !resolution.filePath.includes(`${node_path.sep}react-native-web${node_path.sep}`)) {
122
128
  return resolution;
@@ -2,7 +2,7 @@ import { P as Platform } from '../shared/uniwind.JSWK3vHl.mjs';
2
2
  import FileStoreBase from 'metro-cache/private/stores/FileStore';
3
3
  import os from 'os';
4
4
  import path from 'path';
5
- import { join, dirname, sep, basename } from 'node:path';
5
+ import { dirname, sep, basename } from 'node:path';
6
6
  import { n as name, u as uniq } from '../shared/uniwind.PtWWxxnh.mjs';
7
7
 
8
8
  class FileStore extends FileStoreBase {
@@ -70,8 +70,11 @@ const nativeResolver = (extraComponents) => ({
70
70
  }) => {
71
71
  const resolution = resolver(context, moduleName, platform);
72
72
  if (cachedInternalBasePath === null) {
73
- const componentsResolution = resolver(context, `${name}/components`, platform);
74
- cachedInternalBasePath = componentsResolution.type === "sourceFile" ? join(dirname(componentsResolution.filePath), "../..") : "";
73
+ try {
74
+ cachedInternalBasePath = dirname(require.resolve(`${name}/package.json`));
75
+ } catch {
76
+ cachedInternalBasePath = "";
77
+ }
75
78
  }
76
79
  const isInternal = cachedInternalBasePath !== "" && context.originModulePath.startsWith(cachedInternalBasePath);
77
80
  const isFromNodeModules = context.originModulePath.includes(`${sep}node_modules${sep}`);
@@ -107,8 +110,11 @@ const webResolver = (extraComponents) => ({
107
110
  }) => {
108
111
  const resolution = resolver(context, moduleName, platform);
109
112
  if (cachedInternalBasePath === null) {
110
- const componentsResolution = resolver(context, `${name}/components`, platform);
111
- cachedInternalBasePath = componentsResolution.type === "sourceFile" ? join(dirname(componentsResolution.filePath), "../../../..") : "";
113
+ try {
114
+ cachedInternalBasePath = dirname(require.resolve(`${name}/package.json`));
115
+ } catch {
116
+ cachedInternalBasePath = "";
117
+ }
112
118
  }
113
119
  if (cachedInternalBasePath !== "" && context.originModulePath.startsWith(cachedInternalBasePath) || resolution.type !== "sourceFile" || !resolution.filePath.includes(`${sep}react-native-web${sep}`)) {
114
120
  return resolution;
@@ -158,8 +158,7 @@ const addMetaToStylesTemplate = (Processor, currentPlatform) => {
158
158
  minWidth,
159
159
  maxWidth,
160
160
  colorScheme,
161
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
162
- important,
161
+ important: _,
163
162
  importantProperties,
164
163
  active,
165
164
  focus,
@@ -961,7 +960,6 @@ class CSS {
961
960
  this.logUnsupported(`Unsupported value - ${JSON.stringify(declarationValue)}`);
962
961
  return void 0;
963
962
  }
964
- // eslint-disable-next-line @typescript-eslint/member-ordering
965
963
  static TRANSFORM_TYPES = /* @__PURE__ */ new Set([
966
964
  "translate",
967
965
  "translateX",
@@ -2124,7 +2122,7 @@ const transform = async (config, projectRoot, filePath, data, options) => {
2124
2122
  const isWeb = platform === consts.Platform.Web;
2125
2123
  data = Buffer.from(
2126
2124
  isWeb ? virtualCode : [
2127
- `import { Uniwind } from '${common.name}';`,
2125
+ `const { Uniwind } = require('${common.name}');`,
2128
2126
  `Uniwind.__reinit(rt => ${virtualCode}, ${injectedThemesCode});`
2129
2127
  ].join(""),
2130
2128
  "utf-8"
@@ -151,8 +151,7 @@ const addMetaToStylesTemplate = (Processor, currentPlatform) => {
151
151
  minWidth,
152
152
  maxWidth,
153
153
  colorScheme,
154
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
155
- important,
154
+ important: _,
156
155
  importantProperties,
157
156
  active,
158
157
  focus,
@@ -954,7 +953,6 @@ class CSS {
954
953
  this.logUnsupported(`Unsupported value - ${JSON.stringify(declarationValue)}`);
955
954
  return void 0;
956
955
  }
957
- // eslint-disable-next-line @typescript-eslint/member-ordering
958
956
  static TRANSFORM_TYPES = /* @__PURE__ */ new Set([
959
957
  "translate",
960
958
  "translateX",
@@ -2117,7 +2115,7 @@ const transform = async (config, projectRoot, filePath, data, options) => {
2117
2115
  const isWeb = platform === Platform.Web;
2118
2116
  data = Buffer.from(
2119
2117
  isWeb ? virtualCode : [
2120
- `import { Uniwind } from '${name}';`,
2118
+ `const { Uniwind } = require('${name}');`,
2121
2119
  `Uniwind.__reinit(rt => ${virtualCode}, ${injectedThemesCode});`
2122
2120
  ].join(""),
2123
2121
  "utf-8"
@@ -1 +1,2 @@
1
1
  export declare const isDefined: <T>(value: T) => value is NonNullable<T>;
2
+ export declare const arrayEquals: <T>(a: Array<T>, b: Array<T>) => boolean;
@@ -1 +1,7 @@
1
1
  export const isDefined = (value) => value !== void 0 && value !== null;
2
+ export const arrayEquals = (a, b) => {
3
+ if (a.length !== b.length) {
4
+ return false;
5
+ }
6
+ return a.every((value, index) => value === b[index]);
7
+ };
@@ -15,7 +15,7 @@ export declare class UniwindConfigBuilder {
15
15
  as: T;
16
16
  } & ApplyUniwind<Omit<ComponentPropsWithRef<T>, 'as'>>): import("react").FunctionComponentElement<any>;
17
17
  setTheme(theme: ThemeName | typeof SYSTEM_THEME): void;
18
- updateCSSVariables(theme: ThemeName, variables: CSSVariables): void;
18
+ updateCSSVariables(theme: ThemeName, cssVariables: CSSVariables): void;
19
19
  updateInsets(insets: Insets): void;
20
20
  protected __reinit(_: GenerateStyleSheetsCallback, themes: Array<string>): void;
21
21
  protected onThemeChange(): void;
@@ -76,12 +76,11 @@ export class UniwindConfigBuilder {
76
76
  }
77
77
  }
78
78
  }
79
- updateCSSVariables(theme, variables) {
80
- theme;
81
- variables;
79
+ // oxlint-disable-next-line typescript/no-unused-vars
80
+ updateCSSVariables(theme, cssVariables) {
82
81
  }
82
+ // oxlint-disable-next-line typescript/no-unused-vars
83
83
  updateInsets(insets) {
84
- insets;
85
84
  }
86
85
  __reinit(_, themes) {
87
86
  this._themes = themes;
@@ -1,11 +1,11 @@
1
- import { CSSVariables, ThemeName } from '../types';
1
+ import { CSSVariables, GenerateStyleSheetsCallback, ThemeName } from '../types';
2
2
  import { UniwindConfigBuilder as UniwindConfigBuilderBase } from './config.common';
3
3
  declare class UniwindConfigBuilder extends UniwindConfigBuilderBase {
4
- private runtimeCSSVariables;
4
+ private cssRules?;
5
5
  constructor();
6
6
  updateCSSVariables(theme: ThemeName, variables: CSSVariables): void;
7
- protected onThemeChange(): void;
8
- private applyCSSVariable;
7
+ protected __reinit(generateStyleSheetCallback: GenerateStyleSheetsCallback, themes: Array<string>): void;
8
+ private getUniwindDynamicCSSRules;
9
9
  }
10
10
  export declare const Uniwind: UniwindConfigBuilder;
11
11
  export {};
@@ -1,50 +1,69 @@
1
+ import { arrayEquals } from "../../common/utils.js";
1
2
  import { StyleDependency } from "../../types.js";
2
3
  import { UniwindListener } from "../listener.js";
3
4
  import { Logger } from "../logger.js";
5
+ import { getWebVariable } from "../web/index.js";
4
6
  import { UniwindConfigBuilder as UniwindConfigBuilderBase } from "./config.common.js";
5
7
  class UniwindConfigBuilder extends UniwindConfigBuilderBase {
6
- runtimeCSSVariables = /* @__PURE__ */ new Map();
8
+ cssRules;
7
9
  constructor() {
8
10
  super();
9
11
  }
10
12
  updateCSSVariables(theme, variables) {
13
+ if (typeof document === "undefined") {
14
+ return;
15
+ }
16
+ const uniwindRules = this.getUniwindDynamicCSSRules();
11
17
  Object.entries(variables).forEach(([varName, varValue]) => {
12
18
  if (!varName.startsWith("--") && __DEV__) {
13
19
  Logger.error(`CSS variable name must start with "--", instead got: ${varName}`);
14
- return;
15
- }
16
- const runtimeCSSVariables = this.runtimeCSSVariables.get(theme) ?? {};
17
- runtimeCSSVariables[varName] = varValue;
18
- this.runtimeCSSVariables.set(theme, runtimeCSSVariables);
19
- if (theme === this.currentTheme) {
20
- this.applyCSSVariable(varName, varValue);
21
20
  }
21
+ const existingRules = Object.fromEntries(
22
+ uniwindRules.map((rule) => [rule.theme, getWebVariable(varName, { scopedTheme: rule.theme })])
23
+ );
24
+ uniwindRules.forEach((rule) => {
25
+ if (rule.theme === theme) {
26
+ rule.style.setProperty(
27
+ varName,
28
+ typeof varValue === "number" ? `${varValue}px` : varValue
29
+ );
30
+ return;
31
+ }
32
+ rule.style.setProperty(varName, existingRules[rule.theme] ?? null);
33
+ });
22
34
  });
23
- if (theme === this.currentTheme) {
24
- UniwindListener.notify([StyleDependency.Variables]);
25
- }
35
+ UniwindListener.notify([StyleDependency.Variables]);
26
36
  }
27
- onThemeChange() {
28
- if (typeof document === "undefined") {
37
+ __reinit(generateStyleSheetCallback, themes) {
38
+ const oldThemes = this.themes;
39
+ super.__reinit(generateStyleSheetCallback, themes);
40
+ if (arrayEquals(themes, oldThemes)) {
29
41
  return;
30
42
  }
31
- document.documentElement.removeAttribute("style");
32
- const runtimeCSSVariables = this.runtimeCSSVariables.get(this.currentTheme);
33
- if (!runtimeCSSVariables) {
34
- return;
43
+ this.cssRules = void 0;
44
+ if (typeof document !== "undefined") {
45
+ document.querySelector("#uniwind-dynamic-styles")?.remove();
35
46
  }
36
- Object.entries(runtimeCSSVariables).forEach(([varName, varValue]) => {
37
- this.applyCSSVariable(varName, varValue);
38
- });
39
47
  }
40
- applyCSSVariable(varName, varValue) {
48
+ getUniwindDynamicCSSRules() {
49
+ if (this.cssRules) {
50
+ return this.cssRules;
51
+ }
41
52
  if (typeof document === "undefined") {
42
- return;
53
+ return [];
43
54
  }
44
- document.documentElement.style.setProperty(
45
- varName,
46
- typeof varValue === "number" ? `${varValue}px` : varValue
55
+ const styleElement = document.createElement("style");
56
+ styleElement.innerText = this.themes.reduce(
57
+ (acc, theme) => {
58
+ return `${acc}.${theme}{}`;
59
+ },
60
+ ""
47
61
  );
62
+ styleElement.setAttribute("id", "uniwind-dynamic-styles");
63
+ document.head.appendChild(styleElement);
64
+ const cssRules = Array.from(styleElement.sheet?.cssRules ?? []).filter((rule) => "selectorText" in rule && "style" in rule).map((rule) => ({ style: rule.style, theme: rule.selectorText.replace(".", "") }));
65
+ this.cssRules = cssRules;
66
+ return cssRules;
48
67
  }
49
68
  }
50
69
  export const Uniwind = new UniwindConfigBuilder();
@@ -31,9 +31,7 @@ class UniwindConfigBuilder extends UniwindConfigBuilderBase {
31
31
  get: getValue
32
32
  });
33
33
  });
34
- if (theme === this.currentTheme) {
35
- UniwindListener.notify([StyleDependency.Variables]);
36
- }
34
+ UniwindListener.notify([StyleDependency.Variables]);
37
35
  }
38
36
  updateInsets(insets) {
39
37
  UniwindStore.runtime.insets.bottom = insets.bottom ?? 0;
@@ -49,7 +49,7 @@ class CSSListenerBuilder {
49
49
  listeners?.add(listener);
50
50
  disposables.push(() => listeners?.delete(listener));
51
51
  });
52
- const disposeThemeListener = UniwindListener.subscribe(listener, [StyleDependency.Theme]);
52
+ const disposeThemeListener = UniwindListener.subscribe(listener, [StyleDependency.Theme, StyleDependency.Variables]);
53
53
  return () => {
54
54
  disposables.forEach((disposable) => disposable());
55
55
  disposeThemeListener();
@@ -1,16 +1,11 @@
1
1
  import { useLayoutEffect, useRef, useState } from "react";
2
+ import { arrayEquals } from "../../common/utils.js";
2
3
  import { useUniwindContext } from "../../core/context.js";
3
4
  import { UniwindListener } from "../../core/listener.js";
4
5
  import { Logger } from "../../core/logger.js";
5
6
  import { StyleDependency } from "../../types.js";
6
7
  import { getVariableValue } from "./getVariableValue.js";
7
8
  const getValue = (name, uniwindContext) => Array.isArray(name) ? name.map((name2) => getVariableValue(name2, uniwindContext)) : getVariableValue(name, uniwindContext);
8
- const arrayEquals = (a, b) => {
9
- if (a.length !== b.length) {
10
- return false;
11
- }
12
- return a.every((value, index) => value === b[index]);
13
- };
14
9
  let warned = false;
15
10
  const logDevError = (name) => {
16
11
  warned = true;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@niibase/uniwind",
4
- "version": "1.6.2",
4
+ "version": "1.6.3",
5
5
  "description": "A fork of Uniwind with Reanimated 4 support",
6
6
  "homepage": "https://uniwind.dev",
7
7
  "author": "Unistack",
@@ -12,8 +12,8 @@
12
12
  "precommit": "bun lint",
13
13
  "build": "unbuild",
14
14
  "check:typescript": "tsc --noEmit",
15
- "lint": "eslint src",
16
- "lint:fix": "eslint src --fix",
15
+ "lint": "oxlint src",
16
+ "lint:fix": "oxlint src --fix",
17
17
  "format": "dprint fmt",
18
18
  "prepublishOnly": "bun run build",
19
19
  "circular:check": "dpdm --no-warning --no-tree -T --exit-code circular:1 'src/**/*.ts' 'src/**/*.tsx'",
@@ -1 +1,9 @@
1
1
  export const isDefined = <T>(value: T): value is NonNullable<T> => value !== undefined && value !== null
2
+
3
+ export const arrayEquals = <T>(a: Array<T>, b: Array<T>) => {
4
+ if (a.length !== b.length) {
5
+ return false
6
+ }
7
+
8
+ return a.every((value, index) => value === b[index])
9
+ }
@@ -7,8 +7,7 @@ import { UniwindListener } from '../listener'
7
7
  import { CSSVariables, GenerateStyleSheetsCallback, ThemeName } from '../types'
8
8
 
9
9
  const SYSTEM_THEME = 'system' as const
10
-
11
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
10
+ // Platform.constants is not defined in RNW
12
11
  const RN_VERSION = Platform.constants?.reactNativeVersion?.minor ?? 0
13
12
  const UNSPECIFIED_THEME = RN_VERSION >= 82 ? 'unspecified' : undefined
14
13
 
@@ -21,7 +20,6 @@ export class UniwindConfigBuilder {
21
20
  Appearance.addChangeListener(event => {
22
21
  const colorScheme = event.colorScheme === 'unspecified'
23
22
  ? ColorScheme.Light
24
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
25
23
  : event.colorScheme ?? ColorScheme.Light
26
24
  const prevTheme = this.#currentTheme
27
25
 
@@ -108,15 +106,14 @@ export class UniwindConfigBuilder {
108
106
  }
109
107
  }
110
108
 
111
- updateCSSVariables(theme: ThemeName, variables: CSSVariables) {
109
+ // oxlint-disable-next-line typescript/no-unused-vars
110
+ updateCSSVariables(theme: ThemeName, cssVariables: CSSVariables) {
112
111
  // noop
113
- theme
114
- variables
115
112
  }
116
113
 
114
+ // oxlint-disable-next-line typescript/no-unused-vars
117
115
  updateInsets(insets: Insets) {
118
116
  // noop
119
- insets
120
117
  }
121
118
 
122
119
  protected __reinit(_: GenerateStyleSheetsCallback, themes: Array<string>) {
@@ -44,9 +44,7 @@ class UniwindConfigBuilder extends UniwindConfigBuilderBase {
44
44
  })
45
45
  })
46
46
 
47
- if (theme === this.currentTheme) {
48
- UniwindListener.notify([StyleDependency.Variables])
49
- }
47
+ UniwindListener.notify([StyleDependency.Variables])
50
48
  }
51
49
 
52
50
  updateInsets(insets: Insets) {
@@ -1,66 +1,98 @@
1
+ import { arrayEquals } from '../../common/utils'
1
2
  import { StyleDependency } from '../../types'
2
3
  import { UniwindListener } from '../listener'
3
4
  import { Logger } from '../logger'
4
- import { CSSVariables, ThemeName } from '../types'
5
+ import { CSSVariables, GenerateStyleSheetsCallback, ThemeName } from '../types'
6
+ import { getWebVariable } from '../web'
5
7
  import { UniwindConfigBuilder as UniwindConfigBuilderBase } from './config.common'
6
8
 
9
+ type UniwindCSSRule = {
10
+ style: CSSStyleDeclaration
11
+ theme: ThemeName
12
+ }
13
+
7
14
  class UniwindConfigBuilder extends UniwindConfigBuilderBase {
8
- private runtimeCSSVariables = new Map<ThemeName, CSSVariables>()
15
+ private cssRules?: Array<UniwindCSSRule>
9
16
 
10
17
  constructor() {
11
18
  super()
12
19
  }
13
20
 
14
21
  updateCSSVariables(theme: ThemeName, variables: CSSVariables) {
22
+ if (typeof document === 'undefined') {
23
+ return
24
+ }
25
+
26
+ const uniwindRules = this.getUniwindDynamicCSSRules()
27
+
15
28
  Object.entries(variables).forEach(([varName, varValue]) => {
16
29
  if (!varName.startsWith('--') && __DEV__) {
17
30
  Logger.error(`CSS variable name must start with "--", instead got: ${varName}`)
18
-
19
- return
20
31
  }
21
32
 
22
- const runtimeCSSVariables = this.runtimeCSSVariables.get(theme) ?? {}
33
+ const existingRules: Record<ThemeName, string | undefined> = Object.fromEntries(
34
+ uniwindRules.map(rule => [rule.theme, getWebVariable(varName, { scopedTheme: rule.theme })]),
35
+ )
23
36
 
24
- runtimeCSSVariables[varName] = varValue
25
- this.runtimeCSSVariables.set(theme, runtimeCSSVariables)
37
+ uniwindRules.forEach(rule => {
38
+ if (rule.theme === theme) {
39
+ rule.style.setProperty(
40
+ varName,
41
+ typeof varValue === 'number' ? `${varValue}px` : varValue,
42
+ )
26
43
 
27
- if (theme === this.currentTheme) {
28
- this.applyCSSVariable(varName, varValue)
29
- }
44
+ return
45
+ }
46
+
47
+ rule.style.setProperty(varName, existingRules[rule.theme] ?? null)
48
+ })
30
49
  })
31
50
 
32
- if (theme === this.currentTheme) {
33
- UniwindListener.notify([StyleDependency.Variables])
34
- }
51
+ UniwindListener.notify([StyleDependency.Variables])
35
52
  }
36
53
 
37
- protected onThemeChange() {
38
- if (typeof document === 'undefined') {
54
+ protected __reinit(generateStyleSheetCallback: GenerateStyleSheetsCallback, themes: Array<string>) {
55
+ const oldThemes = this.themes
56
+ super.__reinit(generateStyleSheetCallback, themes)
57
+
58
+ if (arrayEquals(themes, oldThemes)) {
39
59
  return
40
60
  }
41
61
 
42
- document.documentElement.removeAttribute('style')
43
-
44
- const runtimeCSSVariables = this.runtimeCSSVariables.get(this.currentTheme)
62
+ this.cssRules = undefined
45
63
 
46
- if (!runtimeCSSVariables) {
47
- return
64
+ if (typeof document !== 'undefined') {
65
+ document.querySelector('#uniwind-dynamic-styles')?.remove()
48
66
  }
49
-
50
- Object.entries(runtimeCSSVariables).forEach(([varName, varValue]) => {
51
- this.applyCSSVariable(varName, varValue)
52
- })
53
67
  }
54
68
 
55
- private applyCSSVariable(varName: keyof CSSVariables, varValue: CSSVariables[keyof CSSVariables]) {
69
+ private getUniwindDynamicCSSRules() {
70
+ if (this.cssRules) {
71
+ return this.cssRules
72
+ }
73
+
56
74
  if (typeof document === 'undefined') {
57
- return
75
+ return []
58
76
  }
59
77
 
60
- document.documentElement.style.setProperty(
61
- varName,
62
- typeof varValue === 'number' ? `${varValue}px` : varValue,
78
+ const styleElement = document.createElement('style')
79
+
80
+ styleElement.innerText = this.themes.reduce(
81
+ (acc, theme) => {
82
+ return `${acc}.${theme}{}`
83
+ },
84
+ '',
63
85
  )
86
+ styleElement.setAttribute('id', 'uniwind-dynamic-styles')
87
+ document.head.appendChild(styleElement)
88
+
89
+ const cssRules = Array.from(styleElement.sheet?.cssRules ?? [])
90
+ .filter((rule): rule is CSSStyleRule => 'selectorText' in rule && 'style' in rule)
91
+ .map((rule): UniwindCSSRule => ({ style: rule.style, theme: rule.selectorText.replace('.', '') }))
92
+
93
+ this.cssRules = cssRules
94
+
95
+ return cssRules
64
96
  }
65
97
  }
66
98
 
@@ -1,5 +1,3 @@
1
- /* eslint-disable no-console */
2
-
3
1
  export class Logger {
4
2
  static log(message: string) {
5
3
  console.log(`Uniwind - ${message}`)
@@ -1,4 +1,3 @@
1
- /* eslint-disable max-depth */
2
1
  const transforms = [
3
2
  'translateX',
4
3
  'translateY',
@@ -1,4 +1,3 @@
1
- /* eslint-disable max-depth */
2
1
  import { Dimensions, Platform } from 'react-native'
3
2
  import { CSSAnimationKeyframes } from 'react-native-reanimated'
4
3
  import { Platform as UniwindPlatform, UNIWIND_PLATFORM_VARIABLES, UNIWIND_THEME_VARIABLES } from '../../common/consts'
@@ -54,7 +54,6 @@ class CSSListenerBuilder {
54
54
  const mediaQuery = this.classNameMediaQueryListeners.get(className)
55
55
 
56
56
  if (!mediaQuery) {
57
- // eslint-disable-next-line no-empty-function
58
57
  return () => {}
59
58
  }
60
59
 
@@ -64,7 +63,7 @@ class CSSListenerBuilder {
64
63
  disposables.push(() => listeners?.delete(listener))
65
64
  })
66
65
 
67
- const disposeThemeListener = UniwindListener.subscribe(listener, [StyleDependency.Theme])
66
+ const disposeThemeListener = UniwindListener.subscribe(listener, [StyleDependency.Theme, StyleDependency.Variables])
68
67
 
69
68
  return () => {
70
69
  disposables.forEach(disposable => disposable())
@@ -129,7 +128,7 @@ class CSSListenerBuilder {
129
128
  continue
130
129
  }
131
130
 
132
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/strict-boolean-expressions
131
+ // oxlint-disable-next-line @typescript-eslint/strict-boolean-expressions
133
132
  if (!rules) {
134
133
  continue
135
134
  }
@@ -120,7 +120,6 @@ const withManualUniwind = (Component: Component<AnyObject>, options: Record<Prop
120
120
 
121
121
  const existingStyle = props[propName]
122
122
 
123
- // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
124
123
  if (existingStyle) {
125
124
  acc.generatedProps[propName] = [styles, existingStyle]
126
125
 
@@ -1,4 +1,5 @@
1
1
  import { useLayoutEffect, useRef, useState } from 'react'
2
+ import { arrayEquals } from '../../common/utils'
2
3
  import { useUniwindContext } from '../../core/context'
3
4
  import { UniwindListener } from '../../core/listener'
4
5
  import { Logger } from '../../core/logger'
@@ -11,14 +12,6 @@ const getValue = (name: string | Array<string>, uniwindContext: UniwindContextTy
11
12
  ? name.map(name => getVariableValue(name, uniwindContext))
12
13
  : getVariableValue(name, uniwindContext)
13
14
 
14
- const arrayEquals = <T>(a: Array<T>, b: Array<T>) => {
15
- if (a.length !== b.length) {
16
- return false
17
- }
18
-
19
- return a.every((value, index) => value === b[index])
20
- }
21
-
22
15
  let warned = false
23
16
 
24
17
  const logDevError = (name: string) => {
@@ -41,8 +41,7 @@ export const addMetaToStylesTemplate = (Processor: ProcessorBuilder, currentPlat
41
41
  minWidth,
42
42
  maxWidth,
43
43
  colorScheme,
44
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
45
- important,
44
+ important: _,
46
45
  importantProperties,
47
46
  active,
48
47
  focus,
@@ -1,5 +1,3 @@
1
- /* eslint-disable no-console */
2
-
3
1
  const red = '\x1b[91m'
4
2
  const yellow = '\x1b[33m'
5
3
  const blue = '\x1b[36m'
@@ -6,7 +6,6 @@ import path from 'path'
6
6
 
7
7
  class FileStore<T> extends FileStoreBase<T> {
8
8
  async set(key: Buffer, value: any): Promise<void> {
9
- // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
10
9
  if (value?.output?.[0]?.data?.css?.skipCache) {
11
10
  return
12
11
  }
@@ -27,7 +26,7 @@ interface TraverseDependencies {
27
26
  export const patchMetroGraphToSupportUncachedModules = () => {
28
27
  const { Graph } = require('metro/private/DeltaBundler/Graph') as typeof import('metro/private/DeltaBundler/Graph')
29
28
 
30
- // eslint-disable-next-line @typescript-eslint/unbound-method
29
+ // oxlint-disable-next-line @typescript-eslint/unbound-method
31
30
  const original_traverseDependencies = Graph.prototype.traverseDependencies as unknown as TraverseDependencies
32
31
 
33
32
  if (original_traverseDependencies.__patched) {
@@ -91,7 +91,7 @@ export const transform = async (
91
91
  isWeb
92
92
  ? virtualCode
93
93
  : [
94
- `import { Uniwind } from '${name}';`,
94
+ `const { Uniwind } = require('${name}');`,
95
95
  `Uniwind.__reinit(rt => ${virtualCode}, ${injectedThemesCode});`,
96
96
  ].join(''),
97
97
  'utf-8',
@@ -590,7 +590,6 @@ export class CSS {
590
590
  return undefined
591
591
  }
592
592
 
593
- // eslint-disable-next-line @typescript-eslint/member-ordering
594
593
  private static readonly TRANSFORM_TYPES = new Set([
595
594
  'translate',
596
595
  'translateX',
@@ -239,7 +239,6 @@ export class Functions {
239
239
  .replace(/"/g, '')
240
240
  .replace(new RegExp(unit, 'g'), '')
241
241
 
242
- // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
243
242
  return new Function(`return ${numericValue} + '${unit}'`)()
244
243
  } catch {
245
244
  this.logger.error(`Invalid calc ${value}`)
@@ -1,5 +1,5 @@
1
1
  import { CustomResolutionContext, CustomResolver } from 'metro-resolver'
2
- import { basename, dirname, join, sep } from 'node:path'
2
+ import { basename, dirname, sep } from 'node:path'
3
3
  import { name } from '../../package.json'
4
4
 
5
5
  type ResolverConfig = {
@@ -47,12 +47,11 @@ export const nativeResolver = (extraComponents: Record<string, string>) =>
47
47
  const resolution = resolver(context, moduleName, platform)
48
48
 
49
49
  if (cachedInternalBasePath === null) {
50
- const componentsResolution = resolver(context, `${name}/components`, platform)
51
-
52
- cachedInternalBasePath = componentsResolution.type === 'sourceFile'
53
- // Go from src/components to root
54
- ? join(dirname(componentsResolution.filePath), '../..')
55
- : ''
50
+ try {
51
+ cachedInternalBasePath = dirname(require.resolve(`${name}/package.json`))
52
+ } catch {
53
+ cachedInternalBasePath = ''
54
+ }
56
55
  }
57
56
 
58
57
  const isInternal = cachedInternalBasePath !== '' && context.originModulePath.startsWith(cachedInternalBasePath)
@@ -106,13 +105,13 @@ export const webResolver = (extraComponents: Record<string, string>) =>
106
105
  const resolution = resolver(context, moduleName, platform)
107
106
 
108
107
  if (cachedInternalBasePath === null) {
109
- const componentsResolution = resolver(context, `${name}/components`, platform)
110
-
111
- cachedInternalBasePath = componentsResolution.type === 'sourceFile'
112
- // Go from dist/module/components/web to root
113
- ? join(dirname(componentsResolution.filePath), '../../../..')
114
- : ''
108
+ try {
109
+ cachedInternalBasePath = dirname(require.resolve(`${name}/package.json`))
110
+ } catch {
111
+ cachedInternalBasePath = ''
112
+ }
115
113
  }
114
+
116
115
  if (
117
116
  (cachedInternalBasePath !== '' && context.originModulePath.startsWith(cachedInternalBasePath))
118
117
  || resolution.type !== 'sourceFile'
@@ -52,7 +52,6 @@ export const uniq = <T>(arr: Array<T>) => Array.from(new Set(arr))
52
52
 
53
53
  export const isValidJSValue = (jsValueString: string) => {
54
54
  try {
55
- // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
56
55
  new Function(`const test = ${jsValueString}`)
57
56
 
58
57
  return true
@@ -103,7 +103,6 @@ export const serializeJSObject = (obj: Record<string, any>, serializer: (key: st
103
103
  serializedValues =>
104
104
  serializedValues.filter(serializedValue => {
105
105
  try {
106
- // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
107
106
  new Function(`function validateJS() { const obj = ({ ${serializedValue} }) }`)
108
107
 
109
108
  return true
package/src/types.ts CHANGED
@@ -20,5 +20,4 @@ export const enum ColorScheme {
20
20
  Dark = 'dark',
21
21
  }
22
22
 
23
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
24
23
  export interface UniwindConfig {}