Add a merged style to check types of react and native at the same time

This commit is contained in:
Zoe Roux
2022-11-17 01:16:53 +09:00
parent bf58c6f537
commit 186ccf783b
14 changed files with 94 additions and 100 deletions
+5 -9
View File
@@ -12,7 +12,7 @@ const CustomBox = ({ color, ...props }: { color: string } & Stylable) => {
const { css } = useYoshiki();
return (
<View {...css({ bg: color, p: "13px", alignItems: "center" }, props)}>
<View {...css({ bg: color, alignItems: "center" }, props)}>
<Text {...css({ color: "white" })}>Text inside the custom black box.</Text>
</View>
);
@@ -26,7 +26,7 @@ const BoxWithoutProps = (props: Stylable) => {
{...css(
{
backgroundColor: { xs: "#00ff00", md: "#ff0000" },
hover: { alignContent: "center" },
hover: { alignContent: "center", alignItems: "center" },
press: { alignContent: "center" },
focus: { alignContent: "center" },
},
@@ -34,13 +34,9 @@ const BoxWithoutProps = (props: Stylable) => {
)}
>
<Text
{...css(
{
backgroundColor: { xs: "#00ff00", md: "#ff0000" },
hover: { alignContent: "center" },
},
props,
)}
{...css({
backgroundColor: { xs: "#00ff00", md: "#ff0000" },
})}
>
Text inside the box without props (green on small screens, red on bigs)
</Text>
+2 -2
View File
@@ -3,9 +3,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for details.
//
import { Theme, ThemeProvider, useYoshiki } from "yoshiki";
import { Theme, ThemeProvider } from "yoshiki";
import { useYoshiki, useMobileHover } from "yoshiki/web";
import { AppProps } from "next/app";
import { useMobileHover } from "yoshiki";
declare module "yoshiki" {
export interface Theme {
@@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for details.
//
import { StyleRegistryProvider, createStyleRegistry } from "yoshiki";
import { StyleRegistryProvider, createStyleRegistry } from "yoshiki/web";
import Document, { DocumentContext } from "next/document";
Document.getInitialProps = async (ctx: DocumentContext) => {
+1 -1
View File
@@ -5,7 +5,7 @@
import Head from "next/head";
import Image from "next/image";
import { useYoshiki, Stylable } from "yoshiki";
import { useYoshiki, Stylable } from "yoshiki/web";
import { ReactNode } from "react";
const Box = ({ children, ...props }: { children?: ReactNode } & Stylable) => {
+34 -10
View File
@@ -3,14 +3,38 @@
// Licensed under the MIT license. See LICENSE file in the project root for details.
//
export { type Theme, breakpoints, useTheme, ThemeProvider } from "./theme";
import {
useYoshiki as useWebYoshiki,
type Stylable as WebStylable,
type StylableHoverable as WebStylableHoverable,
} from "./web";
import type {
Stylable as NativeStylable,
StylableHoverable as NativeStylableHoverable,
} from "./native";
export {
useYoshiki,
useStyleRegistry,
StyleRegistryProvider,
createStyleRegistry,
type Stylable,
useMobileHover,
Pressable
} from "./react";
import { YsStyleProps } from "./native/generator";
import { Theme } from "./theme";
import { WithState, EnhancedStyle } from "./type";
import type { ViewStyle, ImageStyle, TextStyle } from "react-native";
export const useYoshiki = (): {
css: <
Style extends ViewStyle | TextStyle | ImageStyle,
State extends Partial<WithState<EnhancedStyle<Style>>> | Record<string, never>,
>(
style: EnhancedStyle<Style> & State,
leftOvers?: { style?: Style } | WebStylable,
) => YsStyleProps<Style, State> | WebStylable;
theme: Theme;
} => {
// This index.ts will be used on the web wherase react-native will use the ./native import.
// We need to unsure that this functions works on the web but have types that merge the two here.
// @ts-ignore See comment above.
return useWebYoshiki();
};
export type Stylable = WebStylable | NativeStylable;
export type StylableHoverable = WebStylableHoverable | NativeStylableHoverable;
export { breakpoints, type Theme, ThemeProvider, useTheme } from "./theme";
+13 -9
View File
@@ -7,14 +7,14 @@ import { ViewStyle, TextStyle, ImageStyle, useWindowDimensions } from "react-nat
import { breakpoints, Theme, useTheme } from "../theme";
import { AtLeastOne, Breakpoints, WithState, YoshikiStyle, hasState } from "../type";
import { isBreakpoints } from "../utils";
import { shorthandsFn } from "./shorthands";
import { shorthandsFn } from "../shorthands";
type EnhancedStyle<Properties> = {
export type EnhancedStyle<Properties> = {
[key in keyof Properties]: YoshikiStyle<Properties[key]>;
} & {
[key in keyof typeof shorthandsFn]?: Parameters<typeof shorthandsFn[key]>[0];
};
type Properties = ViewStyle | TextStyle | ImageStyle;
export type Properties = ViewStyle | TextStyle | ImageStyle;
const useBreakpoint = (): number => {
const { width } = useWindowDimensions();
@@ -54,6 +54,10 @@ const propertyMapper = <
return [[key, value]];
};
export type YsStyleProps<Style, State> = State extends AtLeastOne<WithState<Style>>
? { style: (state: { pressed: boolean; focused: boolean; hovered: boolean }) => Style }
: { style: Style };
export const useYoshiki = () => {
const breakpoint = useBreakpoint();
const theme = useTheme();
@@ -65,9 +69,7 @@ export const useYoshiki = () => {
>(
css: EnhancedStyle<Style> & State,
leftOvers?: { style?: Style },
): State extends AtLeastOne<WithState<unknown>>
? { style: (state: { pressed: boolean; focused: boolean; hovered: boolean }) => Style }
: { style: Style } => {
): YsStyleProps<Style, State> => {
const { style, ...leftOverProps } = leftOvers ?? {};
const processStyle = (styleList: EnhancedStyle<Style>): Style => {
@@ -112,9 +114,11 @@ export const useYoshiki = () => {
};
export type Stylable = {
style: Properties;
style?: Properties;
};
export type StylableHoverable = {
style: ((state: { hovered: boolean, focused: boolean, pressed: boolean}) => Properties) | Properties;
}
style:
| ((state: { hovered: boolean; focused: boolean; pressed: boolean }) => Properties)
| Properties;
};
+3 -3
View File
@@ -14,11 +14,11 @@ export const Pressable = ({
onBlur,
style,
...props
}: {
}: Omit<PressableProps, "style"> & {
style:
| PressableProps["style"]
| StyleProp<ViewStyle>
| ((state: { pressed: boolean; hovered: boolean; focused: boolean }) => StyleProp<ViewStyle>);
} & PressableProps) => {
}) => {
const [hovered, setHover] = useState(false);
const [focused, setFocus] = useState(false);
+1 -1
View File
@@ -5,6 +5,6 @@
export { type Theme, breakpoints, useTheme, ThemeProvider } from "../theme";
export { useYoshiki, type Stylable } from "./generator";
export { useYoshiki, type Stylable, type StylableHoverable } from "./generator";
export { Pressable } from "./hover";
+2 -2
View File
@@ -9,7 +9,7 @@ import { isBreakpoints } from "../utils";
import { CSSProperties, useInsertionEffect } from "react";
import { useStyleRegistry } from "./registry";
import { Properties } from "csstype";
import { shorthandsFn } from "./shorthands";
import { shorthandsFn } from "../shorthands";
type _CssObject = {
[key in keyof Properties]: YoshikiStyle<Properties[key]>;
@@ -17,7 +17,7 @@ type _CssObject = {
[key in keyof typeof shorthandsFn]?: Parameters<typeof shorthandsFn[key]>[0];
};
type CssObject = Partial<WithState<_CssObject>> & _CssObject;
export type CssObject = Partial<WithState<_CssObject>> & _CssObject;
const stateMapper: { [key in keyof (WithState<undefined> & { normal: undefined })]: (cn: string) => string } = {
normal: (cn) => `.${cn}`,
-56
View File
@@ -1,56 +0,0 @@
//
// Copyright (c) Zoe Roux and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
//
import { YoshikiStyle } from "../type";
import { Properties } from "csstype";
type YSPs = { [key in keyof Properties]: YoshikiStyle<Properties[key]> };
export const shorthandsFn = {
p: (v: YSPs["padding"]): YSPs => ({
padding: v,
}),
pX: (v: YSPs["paddingLeft"]): YSPs => ({
paddingLeft: v,
paddingRight: v,
}),
paddingX: (v: YSPs["paddingLeft"]): YSPs => ({
paddingLeft: v,
paddingRight: v,
}),
pY: (v: YSPs["paddingTop"]): YSPs => ({
paddingTop: v,
paddingBottom: v,
}),
paddingY: (v: YSPs["paddingTop"]): YSPs => ({
paddingTop: v,
paddingBottom: v,
}),
m: (v: YSPs["margin"]): YSPs => ({
margin: v,
}),
mX: (v: YSPs["marginLeft"]): YSPs => ({
marginLeft: v,
marginRight: v,
}),
marginX: (v: YSPs["marginLeft"]): YSPs => ({
marginLeft: v,
marginRight: v,
}),
mY: (v: YSPs["marginTop"]): YSPs => ({
marginTop: v,
marginBottom: v,
}),
marginY: (v: YSPs["marginTop"]): YSPs => ({
marginTop: v,
marginBottom: v,
}),
// This can't be background because react native does not support it.
bg: (v: YSPs["backgroundColor"]): YSPs => ({
// We still remove the background in case it was set before.
background: "unset",
backgroundColor: v,
}),
};
@@ -3,11 +3,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for details.
//
import { YoshikiStyle } from "../type";
import { ImageStyle, TextStyle, ViewStyle } from "react-native";
import type { EnhancedStyle } from "./type";
import type { ViewStyle } from "react-native";
type Properties = ViewStyle | TextStyle | ImageStyle;
type YSPs = { [key in keyof Properties]: YoshikiStyle<Properties[key]> };
type YSPs = EnhancedStyle<ViewStyle>
export const shorthandsFn = {
p: (v: YSPs["padding"]): YSPs => ({
+16
View File
@@ -4,6 +4,8 @@
//
import { breakpoints, Theme } from "./theme";
import { Properties as CssProperties } from "csstype";
import type { ViewStyle, ImageStyle, TextStyle } from "react-native";
export type YoshikiStyle<Property> =
| Property
@@ -25,3 +27,17 @@ export const hasState = <Style>(obj: unknown): obj is WithState<Style> => {
if (!obj || typeof obj !== "object") return false;
return "hover" in obj || "focus" in obj || "press" in obj;
};
export type OmitNever<T> = {
[key in keyof T as T[key] extends never ? never : key]: T[key];
};
export type Combine<A, B> = OmitNever<Pick<A & B, keyof A & keyof B>>;
export type CommonCss<Style extends ViewStyle | ImageStyle | TextStyle> = Combine<
CssProperties,
Style
>;
export type EnhancedStyle<Style extends ViewStyle | ImageStyle | TextStyle> = {
[key in keyof CommonCss<Style>]: YoshikiStyle<CommonCss<Style>[key]>;
};
+12 -1
View File
@@ -3,4 +3,15 @@
// Licensed under the MIT license. See LICENSE file in the project root for details.
//
export * from "./index";
export { type Theme, breakpoints, useTheme, ThemeProvider } from "./theme";
export {
useYoshiki,
useStyleRegistry,
StyleRegistryProvider,
createStyleRegistry,
type Stylable,
type StylableHoverable,
useMobileHover,
Pressable
} from "./react";
+1 -1
View File
@@ -3,4 +3,4 @@
// Licensed under the MIT license. See LICENSE file in the project root for details.
//
export * from "./src";
export * from "./src/web";