Skip to content

Commit 2070169

Browse files
committed
fix: improve types of StyleRegistry
1 parent 0a5abc2 commit 2070169

6 files changed

Lines changed: 166 additions & 93 deletions

File tree

example/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Text } from "react-native-css-nitro/components/Text";
55

66
StyleRegistry.set("text-red-500", [
77
{ s: [], d: [{ color: "red" }] },
8-
{ s: [], d: [{ color: "green" }] },
8+
{ s: [], d: [{ color: "green" }], m: [["=", "orientation", "landscape"]] },
99
]);
1010

1111
export default function App() {

src/compiler/types.ts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import type { MediaFeatureNameFor_MediaFeatureId } from "lightningcss";
2+
3+
/******************************** Styles ********************************/
4+
export interface StyleRule {
5+
/** Specificity */
6+
s: SpecificityArray;
7+
/** Declarations */
8+
d?: StyleDeclaration[];
9+
/** Variables */
10+
v?: VariableDescriptor[];
11+
/** Named Containers */
12+
c?: string[];
13+
14+
/** Declarations use variables */
15+
dv?: number;
16+
17+
/**
18+
* Conditionals
19+
*/
20+
21+
/** MediaQuery */
22+
m?: MediaCondition[];
23+
/** PseudoClassesQuery */
24+
p?: PseudoClassesQuery;
25+
/** Container Query */
26+
cq?: ContainerQuery[];
27+
/** Attribute Conditions */
28+
aq?: AttributeQuery[];
29+
30+
/**
31+
* Animations and Transitions
32+
*/
33+
34+
/** Animations */
35+
a?: boolean;
36+
}
37+
38+
export type StyleDeclaration =
39+
/** This is a static style object */
40+
| Record<string, StyleDescriptor>
41+
/** A style that needs to be set */
42+
| [StyleDescriptor, string | string[]]
43+
/** A value that can only be computed at runtime, and only after styles have been calculated */
44+
| [StyleDescriptor, string | string[], 1];
45+
46+
export type StyleDescriptor =
47+
| string
48+
| number
49+
| boolean
50+
| undefined
51+
| StyleFunction
52+
| StyleDescriptor[];
53+
54+
export type StyleFunction =
55+
| [
56+
Record<never, never>,
57+
string, // string
58+
]
59+
| [
60+
Record<never, never>,
61+
string, // string
62+
StyleDescriptor, // arguments
63+
];
64+
65+
/****************************** Media Query *****************************/
66+
67+
export type MediaCondition =
68+
// Boolean
69+
| ["!!", MediaFeatureNameFor_MediaFeatureId]
70+
// Not
71+
| ["!", MediaCondition]
72+
// And
73+
| ["&", MediaCondition[]]
74+
// Or
75+
| ["|", MediaCondition[]]
76+
// Comparison
77+
| [
78+
MediaFeatureComparison,
79+
MediaFeatureNameFor_MediaFeatureId,
80+
StyleDescriptor,
81+
]
82+
// [Start, End]
83+
| [
84+
"[]",
85+
MediaFeatureNameFor_MediaFeatureId,
86+
StyleDescriptor, // Start
87+
MediaFeatureComparison, // Start comparison
88+
StyleDescriptor, // End
89+
MediaFeatureComparison, // End comparison
90+
];
91+
92+
export type MediaFeatureComparison = "=" | ">" | ">=" | "<" | "<=";
93+
94+
/***************************** Pseudo Classes ***************************/
95+
96+
export interface PseudoClassesQuery {
97+
/** Hover */
98+
h?: 1;
99+
/** Active */
100+
a?: 1;
101+
/** Focus */
102+
f?: 1;
103+
}
104+
105+
/****************************** Variables *******************************/
106+
107+
export type VariableDescriptor = [string, StyleDescriptor];
108+
109+
/*************************** Attribute Query ****************************/
110+
111+
type AttributeQueryType =
112+
| "a" // Attribute
113+
| "d"; // Data-Attribute
114+
115+
export type AttributeQuery =
116+
| [AttributeQueryType, string] // Exists
117+
| [AttributeQueryType, string, "!"] // Falsy
118+
| [AttributeQueryType, string, AttrSelectorOperator, string] // Use operator
119+
| [AttributeQueryType, string, AttrSelectorOperator, string, "i" | "s"]; // Case sensitivity
120+
121+
export type AttrSelectorOperator = "=" | "~=" | "|=" | "^=" | "$=" | "*=";
122+
123+
/****************************** Containers *****************************/
124+
125+
export interface ContainerQuery {
126+
/** Name */
127+
n?: string | null;
128+
m?: MediaCondition;
129+
p?: PseudoClassesQuery;
130+
a?: AttributeQuery[];
131+
}
132+
133+
/****************************** Specificity *****************************/
134+
135+
/**
136+
* https://drafts.csswg.org/selectors/#specificity-rules
137+
*
138+
* This array is sorted by most common values when parsing a StyleSheet
139+
*/
140+
export type SpecificityArray = SpecificityValue[];
141+
export type SpecificityValue = number | undefined;

src/specs/StyleRegistry/HybridStyleRegistry.nitro.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,40 +108,40 @@ export type StyleConfigNativeStyleToProp = [string, string[]];
108108

109109
interface StyleRule {
110110
s: SpecificityArray;
111-
v?: VariableDescriptor[];
112-
d?: StyleDescriptor[];
111+
v?: HybridVariableDescriptor[];
112+
d?: HybridStyleDescriptor[];
113113

114114
/** MediaQuery */
115-
m?: MediaCondition[];
115+
m?: HybridMediaCondition[];
116116
}
117117

118118
type SpecificityArray = number[];
119-
type StyleDescriptor = AnyMap;
119+
type HybridStyleDescriptor = AnyMap;
120120

121121
/****************************** Variables *******************************/
122122

123-
type VariableDescriptor = [
123+
type HybridVariableDescriptor = [
124124
string,
125125
AnyMap | AnyMap[] | string | number | boolean,
126126
];
127127

128128
/****************************** Conditions ******************************/
129129

130-
export type MediaCondition =
130+
export type HybridMediaCondition =
131131
| [string, string]
132132
| [string, string[]]
133133
// Comparison
134134
| [
135135
MediaFeatureComparison,
136136
MediaFeatureNameFor_MediaFeatureId,
137-
StyleDescriptor,
137+
HybridStyleDescriptor,
138138
]
139139
// [Start, End]
140140
| [
141141
string,
142142
MediaFeatureNameFor_MediaFeatureId,
143-
StyleDescriptor, // Start
143+
HybridStyleDescriptor, // Start
144144
MediaFeatureComparison, // Start comparison
145-
StyleDescriptor, // End
145+
HybridStyleDescriptor, // End
146146
MediaFeatureComparison, // End comparison
147147
];

src/specs/StyleRegistry/index.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1-
import { processColor } from 'react-native';
2-
import { NitroModules } from 'react-native-nitro-modules';
3-
import type { HybridStyleRegistry } from './HybridStyleRegistry.nitro';
1+
import { processColor } from "react-native";
42

5-
export const StyleRegistry =
6-
NitroModules.createHybridObject<HybridStyleRegistry>('HybridStyleRegistry');
3+
import { NitroModules } from "react-native-nitro-modules";
4+
5+
import type { StyleRule } from "../../compiler/types";
6+
import type { HybridStyleRegistry } from "./HybridStyleRegistry.nitro";
7+
8+
export const StyleRegistry = NitroModules.createHybridObject<
9+
Omit<HybridStyleRegistry, keyof JSStyleRegistry> & JSStyleRegistry
10+
>("HybridStyleRegistry");
11+
12+
interface JSStyleRegistry {
13+
set(className: string, styleRule: StyleRule[]): void;
14+
}
715

816
// const { width, height, scale, fontScale } = Dimensions.get('window');
917
// StyleRegistry.setWindowDimensions(width, height, scale, fontScale);

src/specs/StyleRegistry/types.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.

src/utils.ts

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import type { ViewHandle } from './specs/StyleRegistry/types';
2-
31
export function copyComponentProperties(Component: any, StyledComponent: any) {
42
Object.entries(Component).forEach(([key, value]) => {
53
// Filter out the keys we don't want to copy
6-
if (['$$typeof', 'render'].includes(key)) {
4+
if (["$$typeof", "render"].includes(key)) {
75
return;
86
}
97

@@ -16,7 +14,7 @@ export function copyComponentProperties(Component: any, StyledComponent: any) {
1614
}
1715

1816
export function getDeepKeys(obj: unknown, keys = new Set<string>()): string[] {
19-
if (typeof obj !== 'object' || !obj) {
17+
if (typeof obj !== "object" || !obj) {
2018
return [];
2119
}
2220

@@ -33,32 +31,3 @@ export function getDeepKeys(obj: unknown, keys = new Set<string>()): string[] {
3331

3432
return Array.from(keys);
3533
}
36-
37-
export function findShadowNodeForHandle(handle: ViewHandle) {
38-
const node =
39-
handle?.__internalInstanceHandle?.stateNode?.node ??
40-
handle?.getScrollResponder?.()?.getNativeScrollRef?.()
41-
?.__internalInstanceHandle?.stateNode?.node ??
42-
handle?.getNativeScrollRef?.()?.__internalInstanceHandle?.stateNode?.node ??
43-
handle?._viewRef?.__internalInstanceHandle?.stateNode?.node ??
44-
handle?.viewRef?.current?.__internalInstanceHandle?.stateNode?.node ??
45-
handle?._nativeRef?.__internalInstanceHandle?.stateNode?.node;
46-
47-
if (
48-
!node &&
49-
handle?.props?.horizontal &&
50-
handle?.constructor?.name === 'FlatList'
51-
) {
52-
throw new Error(
53-
'react-native-css: detected an unsupported FlatList with the horizontal prop. This will cause crashes on Android due to a bug in React Native core. Read more: https://github.com/facebook/react-native/issues/51601'
54-
);
55-
}
56-
57-
if (!node) {
58-
throw new Error(
59-
`react-native-css: Could not find shadow node for one of your components of type ${handle?.constructor?.name ?? 'unknown'}`
60-
);
61-
}
62-
63-
return node;
64-
}

0 commit comments

Comments
 (0)