From 5a3daa7abe6b8b4f92cd2db79dcb6cd7def7c7ab Mon Sep 17 00:00:00 2001 From: Griko Nibras Date: Mon, 22 Nov 2021 10:34:40 +0700 Subject: [PATCH] feat: simplify resolving breakpoint input Signed-off-by: Griko Nibras --- README.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++---- src/index.ts | 13 ++++++------ 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 7b2e019..d94390b 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ Custom hooks to use Tailwind CSS breakpoints for React 🎐🔨 - [Installing](#installing) - [Usage](#usage) + - [Option #1: Resolve directly from `tailwind.config.js`](#option-1-resolve-directly-from-tailwindconfigjs) + - [Option #2: Only pass breakpoint values](#option-2-only-pass-breakpoint-values) - [Available hooks](#available-hooks) - [`useBreakpoint()`](#usebreakpoint) - [`useBreakpointEffect()`](#usebreakpointeffect) @@ -36,13 +38,59 @@ yarn add @kodingdotninja/use-tailwind-breakpoint ## Usage -[Similar to `pmndrs/zustand`'s `create` API](https://github.com/pmndrs/zustand/#first-create-a-store), create the breakpoint hooks by resolving your `tailwind.config.js`: +### Option #1: Resolve directly from `tailwind.config.js` + +[Similar to `pmndrs/zustand`'s `create` API](https://github.com/pmndrs/zustand/#first-create-a-store), initialize the breakpoint hooks by passing the `tailwind.config.js` which will be resolved internally using [`resolveConfig`](https://github.com/tailwindlabs/tailwindcss/blob/master/src/util/resolveConfig.js): + +```ts +// /hooks/tailwind.ts + +import create from "@kodingdotninja/use-tailwind-breakpoint"; + +import tailwindConfig from "path/to/tailwind.config.js"; + +export const { useBreakpoint } = create(tailwindConfig); +``` + +> ⚠️ This possibly imports all `tailwind.config.js` values. Make sure to check the client bundle size. + +### Option #2: Only pass breakpoint values + +Extract the [`screens`](https://tailwindcss.com/docs/breakpoints) values into a separate file: + +```js +// tailwind.screens.js or other name to separate breakpoint values +const screens = { + sm: "640px", + md: "768px", + // ... +}; +``` + +To keep the same values, `require` inside `tailwind.config.js`: + +```js +// tailwind.config.js +module.exports = { + theme: { + extend: { + screens: require("path/to/tailwind.screens.js"), + }, + }, + // ... +}; +``` + +Then pass the extracted `screens` to the `create` function: ```ts +// /hooks/tailwind.ts + import create from "@kodingdotninja/use-tailwind-breakpoint"; -import tailwindConfig from "path/to/tailwind.config"; -export const { useBreakpoint, ... } = create(tailwindConfig); +import tailwindScreens from "path/to/tailwind.screens.js"; + +export const { useBreakpoint } = create(screens); ``` ## Available hooks @@ -52,7 +100,7 @@ export const { useBreakpoint, ... } = create(tailwindConfig); Use breakpoint value from given breakpoint token ```jsx -import { useBreakpoint } from "@kodingdotninja/use-tailwind-breakpoint"; +import { useBreakpoint } from "./lib/"; function App() { const isDesktop = useBreakpoint("md"); diff --git a/src/index.ts b/src/index.ts index 484543b..bb1394d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,8 @@ import { TailwindConfig } from "tailwindcss/tailwind-config"; export * from "./utils"; +export type Breakpoints = { readonly [breakpoint: string]: string }; + export type CreatorReturnType = { /** * Use breakpoint value from given breakpoint token @@ -75,7 +77,7 @@ export type CreatorReturnType = { * * --- * - * @param configFile Tailwind CSS configuration file (`tailwind.config.js`) + * @param configOrScreens Tailwind CSS configuration file (`tailwind.config.js`) * * @returns Breakpoint hooks * @@ -90,10 +92,10 @@ export type CreatorReturnType = { * export const { useBreakpoint, useBreakpointEffect, useBreakpointValue, ... } = create(tailwindConfig); * ``` */ -export function create(configFile: Config) { - const config = resolveConfig(configFile); +export function create(configOrScreens: ConfigOrScreens) { + const screens = (resolveConfig(configOrScreens as TailwindConfig).theme.screens ?? configOrScreens) as Breakpoints; - function useBreakpoint(breakpoint: Breakpoint, defaultValue: boolean = false) { + function useBreakpoint(breakpoint: string, defaultValue: boolean = false) { const [match, setMatch] = React.useState(() => defaultValue); const matchRef = React.useRef(defaultValue); @@ -101,8 +103,7 @@ export function create(configFile: Config) { if (!(isBrowser && "matchMedia" in window)) return undefined; function track() { - // @ts-expect-error tsconfig.compilerOptions.strict prevents accessing index with unknown value type - const value = (config.theme.screens?.[breakpoint] as string) ?? "999999px"; + const value = screens?.[breakpoint] ?? "999999px"; const query = window.matchMedia(`(min-width: ${value})`); matchRef.current = query.matches; if (matchRef.current != match) {