From 6a54aded634ca58c40d8c15e70e771c1220f9b8d Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Tue, 13 Dec 2022 00:05:33 +0900 Subject: [PATCH] Add higher order breakpoints --- README.md | 48 +++++++++++++++++++---- examples/expo-example/src/app.tsx | 28 +++++++------ examples/next-example/src/pages/index.tsx | 20 ++++++---- packages/yoshiki/package.json | 2 +- packages/yoshiki/src/native/generator.tsx | 3 +- packages/yoshiki/src/native/index.tsx | 1 + packages/yoshiki/src/native/type.ts | 21 +++++++++- packages/yoshiki/src/type.ts | 2 +- packages/yoshiki/src/utils.ts | 11 ++++++ packages/yoshiki/src/web/generator.ts | 13 +++++- packages/yoshiki/src/web/index.ts | 2 +- 11 files changed, 116 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 8ee2044..7166946 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,11 @@ As any other npm package, simply run -``yarn add yoshiki`` +`yarn add yoshiki` or -``npm install --save yoshiki`` - +`npm install --save yoshiki` ## Usage @@ -70,6 +69,41 @@ const ColoredBox = ({ color }: { color: string }) => { }; ``` +You can also use multiple style objects to apply some conditions or a breakpoint to multiple styles at once: + +```tsx +import { useState } from "react"; +import { Text, View } from "react-native"; +import { Stylable, useYoshiki, md } from "yoshiki/native"; + +const ColoredBox = ({ color }: { color: string }) => { + const { css } = useYoshiki(); + const [state, setState] = useState(state); + + return ( + theme.spaccing, + m: 1, + }, + md({ + width: rem(3), + }), + ])} + > + Text inside the colored box. + + ); +}; +``` + +This syntax, as any others of Yoshiki works on both React and React Native. + ## Recipes ### Customize your own components @@ -237,21 +271,19 @@ const { css, theme } = useYoshiki; The `theme` variable is the one returned from `useTheme` and the css function has the following signature: ```typescript -css: (css: CssObject, leftovers: object) => Props +css: (css: CssObject, leftovers: object) => Props; ``` The first parameter is a css object, in react web that means a dictionary of css key-values. On React Native that means -a `ViewStyle`, a `TextStyle` or an `ImageStyle`. Yoshiki will unsure type safety by returning the style object needed -for your arguments. +a `ViewStyle`, a `TextStyle` or an `ImageStyle`. Yoshiki will unsure type safety by returning the style object needed +for your arguments. The css object can also take the keys `hover`, `focus` and `press`, and it will apply the style object given as a value to the object only when it should. - The leftover parameter is here to allow your component to be customized by yoshiki. See [Customize your own components](#customize-your-own-components) for more details. - ### useTheme ```typescript diff --git a/examples/expo-example/src/app.tsx b/examples/expo-example/src/app.tsx index db0fdaa..7e75b86 100644 --- a/examples/expo-example/src/app.tsx +++ b/examples/expo-example/src/app.tsx @@ -6,7 +6,7 @@ import { StatusBar } from "expo-status-bar"; import { Text, View, Pressable, TextProps } from "react-native"; import { registerRootComponent } from "expo"; -import { Stylable, useYoshiki, px } from "yoshiki/native"; +import { Stylable, useYoshiki, px, md } from "yoshiki/native"; import { H1 } from "@expo/html-elements"; const CustomBox = ({ color, ...props }: { color: string } & Stylable) => { @@ -27,15 +27,19 @@ const BoxWithoutProps = (props: Stylable) => { return ( @@ -55,9 +59,9 @@ const P = (props: TextProps) => { return ( diff --git a/examples/next-example/src/pages/index.tsx b/examples/next-example/src/pages/index.tsx index fdda0e5..4722d1b 100644 --- a/examples/next-example/src/pages/index.tsx +++ b/examples/next-example/src/pages/index.tsx @@ -5,7 +5,7 @@ import Head from "next/head"; import Image from "next/image"; -import { useYoshiki, Stylable, px } from "yoshiki/web"; +import { useYoshiki, Stylable, px, md } from "yoshiki/web"; import { ReactNode } from "react"; const Box = ({ children, ...props }: { children?: ReactNode } & Stylable) => { @@ -22,13 +22,17 @@ export default function Home(props: object) { return (
diff --git a/packages/yoshiki/package.json b/packages/yoshiki/package.json index 6f33f9c..e715794 100644 --- a/packages/yoshiki/package.json +++ b/packages/yoshiki/package.json @@ -1,6 +1,6 @@ { "name": "yoshiki", - "version": "0.2.13", + "version": "0.3.1", "author": "Zoe Roux (https://github.com/AnonymusRaccoon)", "license": "MIT", "keywords": [ diff --git a/packages/yoshiki/src/native/generator.tsx b/packages/yoshiki/src/native/generator.tsx index 3bf32b6..050aaa3 100644 --- a/packages/yoshiki/src/native/generator.tsx +++ b/packages/yoshiki/src/native/generator.tsx @@ -36,7 +36,8 @@ const propertyMapper = ( const bpKeys = Object.keys(breakpoints) as Array>; for (let i = breakpoint; i >= 0; i--) { if (bpKeys[i] in value) { - const bpVal = value[bpKeys[i]]; + const bpValOrF = value[bpKeys[i]]; + const bpVal = typeof bpValOrF === "function" ? bpValOrF(theme) : bpValOrF; return bpVal ? [[key, bpVal]] : []; } } diff --git a/packages/yoshiki/src/native/index.tsx b/packages/yoshiki/src/native/index.tsx index a03e222..61970a8 100644 --- a/packages/yoshiki/src/native/index.tsx +++ b/packages/yoshiki/src/native/index.tsx @@ -27,6 +27,7 @@ export { breakpoints, useTheme } from "../theme"; export { useYoshiki } from "./generator"; export { Pressable } from "./hover"; export * from "./units"; +export { sm, md, lg, xl } from "./type"; export const ThemeProvider = ({ theme, children }: { theme: Theme; children?: ReactNode }) => { return {children}; diff --git a/packages/yoshiki/src/native/type.ts b/packages/yoshiki/src/native/type.ts index 07b3324..a59780b 100644 --- a/packages/yoshiki/src/native/type.ts +++ b/packages/yoshiki/src/native/type.ts @@ -6,6 +6,8 @@ import { FilterOr, WithState, YoshikiStyle, Length, StyleList } from "../type"; import { shorthandsFn } from "../shorthands"; import { ImageStyle, StyleProp, TextStyle, ViewStyle } from "react-native"; +import { Theme } from "../theme"; +import { forceBreakpoint, WithBreakpoints } from "../utils"; // The extends any check is only used to make EnhancedStyle a distributive type. // This means EnhancedStyle = EnhancedStyle | EnhancedStyle @@ -21,6 +23,21 @@ export type EnhancedStyle = Properties extends any } : never; +type ForcedBreakpointStyle = Properties extends any + ? { + [key in keyof Properties]: Properties[key] | ((theme: Theme) => Properties[key]); + } + : never; + +export const sm = (value: ForcedBreakpointStyle) => + forceBreakpoint(value, "sm"); +export const md = (value: ForcedBreakpointStyle) => + forceBreakpoint(value, "md"); +export const lg = (value: ForcedBreakpointStyle) => + forceBreakpoint(value, "lg"); +export const xl = (value: ForcedBreakpointStyle) => + forceBreakpoint(value, "xl"); + export type StyleFunc