@niibase/uniwind 1.4.0 → 1.5.0
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/dist/common/common/consts.js +18 -0
- package/dist/common/components/native/Pressable.js +13 -2
- package/dist/common/components/native/TouchableHighlight.js +11 -1
- package/dist/common/components/native/TouchableOpacity.js +11 -1
- package/dist/common/core/native/runtime.js +11 -1
- package/dist/common/core/native/store.js +19 -2
- package/dist/common/css/variants.js +1 -1
- package/dist/common/css-visitor/function-visitor.js +9 -0
- package/dist/common/css-visitor/rule-visitor.js +49 -5
- package/dist/metro/index.cjs +2 -2
- package/dist/metro/index.d.ts +1 -0
- package/dist/metro/index.mjs +1 -1
- package/dist/metro/metro-transformer.cjs +47 -11
- package/dist/metro/metro-transformer.mjs +45 -9
- package/dist/module/common/consts.d.ts +11 -0
- package/dist/module/common/consts.js +12 -0
- package/dist/module/components/native/Pressable.d.ts +5 -0
- package/dist/module/components/native/Pressable.js +12 -2
- package/dist/module/components/native/TouchableHighlight.js +11 -1
- package/dist/module/components/native/TouchableOpacity.js +11 -1
- package/dist/module/core/native/parsers/gradient.d.ts +1 -1
- package/dist/module/core/native/runtime.js +5 -2
- package/dist/module/core/native/store.d.ts +1 -0
- package/dist/module/core/native/store.js +19 -2
- package/dist/module/core/types.d.ts +1 -0
- package/dist/module/css/variants.js +1 -1
- package/dist/module/css-visitor/function-visitor.d.ts +1 -0
- package/dist/module/css-visitor/function-visitor.js +3 -0
- package/dist/module/css-visitor/rule-visitor.d.ts +3 -1
- package/dist/module/css-visitor/rule-visitor.js +54 -5
- package/dist/shared/uniwind.B5q8hBGv.cjs +18 -0
- package/dist/shared/{uniwind.D-ahjOrG.mjs → uniwind.BWb5KNML.mjs} +58 -6
- package/dist/shared/{uniwind.CyACT0sD.cjs → uniwind.DTMo4epG.cjs} +58 -6
- package/dist/shared/uniwind.JSWK3vHl.mjs +14 -0
- package/dist/vite/index.cjs +1 -1
- package/dist/vite/index.mjs +1 -1
- package/package.json +19 -13
- package/readme.md +4 -12
- package/src/common/consts.ts +12 -0
- package/src/components/native/Pressable.tsx +17 -1
- package/src/components/native/TouchableHighlight.tsx +10 -0
- package/src/components/native/TouchableOpacity.tsx +10 -0
- package/src/core/config/config.common.ts +1 -2
- package/src/core/native/parsers/gradient.ts +1 -1
- package/src/core/native/runtime.ts +5 -1
- package/src/core/native/store.ts +24 -2
- package/src/core/types.ts +1 -0
- package/src/css/variants.ts +1 -1
- package/src/css-visitor/function-visitor.ts +4 -0
- package/src/css-visitor/rule-visitor.ts +68 -9
- package/src/metro/addMetaToStylesTemplate.ts +9 -3
- package/src/metro/compileVirtual.ts +2 -1
- package/src/metro/index.d.ts +1 -0
- package/src/metro/metro-transformer.ts +19 -2
- package/src/metro/processor/functions.ts +4 -0
- package/src/metro/processor/mq.ts +12 -2
- package/src/metro/processor/processor.ts +3 -2
- package/src/metro/processor/rn.ts +10 -0
- package/src/metro/types.ts +2 -7
- package/src/metro/withUniwindConfig.ts +2 -1
- package/uniwind.css +5 -2
- package/dist/shared/uniwind.BZIuaszw.cjs +0 -11
- package/dist/shared/uniwind.CyoRUwOj.mjs +0 -9
|
@@ -5,9 +5,11 @@ import { copyComponentProperties } from "../utils.js";
|
|
|
5
5
|
import { useStyle } from "./useStyle.js";
|
|
6
6
|
export const TouchableHighlight = copyComponentProperties(RNTouchableHighlight, (props) => {
|
|
7
7
|
const [isPressed, setIsPressed] = useState(false);
|
|
8
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
8
9
|
const state = {
|
|
9
10
|
isDisabled: Boolean(props.disabled),
|
|
10
|
-
isPressed
|
|
11
|
+
isPressed,
|
|
12
|
+
isFocused
|
|
11
13
|
};
|
|
12
14
|
const { Component, style } = useStyle(RNTouchableHighlight, props.className, props, state);
|
|
13
15
|
const underlayColor = useStyle(props.underlayColorClassName, props, state).accentColor;
|
|
@@ -24,6 +26,14 @@ export const TouchableHighlight = copyComponentProperties(RNTouchableHighlight,
|
|
|
24
26
|
onPressOut: (event) => {
|
|
25
27
|
setIsPressed(false);
|
|
26
28
|
props.onPressOut?.(event);
|
|
29
|
+
},
|
|
30
|
+
onFocus: (event) => {
|
|
31
|
+
setIsFocused(true);
|
|
32
|
+
props.onFocus?.(event);
|
|
33
|
+
},
|
|
34
|
+
onBlur: (event) => {
|
|
35
|
+
setIsFocused(false);
|
|
36
|
+
props.onBlur?.(event);
|
|
27
37
|
}
|
|
28
38
|
}
|
|
29
39
|
);
|
|
@@ -5,9 +5,11 @@ import { copyComponentProperties } from "../utils.js";
|
|
|
5
5
|
import { useStyle } from "./useStyle.js";
|
|
6
6
|
export const TouchableOpacity = copyComponentProperties(RNTouchableOpacity, (props) => {
|
|
7
7
|
const [isPressed, setIsPressed] = useState(false);
|
|
8
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
8
9
|
const state = {
|
|
9
10
|
isDisabled: Boolean(props.disabled),
|
|
10
|
-
isPressed
|
|
11
|
+
isPressed,
|
|
12
|
+
isFocused
|
|
11
13
|
};
|
|
12
14
|
const { Component, style } = useStyle(RNTouchableOpacity, props.className, props, state);
|
|
13
15
|
return /* @__PURE__ */ jsx(
|
|
@@ -22,6 +24,14 @@ export const TouchableOpacity = copyComponentProperties(RNTouchableOpacity, (pro
|
|
|
22
24
|
onPressOut: (event) => {
|
|
23
25
|
setIsPressed(false);
|
|
24
26
|
props.onPressOut?.(event);
|
|
27
|
+
},
|
|
28
|
+
onFocus: (event) => {
|
|
29
|
+
setIsFocused(true);
|
|
30
|
+
props.onFocus?.(event);
|
|
31
|
+
},
|
|
32
|
+
onBlur: (event) => {
|
|
33
|
+
setIsFocused(false);
|
|
34
|
+
props.onBlur?.(event);
|
|
25
35
|
}
|
|
26
36
|
}
|
|
27
37
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Appearance, Dimensions, I18nManager, PixelRatio, StyleSheet } from "react-native";
|
|
1
|
+
import { Appearance, Dimensions, I18nManager, PixelRatio, Platform, StyleSheet } from "react-native";
|
|
2
2
|
import { cubicBezier, linear, steps } from "react-native-reanimated";
|
|
3
3
|
import { initialWindowMetrics } from "react-native-safe-area-context";
|
|
4
4
|
import { ColorScheme, Orientation } from "../../types.js";
|
|
@@ -23,6 +23,9 @@ export const UniwindRuntime = {
|
|
|
23
23
|
steps,
|
|
24
24
|
linear,
|
|
25
25
|
lightDark: () => "",
|
|
26
|
-
parseColor
|
|
26
|
+
parseColor,
|
|
27
|
+
platformSelect: (android, ios, other) => {
|
|
28
|
+
return Platform.select(Boolean(other) ? { android, ios, default: other } : { android, default: ios });
|
|
29
|
+
}
|
|
27
30
|
};
|
|
28
31
|
UniwindRuntime.lightDark = lightDark.bind(UniwindRuntime);
|
|
@@ -15,6 +15,7 @@ declare class UniwindStoreBuilder {
|
|
|
15
15
|
reinit: (generateStyleSheetCallback: GenerateStyleSheetsCallback, themes: Array<string>) => void;
|
|
16
16
|
private resolveStyles;
|
|
17
17
|
private validateDataAttributes;
|
|
18
|
+
private getCurrentPlatform;
|
|
18
19
|
}
|
|
19
20
|
export declare const UniwindStore: UniwindStoreBuilder;
|
|
20
21
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Dimensions, Platform } from "react-native";
|
|
2
|
+
import { Platform as UniwindPlatform, UNIWIND_PLATFORM_VARIABLES, UNIWIND_THEME_VARIABLES } from "../../common/consts.js";
|
|
2
3
|
import { Orientation, StyleDependency } from "../../types.js";
|
|
3
4
|
import { UniwindListener } from "../listener.js";
|
|
4
5
|
import { cloneWithAccessors } from "./native-utils.js";
|
|
@@ -40,7 +41,13 @@ class UniwindStoreBuilder {
|
|
|
40
41
|
}
|
|
41
42
|
reinit = (generateStyleSheetCallback, themes) => {
|
|
42
43
|
const { scopedVars, stylesheet, vars, keyframes } = generateStyleSheetCallback(this.runtime);
|
|
43
|
-
const
|
|
44
|
+
const platform = this.getCurrentPlatform();
|
|
45
|
+
const commonPlatform = platform.includes("tv") ? UniwindPlatform.TV : UniwindPlatform.Native;
|
|
46
|
+
const commonPlatformVars = scopedVars[`${UNIWIND_PLATFORM_VARIABLES}${commonPlatform}`];
|
|
47
|
+
const platformVars = scopedVars[`${UNIWIND_PLATFORM_VARIABLES}${platform}`];
|
|
48
|
+
if (commonPlatformVars) {
|
|
49
|
+
Object.defineProperties(vars, Object.getOwnPropertyDescriptors(commonPlatformVars));
|
|
50
|
+
}
|
|
44
51
|
if (platformVars) {
|
|
45
52
|
Object.defineProperties(vars, Object.getOwnPropertyDescriptors(platformVars));
|
|
46
53
|
}
|
|
@@ -48,7 +55,7 @@ class UniwindStoreBuilder {
|
|
|
48
55
|
this.stylesheet = stylesheet;
|
|
49
56
|
this.vars = Object.fromEntries(themes.map((theme) => {
|
|
50
57
|
const clonedVars = cloneWithAccessors(vars);
|
|
51
|
-
const themeVars = scopedVars[
|
|
58
|
+
const themeVars = scopedVars[`${UNIWIND_THEME_VARIABLES}${theme}`];
|
|
52
59
|
if (themeVars) {
|
|
53
60
|
Object.defineProperties(clonedVars, Object.getOwnPropertyDescriptors(themeVars));
|
|
54
61
|
}
|
|
@@ -209,6 +216,16 @@ class UniwindStoreBuilder {
|
|
|
209
216
|
}
|
|
210
217
|
return true;
|
|
211
218
|
}
|
|
219
|
+
getCurrentPlatform() {
|
|
220
|
+
const platform = Platform.OS;
|
|
221
|
+
if (platform === "android") {
|
|
222
|
+
return Platform.isTV ? UniwindPlatform.AndroidTV : UniwindPlatform.Android;
|
|
223
|
+
}
|
|
224
|
+
if (platform === "ios") {
|
|
225
|
+
return Platform.isTV ? UniwindPlatform.AppleTV : UniwindPlatform.iOS;
|
|
226
|
+
}
|
|
227
|
+
return platform;
|
|
228
|
+
}
|
|
212
229
|
}
|
|
213
230
|
export const UniwindStore = new UniwindStoreBuilder();
|
|
214
231
|
Dimensions.addEventListener("change", ({ window }) => {
|
|
@@ -57,6 +57,7 @@ export type UniwindRuntime = {
|
|
|
57
57
|
linear: (...points: ControlPoint[]) => LinearEasing;
|
|
58
58
|
lightDark: (light: string, dark: string) => string;
|
|
59
59
|
parseColor: (type: string, color: string) => string;
|
|
60
|
+
platformSelect: (android: string, ios: string, other?: string) => string;
|
|
60
61
|
};
|
|
61
62
|
export type RNStyle = ViewStyle & TextStyle & ImageStyle & {
|
|
62
63
|
accentColor?: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Function as LightningCSSFunction, TokenOrValue } from 'lightningcss';
|
|
2
2
|
export declare class FunctionVisitor {
|
|
3
3
|
[name: string]: (fn: LightningCSSFunction) => TokenOrValue;
|
|
4
|
+
platformSelect(fn: LightningCSSFunction): TokenOrValue;
|
|
4
5
|
pixelRatio(fn: LightningCSSFunction): TokenOrValue;
|
|
5
6
|
fontScale(fn: LightningCSSFunction): TokenOrValue;
|
|
6
7
|
hairlineWidth(): TokenOrValue;
|
|
@@ -3,6 +3,9 @@ const ONE_PX = {
|
|
|
3
3
|
value: { type: "dimension", unit: "px", value: 1 }
|
|
4
4
|
};
|
|
5
5
|
export class FunctionVisitor {
|
|
6
|
+
platformSelect(fn) {
|
|
7
|
+
return fn.arguments.at(0) ?? { type: "token", value: { type: "ident", value: "initial" } };
|
|
8
|
+
}
|
|
6
9
|
pixelRatio(fn) {
|
|
7
10
|
return {
|
|
8
11
|
type: "function",
|
|
@@ -16,9 +16,11 @@ export declare class RuleVisitor implements LightningRuleVisitors {
|
|
|
16
16
|
}>) => void;
|
|
17
17
|
style: (styleRule: Extract<LightningRuleVisitor, {
|
|
18
18
|
type: "style";
|
|
19
|
-
}>) => void | ReturnedRule;
|
|
19
|
+
}>) => void | ReturnedRule | ReturnedRule[];
|
|
20
20
|
cleanup(): void;
|
|
21
|
+
private processThemeRoot;
|
|
21
22
|
private processThemeStyle;
|
|
22
23
|
private processClassStyle;
|
|
24
|
+
private removeNulls;
|
|
23
25
|
}
|
|
24
26
|
export {};
|
|
@@ -10,9 +10,8 @@ export class RuleVisitor {
|
|
|
10
10
|
};
|
|
11
11
|
style = (styleRule) => {
|
|
12
12
|
const firstSelector = styleRule.value.selectors.at(0)?.at(0);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return this.processThemeStyle(styleRule, secondSelector);
|
|
13
|
+
if (this.currentLayerName === "theme" && firstSelector?.type === "pseudo-class" && firstSelector.kind === "root") {
|
|
14
|
+
return this.removeNulls(this.processThemeRoot(styleRule));
|
|
16
15
|
}
|
|
17
16
|
if (firstSelector?.type === "class") {
|
|
18
17
|
return this.processClassStyle(styleRule, firstSelector);
|
|
@@ -23,14 +22,47 @@ export class RuleVisitor {
|
|
|
23
22
|
this.processedClassNames.clear();
|
|
24
23
|
this.processedVariables.clear();
|
|
25
24
|
}
|
|
25
|
+
processThemeRoot(styleRule) {
|
|
26
|
+
const themeScopedRules = styleRule.value.rules?.filter((rule) => {
|
|
27
|
+
if (rule.type !== "style") {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const firstSelector = rule.value.selectors.at(0)?.at(0);
|
|
31
|
+
const secondSelector = rule.value.selectors.at(0)?.at(1);
|
|
32
|
+
return firstSelector?.type === "nesting" && secondSelector?.type === "pseudo-class" && secondSelector.kind === "where";
|
|
33
|
+
}) ?? [];
|
|
34
|
+
const nonThemeRules = styleRule.value.rules?.filter((rule) => !themeScopedRules.includes(rule));
|
|
35
|
+
const processedThemeScopedRules = themeScopedRules.map((rule) => {
|
|
36
|
+
if (rule.type !== "style") {
|
|
37
|
+
return rule;
|
|
38
|
+
}
|
|
39
|
+
const secondSelector = rule.value.selectors.at(0)?.at(1);
|
|
40
|
+
if (secondSelector?.type === "pseudo-class" && secondSelector.kind === "where") {
|
|
41
|
+
return this.processThemeStyle(rule, secondSelector);
|
|
42
|
+
}
|
|
43
|
+
return rule;
|
|
44
|
+
});
|
|
45
|
+
return [
|
|
46
|
+
{
|
|
47
|
+
type: "style",
|
|
48
|
+
value: {
|
|
49
|
+
loc: styleRule.value.loc,
|
|
50
|
+
selectors: styleRule.value.selectors,
|
|
51
|
+
rules: nonThemeRules,
|
|
52
|
+
declarations: styleRule.value.declarations
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
...processedThemeScopedRules
|
|
56
|
+
];
|
|
57
|
+
}
|
|
26
58
|
processThemeStyle(styleRule, secondSelector) {
|
|
27
59
|
const whereSelector = secondSelector.selectors.at(0)?.at(0);
|
|
28
60
|
if (whereSelector?.type !== "class") {
|
|
29
|
-
return;
|
|
61
|
+
return styleRule;
|
|
30
62
|
}
|
|
31
63
|
const selectedVariant = this.themes.find((theme) => whereSelector.name === theme);
|
|
32
64
|
if (selectedVariant === void 0 || this.processedVariables.has(selectedVariant)) {
|
|
33
|
-
return;
|
|
65
|
+
return styleRule;
|
|
34
66
|
}
|
|
35
67
|
this.processedVariables.add(selectedVariant);
|
|
36
68
|
return {
|
|
@@ -59,4 +91,21 @@ export class RuleVisitor {
|
|
|
59
91
|
}
|
|
60
92
|
};
|
|
61
93
|
}
|
|
94
|
+
// Fixes lightningcss serialization bug
|
|
95
|
+
removeNulls(value) {
|
|
96
|
+
if (Array.isArray(value)) {
|
|
97
|
+
return value.map((v) => this.removeNulls(v));
|
|
98
|
+
}
|
|
99
|
+
if (typeof value === "object" && value !== null) {
|
|
100
|
+
return Object.fromEntries(
|
|
101
|
+
Object.entries(value).filter(([_, value2]) => {
|
|
102
|
+
if (value2 === null) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}).map(([key, value2]) => [key, this.removeNulls(value2)])
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
62
111
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Platform = /* @__PURE__ */ ((Platform2) => {
|
|
4
|
+
Platform2["Android"] = "android";
|
|
5
|
+
Platform2["iOS"] = "ios";
|
|
6
|
+
Platform2["Web"] = "web";
|
|
7
|
+
Platform2["Native"] = "native";
|
|
8
|
+
Platform2["TV"] = "tv";
|
|
9
|
+
Platform2["AndroidTV"] = "android-tv";
|
|
10
|
+
Platform2["AppleTV"] = "apple-tv";
|
|
11
|
+
return Platform2;
|
|
12
|
+
})(Platform || {});
|
|
13
|
+
const UNIWIND_PLATFORM_VARIABLES = "__uniwind-platform-";
|
|
14
|
+
const UNIWIND_THEME_VARIABLES = "__uniwind-theme-";
|
|
15
|
+
|
|
16
|
+
exports.Platform = Platform;
|
|
17
|
+
exports.UNIWIND_PLATFORM_VARIABLES = UNIWIND_PLATFORM_VARIABLES;
|
|
18
|
+
exports.UNIWIND_THEME_VARIABLES = UNIWIND_THEME_VARIABLES;
|
|
@@ -44,6 +44,9 @@ const ONE_PX = {
|
|
|
44
44
|
value: { type: "dimension", unit: "px", value: 1 }
|
|
45
45
|
};
|
|
46
46
|
class FunctionVisitor {
|
|
47
|
+
platformSelect(fn) {
|
|
48
|
+
return fn.arguments.at(0) ?? { type: "token", value: { type: "ident", value: "initial" } };
|
|
49
|
+
}
|
|
47
50
|
pixelRatio(fn) {
|
|
48
51
|
return {
|
|
49
52
|
type: "function",
|
|
@@ -90,9 +93,8 @@ class RuleVisitor {
|
|
|
90
93
|
};
|
|
91
94
|
style = (styleRule) => {
|
|
92
95
|
const firstSelector = styleRule.value.selectors.at(0)?.at(0);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return this.processThemeStyle(styleRule, secondSelector);
|
|
96
|
+
if (this.currentLayerName === "theme" && firstSelector?.type === "pseudo-class" && firstSelector.kind === "root") {
|
|
97
|
+
return this.removeNulls(this.processThemeRoot(styleRule));
|
|
96
98
|
}
|
|
97
99
|
if (firstSelector?.type === "class") {
|
|
98
100
|
return this.processClassStyle(styleRule, firstSelector);
|
|
@@ -103,14 +105,47 @@ class RuleVisitor {
|
|
|
103
105
|
this.processedClassNames.clear();
|
|
104
106
|
this.processedVariables.clear();
|
|
105
107
|
}
|
|
108
|
+
processThemeRoot(styleRule) {
|
|
109
|
+
const themeScopedRules = styleRule.value.rules?.filter((rule) => {
|
|
110
|
+
if (rule.type !== "style") {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const firstSelector = rule.value.selectors.at(0)?.at(0);
|
|
114
|
+
const secondSelector = rule.value.selectors.at(0)?.at(1);
|
|
115
|
+
return firstSelector?.type === "nesting" && secondSelector?.type === "pseudo-class" && secondSelector.kind === "where";
|
|
116
|
+
}) ?? [];
|
|
117
|
+
const nonThemeRules = styleRule.value.rules?.filter((rule) => !themeScopedRules.includes(rule));
|
|
118
|
+
const processedThemeScopedRules = themeScopedRules.map((rule) => {
|
|
119
|
+
if (rule.type !== "style") {
|
|
120
|
+
return rule;
|
|
121
|
+
}
|
|
122
|
+
const secondSelector = rule.value.selectors.at(0)?.at(1);
|
|
123
|
+
if (secondSelector?.type === "pseudo-class" && secondSelector.kind === "where") {
|
|
124
|
+
return this.processThemeStyle(rule, secondSelector);
|
|
125
|
+
}
|
|
126
|
+
return rule;
|
|
127
|
+
});
|
|
128
|
+
return [
|
|
129
|
+
{
|
|
130
|
+
type: "style",
|
|
131
|
+
value: {
|
|
132
|
+
loc: styleRule.value.loc,
|
|
133
|
+
selectors: styleRule.value.selectors,
|
|
134
|
+
rules: nonThemeRules,
|
|
135
|
+
declarations: styleRule.value.declarations
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
...processedThemeScopedRules
|
|
139
|
+
];
|
|
140
|
+
}
|
|
106
141
|
processThemeStyle(styleRule, secondSelector) {
|
|
107
142
|
const whereSelector = secondSelector.selectors.at(0)?.at(0);
|
|
108
143
|
if (whereSelector?.type !== "class") {
|
|
109
|
-
return;
|
|
144
|
+
return styleRule;
|
|
110
145
|
}
|
|
111
146
|
const selectedVariant = this.themes.find((theme) => whereSelector.name === theme);
|
|
112
147
|
if (selectedVariant === void 0 || this.processedVariables.has(selectedVariant)) {
|
|
113
|
-
return;
|
|
148
|
+
return styleRule;
|
|
114
149
|
}
|
|
115
150
|
this.processedVariables.add(selectedVariant);
|
|
116
151
|
return {
|
|
@@ -139,6 +174,23 @@ class RuleVisitor {
|
|
|
139
174
|
}
|
|
140
175
|
};
|
|
141
176
|
}
|
|
177
|
+
// Fixes lightningcss serialization bug
|
|
178
|
+
removeNulls(value) {
|
|
179
|
+
if (Array.isArray(value)) {
|
|
180
|
+
return value.map((v) => this.removeNulls(v));
|
|
181
|
+
}
|
|
182
|
+
if (typeof value === "object" && value !== null) {
|
|
183
|
+
return Object.fromEntries(
|
|
184
|
+
Object.entries(value).filter(([_, value2]) => {
|
|
185
|
+
if (value2 === null) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
}).map(([key, value2]) => [key, this.removeNulls(value2)])
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return value;
|
|
193
|
+
}
|
|
142
194
|
}
|
|
143
195
|
|
|
144
196
|
class UniwindCSSVisitor {
|
|
@@ -372,7 +424,7 @@ const generateCSSForThemes = async (themes, input) => {
|
|
|
372
424
|
return uniwindCSS;
|
|
373
425
|
};
|
|
374
426
|
|
|
375
|
-
const variants = ["ios", "android", "web", "native"];
|
|
427
|
+
const variants = ["ios", "android", "web", "native", "tv", "android-tv", "apple-tv"];
|
|
376
428
|
const generateCSSForVariants = () => {
|
|
377
429
|
let css = "";
|
|
378
430
|
variants.forEach((variant) => {
|
|
@@ -51,6 +51,9 @@ const ONE_PX = {
|
|
|
51
51
|
value: { type: "dimension", unit: "px", value: 1 }
|
|
52
52
|
};
|
|
53
53
|
class FunctionVisitor {
|
|
54
|
+
platformSelect(fn) {
|
|
55
|
+
return fn.arguments.at(0) ?? { type: "token", value: { type: "ident", value: "initial" } };
|
|
56
|
+
}
|
|
54
57
|
pixelRatio(fn) {
|
|
55
58
|
return {
|
|
56
59
|
type: "function",
|
|
@@ -97,9 +100,8 @@ class RuleVisitor {
|
|
|
97
100
|
};
|
|
98
101
|
style = (styleRule) => {
|
|
99
102
|
const firstSelector = styleRule.value.selectors.at(0)?.at(0);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return this.processThemeStyle(styleRule, secondSelector);
|
|
103
|
+
if (this.currentLayerName === "theme" && firstSelector?.type === "pseudo-class" && firstSelector.kind === "root") {
|
|
104
|
+
return this.removeNulls(this.processThemeRoot(styleRule));
|
|
103
105
|
}
|
|
104
106
|
if (firstSelector?.type === "class") {
|
|
105
107
|
return this.processClassStyle(styleRule, firstSelector);
|
|
@@ -110,14 +112,47 @@ class RuleVisitor {
|
|
|
110
112
|
this.processedClassNames.clear();
|
|
111
113
|
this.processedVariables.clear();
|
|
112
114
|
}
|
|
115
|
+
processThemeRoot(styleRule) {
|
|
116
|
+
const themeScopedRules = styleRule.value.rules?.filter((rule) => {
|
|
117
|
+
if (rule.type !== "style") {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
const firstSelector = rule.value.selectors.at(0)?.at(0);
|
|
121
|
+
const secondSelector = rule.value.selectors.at(0)?.at(1);
|
|
122
|
+
return firstSelector?.type === "nesting" && secondSelector?.type === "pseudo-class" && secondSelector.kind === "where";
|
|
123
|
+
}) ?? [];
|
|
124
|
+
const nonThemeRules = styleRule.value.rules?.filter((rule) => !themeScopedRules.includes(rule));
|
|
125
|
+
const processedThemeScopedRules = themeScopedRules.map((rule) => {
|
|
126
|
+
if (rule.type !== "style") {
|
|
127
|
+
return rule;
|
|
128
|
+
}
|
|
129
|
+
const secondSelector = rule.value.selectors.at(0)?.at(1);
|
|
130
|
+
if (secondSelector?.type === "pseudo-class" && secondSelector.kind === "where") {
|
|
131
|
+
return this.processThemeStyle(rule, secondSelector);
|
|
132
|
+
}
|
|
133
|
+
return rule;
|
|
134
|
+
});
|
|
135
|
+
return [
|
|
136
|
+
{
|
|
137
|
+
type: "style",
|
|
138
|
+
value: {
|
|
139
|
+
loc: styleRule.value.loc,
|
|
140
|
+
selectors: styleRule.value.selectors,
|
|
141
|
+
rules: nonThemeRules,
|
|
142
|
+
declarations: styleRule.value.declarations
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
...processedThemeScopedRules
|
|
146
|
+
];
|
|
147
|
+
}
|
|
113
148
|
processThemeStyle(styleRule, secondSelector) {
|
|
114
149
|
const whereSelector = secondSelector.selectors.at(0)?.at(0);
|
|
115
150
|
if (whereSelector?.type !== "class") {
|
|
116
|
-
return;
|
|
151
|
+
return styleRule;
|
|
117
152
|
}
|
|
118
153
|
const selectedVariant = this.themes.find((theme) => whereSelector.name === theme);
|
|
119
154
|
if (selectedVariant === void 0 || this.processedVariables.has(selectedVariant)) {
|
|
120
|
-
return;
|
|
155
|
+
return styleRule;
|
|
121
156
|
}
|
|
122
157
|
this.processedVariables.add(selectedVariant);
|
|
123
158
|
return {
|
|
@@ -146,6 +181,23 @@ class RuleVisitor {
|
|
|
146
181
|
}
|
|
147
182
|
};
|
|
148
183
|
}
|
|
184
|
+
// Fixes lightningcss serialization bug
|
|
185
|
+
removeNulls(value) {
|
|
186
|
+
if (Array.isArray(value)) {
|
|
187
|
+
return value.map((v) => this.removeNulls(v));
|
|
188
|
+
}
|
|
189
|
+
if (typeof value === "object" && value !== null) {
|
|
190
|
+
return Object.fromEntries(
|
|
191
|
+
Object.entries(value).filter(([_, value2]) => {
|
|
192
|
+
if (value2 === null) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
}).map(([key, value2]) => [key, this.removeNulls(value2)])
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
return value;
|
|
200
|
+
}
|
|
149
201
|
}
|
|
150
202
|
|
|
151
203
|
class UniwindCSSVisitor {
|
|
@@ -379,7 +431,7 @@ const generateCSSForThemes = async (themes, input) => {
|
|
|
379
431
|
return uniwindCSS;
|
|
380
432
|
};
|
|
381
433
|
|
|
382
|
-
const variants = ["ios", "android", "web", "native"];
|
|
434
|
+
const variants = ["ios", "android", "web", "native", "tv", "android-tv", "apple-tv"];
|
|
383
435
|
const generateCSSForVariants = () => {
|
|
384
436
|
let css = "";
|
|
385
437
|
variants.forEach((variant) => {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
var Platform = /* @__PURE__ */ ((Platform2) => {
|
|
2
|
+
Platform2["Android"] = "android";
|
|
3
|
+
Platform2["iOS"] = "ios";
|
|
4
|
+
Platform2["Web"] = "web";
|
|
5
|
+
Platform2["Native"] = "native";
|
|
6
|
+
Platform2["TV"] = "tv";
|
|
7
|
+
Platform2["AndroidTV"] = "android-tv";
|
|
8
|
+
Platform2["AppleTV"] = "apple-tv";
|
|
9
|
+
return Platform2;
|
|
10
|
+
})(Platform || {});
|
|
11
|
+
const UNIWIND_PLATFORM_VARIABLES = "__uniwind-platform-";
|
|
12
|
+
const UNIWIND_THEME_VARIABLES = "__uniwind-theme-";
|
|
13
|
+
|
|
14
|
+
export { Platform as P, UNIWIND_PLATFORM_VARIABLES as U, UNIWIND_THEME_VARIABLES as a };
|
package/dist/vite/index.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const node = require('@tailwindcss/node');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const common = require('../shared/uniwind.nl8746mK.cjs');
|
|
6
|
-
const stringifyThemes = require('../shared/uniwind.
|
|
6
|
+
const stringifyThemes = require('../shared/uniwind.DTMo4epG.cjs');
|
|
7
7
|
require('fs');
|
|
8
8
|
require('lightningcss');
|
|
9
9
|
|
package/dist/vite/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { normalizePath } from '@tailwindcss/node';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { u as uniq, n as name } from '../shared/uniwind.F-0-Rr--.mjs';
|
|
4
|
-
import { s as stringifyThemes, U as UniwindCSSVisitor, a as buildCSS, b as buildDtsFile } from '../shared/uniwind.
|
|
4
|
+
import { s as stringifyThemes, U as UniwindCSSVisitor, a as buildCSS, b as buildDtsFile } from '../shared/uniwind.BWb5KNML.mjs';
|
|
5
5
|
import 'fs';
|
|
6
6
|
import 'lightningcss';
|
|
7
7
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"private": false,
|
|
3
3
|
"name": "@niibase/uniwind",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"description": "
|
|
4
|
+
"version": "1.5.0",
|
|
5
|
+
"description": "A fork of Uniwind with Reanimated 4 support",
|
|
6
6
|
"homepage": "https://uniwind.dev",
|
|
7
7
|
"author": "Unistack",
|
|
8
8
|
"type": "module",
|
|
9
|
-
"repository": "https://github.com/divineniiquaye/uniwind",
|
|
9
|
+
"repository": "https://github.com/divineniiquaye/uniwind-oss",
|
|
10
10
|
"sideEffects": false,
|
|
11
11
|
"scripts": {
|
|
12
12
|
"precommit": "bun lint",
|
|
@@ -18,13 +18,15 @@
|
|
|
18
18
|
"prepublishOnly": "bun run build",
|
|
19
19
|
"circular:check": "dpdm --no-warning --no-tree -T --exit-code circular:1 'src/**/*.ts' 'src/**/*.tsx'",
|
|
20
20
|
"build:css": "bun run src/css/index.ts",
|
|
21
|
-
"postinstall": "node scripts/postinstall.mjs",
|
|
22
21
|
"test:native": "jest --config jest.config.native.js",
|
|
23
|
-
"test:web": "jest --config jest.config.web.js"
|
|
22
|
+
"test:web": "jest --config jest.config.web.js",
|
|
23
|
+
"test:e2e": "playwright test",
|
|
24
|
+
"release": "release-it"
|
|
24
25
|
},
|
|
25
26
|
"keywords": [
|
|
26
27
|
"unistyles",
|
|
27
28
|
"react-native-unistyles",
|
|
29
|
+
"uniwind",
|
|
28
30
|
"react-native",
|
|
29
31
|
"react",
|
|
30
32
|
"native",
|
|
@@ -78,8 +80,8 @@
|
|
|
78
80
|
"LICENSE"
|
|
79
81
|
],
|
|
80
82
|
"dependencies": {
|
|
81
|
-
"@tailwindcss/node": "4.1
|
|
82
|
-
"@tailwindcss/oxide": "4.1
|
|
83
|
+
"@tailwindcss/node": "4.2.1",
|
|
84
|
+
"@tailwindcss/oxide": "4.2.1",
|
|
83
85
|
"culori": "4.0.2",
|
|
84
86
|
"lightningcss": "1.30.1"
|
|
85
87
|
},
|
|
@@ -92,7 +94,8 @@
|
|
|
92
94
|
"tailwindcss": ">=4"
|
|
93
95
|
},
|
|
94
96
|
"devDependencies": {
|
|
95
|
-
"@
|
|
97
|
+
"@playwright/test": "1.58.2",
|
|
98
|
+
"@react-native/babel-preset": "0.84.1",
|
|
96
99
|
"@testing-library/jest-dom": "6.9.1",
|
|
97
100
|
"@testing-library/jest-native": "5.4.3",
|
|
98
101
|
"@testing-library/react": "16.3.2",
|
|
@@ -101,19 +104,22 @@
|
|
|
101
104
|
"@types/culori": "4.0.1",
|
|
102
105
|
"@types/jest": "30.0.0",
|
|
103
106
|
"@types/react": "catalog:",
|
|
104
|
-
"
|
|
105
|
-
"
|
|
107
|
+
"dpdm": "4.0.1",
|
|
108
|
+
"git-cliff": "2.12.0",
|
|
106
109
|
"jest": "30.2.0",
|
|
107
110
|
"jest-environment-jsdom": "30.2.0",
|
|
108
|
-
"
|
|
111
|
+
"metro": "0.84.2",
|
|
112
|
+
"prettier": "3.8.1",
|
|
109
113
|
"react-native-gesture-handler": "2.28.0",
|
|
110
114
|
"react-native-reanimated": "catalog:",
|
|
111
115
|
"react-native-safe-area-context": "5.6.0",
|
|
112
116
|
"react-native-web": "catalog:",
|
|
113
|
-
"react-test-renderer": "19.
|
|
117
|
+
"react-test-renderer": "19.2.4",
|
|
118
|
+
"release-it": "19.2.4",
|
|
114
119
|
"ts-jest": "29.4.6",
|
|
115
120
|
"typescript": "catalog:",
|
|
116
121
|
"unbuild": "3.6.1",
|
|
117
|
-
"vite": "7.
|
|
122
|
+
"vite": "7.3.1",
|
|
123
|
+
"esbuild": "0.27.3"
|
|
118
124
|
}
|
|
119
125
|
}
|
package/readme.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
[](https://www.npmjs.com/package/uniwind)
|
|
16
16
|
[](https://opensource.org/licenses/MIT)
|
|
17
17
|
|
|
18
|
-
> **Note:** This is a fork of uniwind that
|
|
18
|
+
> **Note:** This is a fork of **uniwind** that leverages **react-native-reanimated** (v4.0.0+) to enable CSS-like animations and transitions using Tailwind classes. This package is kept in sync with the original `uniwind` releases.
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
21
21
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
bun add @niibase/uniwind tailwindcss react-native-safe-area-context react-native-reanimated
|
|
25
25
|
|
|
26
26
|
# Or install from the original package
|
|
27
|
-
bun add uniwind tailwindcss react-native-safe-area-context
|
|
27
|
+
bun add uniwind tailwindcss react-native-safe-area-context
|
|
28
28
|
|
|
29
29
|
# Or install @niibase/uniwind as alias for uniwind
|
|
30
30
|
bun add uniwind@npm:@niibase/uniwind tailwindcss react-native-safe-area-context react-native-reanimated
|
|
@@ -41,8 +41,8 @@ Then follow [installation guides](https://docs.uniwind.dev/quickstart)
|
|
|
41
41
|
|
|
42
42
|
## Features
|
|
43
43
|
|
|
44
|
-
- ⚛️ Out‑of‑the‑box `className` bindings for every React Native component
|
|
45
|
-
- ⚡ Styles are computed at build time for maximum performance
|
|
44
|
+
- ⚛️ Out‑of‑the‑box `className` bindings for every React Native component
|
|
45
|
+
- ⚡ Styles are computed at build time for maximum performance
|
|
46
46
|
- 🎬 **CSS animations and transitions** powered by Reanimated 4
|
|
47
47
|
- 🌙 Dark mode and 🎨 fully customizable themes
|
|
48
48
|
- 🧩 Pseudo‑classes support — `focus`, `active`, `disabled`, and more
|
|
@@ -50,14 +50,6 @@ Then follow [installation guides](https://docs.uniwind.dev/quickstart)
|
|
|
50
50
|
- 🧰 Use custom CSS properties directly in React Native
|
|
51
51
|
- 🔥 And [much more](https://docs.uniwind.dev/api/use-uniwind)
|
|
52
52
|
|
|
53
|
-
## Roadmap
|
|
54
|
-
|
|
55
|
-
- [x] **Reanimated 4 support** - Full compatibility with React Native Reanimated v4 ✅
|
|
56
|
-
- [ ] **Babel support to extend beyond React Native components** - Enable className support for custom components and third-party libraries
|
|
57
|
-
- [ ] **Unistyles (future)** - Integration with Unistyles for enhanced styling capabilities
|
|
58
|
-
|
|
59
|
-
> **Note:** Once Babel support is completed, the likelihood of adding Unistyles support is high.
|
|
60
|
-
|
|
61
53
|
## Contributing
|
|
62
54
|
|
|
63
55
|
Contributions are welcome!
|