@uniflowed/stylex 0.0.0-alpha.40 → 0.0.0-alpha.42

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.
@@ -0,0 +1,40 @@
1
+ // @flow
2
+
3
+ export type NativeStyleProps = { readonly style: { readonly [string]: string | number } };
4
+
5
+ /** Return null for web namespaces; mixing renderer outputs is an error. */
6
+ export function nativeProps(
7
+ styles: $ReadOnlyArray<mixed>,
8
+ nativeOnly: boolean = false,
9
+ ): NativeStyleProps | null {
10
+ let native = false;
11
+ let web = false;
12
+ const merged: { [string]: string | number } = {};
13
+ const pending = [...styles];
14
+ for (let index = 0; index < pending.length; index += 1) {
15
+ const value = pending[index];
16
+ if (Array.isArray(value)) {
17
+ pending.splice(index + 1, 0, ...value);
18
+ continue;
19
+ }
20
+ if (value == null || typeof value !== "object") continue;
21
+ // Static objects written by the compiler; validate their scalar fields.
22
+ const namespace: { [string]: mixed } = value as $FlowFixMe;
23
+ if (namespace.$$css === true) web = true;
24
+ if (namespace.$$native !== true) {
25
+ if (nativeOnly) throw new Error("StyleX native: expected a compiled native namespace");
26
+ continue;
27
+ }
28
+ native = true;
29
+ for (const property of Object.keys(namespace)) {
30
+ if (property === "$$native") continue;
31
+ const entry = namespace[property];
32
+ if (typeof entry !== "string" && typeof entry !== "number") {
33
+ throw new Error(`StyleX native: invalid compiled value for ${property}`);
34
+ }
35
+ merged[property] = entry;
36
+ }
37
+ }
38
+ if (native && web) throw new Error("StyleX: cannot mix native style objects with web classes");
39
+ return native ? { style: merged } : null;
40
+ }
package/native.js ADDED
@@ -0,0 +1,40 @@
1
+ // @flow
2
+ import type { ViewStyle, TextStyle, ImageStyle } from "react-native";
3
+ import { nativeRuntimeRequired } from "@uniflowed/core/native";
4
+ import { nativeProps } from "./native-props.js";
5
+
6
+ // Use one property map: a ViewStyle | TextStyle union would accept an invalid
7
+ // fontWeight through its ViewStyle branch, whose optional fields all match.
8
+ export type NativeStyle = $ReadOnly<{
9
+ ...$Exact<ViewStyle>,
10
+ ...$Exact<TextStyle>,
11
+ ...$Exact<ImageStyle>,
12
+ }>;
13
+ export type NativeStyleArgument<Style> =
14
+ | Style
15
+ | false
16
+ | null
17
+ | void
18
+ | $ReadOnlyArray<NativeStyleArgument<Style>>;
19
+ type StyleFields<Value> = Value extends $ReadOnlyArray<infer Item>
20
+ ? StyleFields<Item>
21
+ : Value extends (false | null | void)
22
+ ? {}
23
+ : Value;
24
+
25
+ /** Compile-time namespaces, checked against the app's React Native styles. */
26
+ export function create<Styles extends { readonly [string]: NativeStyle }>(styles: Styles): Styles {
27
+ return nativeRuntimeRequired("@uniflowed/stylex/native", "stylex.create");
28
+ }
29
+
30
+ /** Native-only props retain the authored property types and never add className. */
31
+ export function props<Args extends $ReadOnlyArray<NativeStyleArgument<NativeStyle>>>(
32
+ ...styles: Args
33
+ ): { readonly style: Partial<StyleFields<Args>> } {
34
+ const result = nativeProps(styles, true);
35
+ // The compiler validates the native subset and preserves every scalar value.
36
+ // The merger copies those fields, but its dynamic keys cannot retain Style.
37
+ return (result ?? { style: {} }) as $FlowFixMe;
38
+ }
39
+
40
+ export const stylex = { create, props };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniflowed/stylex",
3
- "version": "0.0.0-alpha.40",
3
+ "version": "0.0.0-alpha.42",
4
4
  "description": "Flow declarations for @uniflowed/stylex, part of the Unified Toolchain for Flow.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -15,13 +15,22 @@
15
15
  "./props": "./props.js",
16
16
  "./preset": "./preset.js",
17
17
  "./theme": "./theme.js",
18
- "./tokens.stylex.js": "./tokens.stylex.js"
18
+ "./tokens.stylex.js": "./tokens.stylex.js",
19
+ "./native": "./native.js"
19
20
  },
20
21
  "files": [
21
22
  "*.js",
22
23
  "!*.test.js"
23
24
  ],
24
25
  "dependencies": {
25
- "@uniflowed/core": "0.0.0-alpha.40"
26
+ "@uniflowed/core": "0.0.0-alpha.42"
27
+ },
28
+ "peerDependencies": {
29
+ "react-native": ">=0.86.0"
30
+ },
31
+ "peerDependenciesMeta": {
32
+ "react-native": {
33
+ "optional": true
34
+ }
26
35
  }
27
36
  }
package/props.js CHANGED
@@ -1,4 +1,6 @@
1
1
  // @flow
2
+
3
+ import { nativeProps } from "./native-props.js";
2
4
  //
3
5
  // `@uniflowed/stylex/props`: the merge, and the only part of StyleX that runs.
4
6
  //
@@ -56,7 +58,10 @@ export type CompiledStyle = {
56
58
  export type StyleArgument = mixed;
57
59
 
58
60
  /** What `props` hands to an element. */
59
- export type StyleProps = { readonly className?: string };
61
+ export type StyleProps = {
62
+ readonly className?: string,
63
+ readonly style?: { readonly [string]: string | number },
64
+ };
60
65
 
61
66
  /** What one property contributed, once the merge has picked a winner. */
62
67
  type Winner = string | null | CompiledClasses;
@@ -73,6 +78,8 @@ type Winner = string | null | CompiledClasses;
73
78
  * survived.
74
79
  */
75
80
  export function props(...styles: $ReadOnlyArray<StyleArgument>): StyleProps {
81
+ const native = nativeProps(styles);
82
+ if (native != null) return native;
76
83
  const winners: { [string]: Winner } = {};
77
84
  collect(styles, winners);
78
85