diff --git a/.size-limit.js b/.size-limit.js index 67ed79d7..83b04fde 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -13,12 +13,12 @@ module.exports = [ }, { name: 'styled-breakpoints', - path: './styled-breakpoints/create-styled-breakpoints-theme/index.js', + path: './styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.js', import: '{ createStyledBreakpointsTheme }', limit: '900 B', }, { - name: 'styled-breakpoints + useMediaQuery', + name: 'useMediaQuery', path: './use-media-query/index.js', import: '{ useMediaQuery }', limit: '350 B', @@ -26,7 +26,8 @@ module.exports = [ { name: 'styled-breakpoints + useMediaQuery', import: { - './styled-breakpoints/index.js': '{ createStyledBreakpointsTheme }', + './styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.js': + '{ createStyledBreakpointsTheme }', './use-media-query/index.js': '{ useMediaQuery }', }, limit: '1.1 kB', diff --git a/README.md b/README.md index 4c90eb91..e4b2b06b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,3 @@ -
- - Open in Codeflow - -
-

@@ -45,8 +36,8 @@ styled-breakpoints

- -[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://stand-with-ukraine.pp.ua) +
+
# Breakpoints @@ -121,7 +112,6 @@ From largest to smallest - core concepts - available breakpoints - [quick start](#quick-start) -- migration from v11 - [media queries](#media-queries) - [min-width](#min-width) - [max-width](#max-width) @@ -129,8 +119,6 @@ From largest to smallest - [between breakpoints](#between-breakpoints) - [useMediaQuery hook](#usemediaquery-hook) - [customization](#customization) - - strict typed breakpoints - - merge with another theme
@@ -177,22 +165,49 @@ npm install styled-components styled-breakpoints@latest yarn add styled-components styled-breakpoints@latest ``` -`styled.d.ts` +
+ +#### Configuration + +`theme/index.tsx` + +```tsx +import { createStyledBreakpointsTheme } from 'styled-breakpoints'; +import styled { ThemeProvider as Provider } from 'styled-components'; + +export const theme = createStyledBreakpointsTheme(); + +type Props = { + children: React.ReactNode; +} + +export const ThemeProvider = ({children}: Props) => { + return {children} +} +``` + +
+ +`theme/styled.d.ts` ```ts import 'styled-components'; -import { StyledBreakpointsTheme } from 'styled-breakpoints'; +import { theme } from './theme'; + +type CustomTheme = typeof theme; declare module 'styled-components' { - export interface DefaultTheme extends StyledBreakpointsTheme {} + export interface DefaultTheme extends CustomTheme {} } ``` +
+ `app.tsx` ```tsx -import styled { DefaultTheme, ThemeProvider } from 'styled-components'; -import { createStyledBreakpointsTheme } from 'styled-breakpoints'; +import styled from 'styled-components'; +import { ThemeProvider } from './theme'; const Box = styled.div` display: none; @@ -200,14 +215,13 @@ const Box = styled.div` ${({ theme }) => theme.breakpoints.up('sm')} { display: block; } -` -const theme: DefaultTheme = createStyledBreakpointsTheme(); +`; const App = () => ( - - + + -) +); ``` @@ -226,23 +240,49 @@ npm install @emotion/{styled,react} styled-breakpoints@latest yarn add @emotion/{styled,react} styled-breakpoints@latest ``` -`emotion.d.ts` +
+ +#### Configuration + +`theme/index.tsx` + +```tsx +import { createStyledBreakpointsTheme } from 'styled-breakpoints'; +import { ThemeProvider as Provider } from '@emotion/react'; + +export const theme = createStyledBreakpointsTheme(); + +type Props = { + children: React.ReactNode; +}; + +export const ThemeProvider = ({ children }: Props) => { + return {children}; +}; +``` + +
+ +`theme/emotion.d.ts` ```ts import '@emotion/react'; -import { StyledBreakpointsTheme } from 'styled-breakpoints'; +import { theme } from './theme'; + +type CustomTheme = typeof theme; declare module '@emotion/react' { - export interface Theme extends StyledBreakpointsTheme {} + export interface Theme extends CustomTheme {} } ``` +
+ `app.tsx` ```tsx -import styled, from '@emotion/styled'; -import { Theme, ThemeProvider } from '@emotion/react'; -import { createStyledBreakpointsTheme } from 'styled-breakpoints'; +import styled from '@emotion/styled'; +import { ThemeProvider } from './theme'; const Box = styled.div` display: none; @@ -252,10 +292,8 @@ const Box = styled.div` } `; -const theme: Theme = createStyledBreakpointsTheme(); - const App = () => ( - + ); @@ -265,72 +303,6 @@ const App = () => (
-

🏎️  Migration from v11.2.3

- -### Theme - -The `createTheme` function has been replaced with `createStyledBreakpointsTheme`. - -```diff -- import { createTheme } from "styled-breakpoints"; - -- const theme = createTheme(); - - - -+ import { createStyledBreakpointsTheme } from "styled-breakpoints"; - -+ const theme = createStyledBreakpointsTheme(); -``` - -### Breakpoint Functions - -Additionally, the functions `up`, `down`, `between`, and `only` have been moved to the theme object. This means that you no longer need to import them individually each time you want to use them. - -```diff -- import { up } from "styled-breakpoints"; - -- const Box = styled.div` -- ${up('md')} { -- background-color: red; -- } - - -+ const Box = styled.div` -+ ${({ theme }) => theme.breakpoints.up('md')} { -+ background-color: red; -+ } -` -``` - -### Hooks - -```diff -- import { up } from 'styled-breakpoints'; -- import { useBreakpoint } from 'styled-breakpoints/react-styled'; - -or - -- import { up } from 'styled-breakpoints'; -- import { useBreakpoint } from 'styled-breakpoints/react-emotion'; - -- const Example = () => { -- const isMd = useBreakpoint(only('md')); -- -- return {isMd && } -- } - -+ import { useMediaQuery } from 'styled-breakpoints/use-media-query'; - -+ const Example = () => { -+ const isMd = useMediaQuery(useTheme()?.breakpoints.only('md')); -+ -+ return {isMd && } -+ } -``` - -
- ## Media queries - 🚀 Caching is implemented in all functions to optimize performance. @@ -496,7 +468,7 @@ features:
Type declaration ```ts - declare function useMediaQuery(query?: string) => boolean + declare function useMediaQuery(query: string) => boolean ```
@@ -507,7 +479,7 @@ import { useMediaQuery } from 'styled-breakpoints/use-media-query'; import { Box } from 'third-party-library'; const SomeComponent = () => { - const isMd = useMediaQuery(useTheme()?.breakpoints.only('md')); + const isMd = useMediaQuery(useTheme().breakpoints.only('md')); return {isMd && }; }; @@ -517,86 +489,11 @@ const SomeComponent = () => { ## Customization -

⚙️ Strict Typed Breakpoints

+

🎨 Merge with another theme

-`app.tsx` +`theme/index.tsx` ```tsx -import styled, { DefaultTheme } from 'styled-components'; // or from '@emotion/react' -import { createStyledBreakpointsTheme } from 'styled-breakpoints'; - -export const breakpoints = { - small: '0px', - medium: '640px', - large: '1024px', - xLarge: '1200px', - xxLarge: '1440px', -} as const; - -const theme: DefaultTheme = createStyledBreakpointsTheme({ - breakpoints, -}); - -const App = () => ( - - - -); -``` - -

💅 Styled Components

- -`styled.d.ts` - -```ts -import 'styled-components'; -import { MediaQueries } from 'styled-breakpoints'; -import { breakpoints } from './app'; - -type Min = keyof typeof breakpoints; - -// For max values remove the first key. -type Max = Exclude; - -declare module 'styled-components' { - export interface DefaultTheme { - breakpoints: MediaQueries; - } -} -``` - -
- -

👩‍🎤 Emotion

- -`emotion.d.ts` - -```ts -import '@emotion/react'; -import { MediaQueries } from 'styled-breakpoints'; -import { breakpoints } from './app'; - -type Min = keyof typeof breakpoints; - -// For max values remove the first key. -type Max = Exclude; - -declare module '@emotion/react' { - export interface Theme extends { - breakpoints: MediaQueries; - } -} -``` - -
-
- -

🎨 Merge with another theme

- -`app.tsx` - -```tsx -import { DefaultTheme, ThemeProvider } from 'styled-components'; // or from '@emotion/react'; import { createStyledBreakpointsTheme } from 'styled-breakpoints'; export const primaryTheme = { @@ -608,55 +505,13 @@ export const primaryTheme = { }, } as const; -const const theme: DefaultTheme = { +export const theme = { ...primaryTheme, ...createStyledBreakpointsTheme(), -} - -const App = () => ( - - - -); -``` - -

💅 Styled Components

- -`styled.d.ts` - -```ts -import 'styled-components'; -import { StyledBreakpointsTheme } from 'styled-breakpoints'; -import { primaryTheme } from './app'; - -type PrimaryTheme = typeof primaryTheme; - -declare module 'styled-components' { - export interface DefaultTheme extends StyledBreakpointsTheme, PrimaryTheme {} -} -``` - -
- -

👩‍🎤 Emotion

- -`emotion.d.ts` - -```ts -import '@emotion/react'; -import { StyledBreakpointsTheme } from 'styled-breakpoints'; -import { primaryTheme } from './app'; - -type PrimaryTheme = typeof primaryTheme; - -declare module '@emotion/react' { - export interface Theme extends PrimaryTheme, StyledBreakpointsTheme {} -} +} as const; ``` -
- -
+
## License diff --git a/index.js b/index.js deleted file mode 100644 index 86383195..00000000 --- a/index.js +++ /dev/null @@ -1,2 +0,0 @@ -exports.createStyledBreakpointsTheme = - require('./styled-breakpoints/create-styled-breakpoints-theme').createStyledBreakpointsTheme; diff --git a/package.json b/package.json index d1a91a02..3f7c8f82 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "name": "styled-breakpoints", "version": "12.1.10", "description": "Simple and powerful css breakpoints for styled-components and emotion", - "main": "index.js", - "types": "index.d.ts", + "main": "./styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.js", + "types": "./styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.d.ts", "sideEffects": false, "scripts": { "commit": "cross-env git-cz", @@ -91,6 +91,7 @@ "prettier": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "semantic-release-githubsquash": "^0.2.12", "size-limit": "^11.0.2", "vitest": "^1.0.1" } diff --git a/shared/create-breakpoints-api/create-breakpoints-api.dev.js b/shared/create-breakpoints-api/create-breakpoints-api.dev.js index 59b49200..4feb31e9 100644 --- a/shared/create-breakpoints-api/create-breakpoints-api.dev.js +++ b/shared/create-breakpoints-api/create-breakpoints-api.dev.js @@ -1,16 +1,11 @@ const { createBreakpointsApi } = require('./create-breakpoints-api.prod'); const { createInvariant } = require('../create-invariant'); -/** - * Creates an object with breakpoints. - * @param {Object} options - The options for creating the theme. - * @param {Object} options.breakpoints - An object defining breakpoints. - * @param {String} options.errorPrefix - The error prefix for validation. - * @returns {Object} - An object with breakpoint functions. - */ -exports.createBreakpointsApi = ({ breakpoints, errorPrefix }) => { - // Create an object for input validation - const invariant = createInvariant(errorPrefix); +const DEFAULT_ERROR_PREFIX = '[breakpoints]: '; +exports.DEFAULT_ERROR_PREFIX = DEFAULT_ERROR_PREFIX; + +exports.createBreakpointsApi = ({ breakpoints, errorPrefix } = {}) => { + const invariant = createInvariant(errorPrefix || DEFAULT_ERROR_PREFIX); const validation = createValidation({ invariant, breakpoints, @@ -18,27 +13,16 @@ exports.createBreakpointsApi = ({ breakpoints, errorPrefix }) => { validation.validateBreakpoints(); - // Create a breakpoints API const api = createBreakpointsApi({ breakpoints, }); - /** - * Get the minimum breakpoint value. - * @param {string} min - The breakpoint key. - * @returns {string} - The minimum breakpoint value. - */ const up = (min) => { validation.validateKey(min); return api.up(min); }; - /** - * Get the maximum breakpoint value using calcMaxWidth. - * @param {string} max - The breakpoint key. - * @returns {string} - The maximum breakpoint value. - */ const down = (max) => { validation.validateKey(max); validation.validateNonZeroValue(max); @@ -46,12 +30,6 @@ exports.createBreakpointsApi = ({ breakpoints, errorPrefix }) => { return api.down(max); }; - /** - * Get a range between two breakpoints. - * @param {string} min - The minimum breakpoint key. - * @param {string} max - The maximum breakpoint key. - * @returns {Object} - An object with 'min' and 'max' properties containing the corresponding breakpoint values. - */ const between = (min, max) => { validation.validateKey(min); validation.validateKey(max); @@ -60,11 +38,6 @@ exports.createBreakpointsApi = ({ breakpoints, errorPrefix }) => { return api.between(min, max); }; - /** - * Get a range based on a single breakpoint key. - * @param {string} key - The breakpoint key. - * @returns {string|Object} - The minimum or a range object based on the provided key. - */ const only = (key) => { validation.validateKey(key); @@ -94,6 +67,7 @@ function createValidation({ invariant, breakpoints }) { function validateBreakpoints() { const VALID_PATTERN = /^\d+px$/; + const invalidBreakpoints = keys.reduce((acc, key) => { // Check the validity of breakpoint values if (!VALID_PATTERN.test(breakpoints[key].trim())) { @@ -113,17 +87,16 @@ function createValidation({ invariant, breakpoints }) { } function validateKey(key) { - // Check if the specified breakpoint exists invariant( breakpoints[key], - `breakpoint \`${key}\` not found in ${keys.join(', ')}.` + `Breakpoint \`${key}\` not found in ${keys.join(', ')}.` ); } + // Check that a breakpoint is not equal to 0. function validateNonZeroValue(key) { const value = breakpoints[key]; - // Check that the breakpoint is not 0 invariant( removeUnits(value) !== 0, `\`${key}: ${value}\` cannot be assigned as minimum breakpoint.` @@ -133,11 +106,10 @@ function createValidation({ invariant, breakpoints }) { function validateMaxIsGreaterOrEqualToMin(min, max) { const diff = removeUnits(breakpoints[max]) - removeUnits(breakpoints[min]); - // Check that `max` is greater than or equal to `min` invariant(diff >= 0, 'The `max` value cannot be less than the `min`.'); } } function removeUnits(value) { - return parseInt(value, 10); + return parseInt(value, 10) || 0; } diff --git a/shared/create-breakpoints-api/create-breakpoints-api.dev.spec.js b/shared/create-breakpoints-api/create-breakpoints-api.dev.spec.js index 4db3bdc8..0b176dc9 100644 --- a/shared/create-breakpoints-api/create-breakpoints-api.dev.spec.js +++ b/shared/create-breakpoints-api/create-breakpoints-api.dev.spec.js @@ -1,4 +1,4 @@ -import { describe, beforeAll, vi, beforeEach, it, expect } from 'vitest'; +import { describe, beforeAll, vi, it, expect } from 'vitest'; import { DEFAULT_BREAKPOINTS } from '../constants'; describe('createBreakpointsApi', () => { @@ -15,9 +15,11 @@ describe('createBreakpointsApi', () => { vi.resetModules(); process.env.NODE_ENV = 'development'; + breakpointsApi = require('.').createBreakpointsApi; + ERROR_PREFIX = '[breakpoints]: '; INVALID_BREAKPOINT_KEY = 'invalid'; - EXPECTED_ERROR_MESSAGE_FOR_INVALID_KEY = `${ERROR_PREFIX}breakpoint \`${INVALID_BREAKPOINT_KEY}\` not found in ${Object.keys( + EXPECTED_ERROR_MESSAGE_FOR_INVALID_KEY = `${ERROR_PREFIX}Breakpoint \`${INVALID_BREAKPOINT_KEY}\` not found in ${Object.keys( DEFAULT_BREAKPOINTS ).join(', ')}.`; @@ -26,11 +28,6 @@ describe('createBreakpointsApi', () => { describe('development environment', () => { describe('breakpoints validation', () => { - // Arrange - beforeEach(() => { - breakpointsApi = require('.').createBreakpointsApi; - }); - it('does not throw an error if all breakpoints are valid', () => { // Act const received = () => diff --git a/styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.d.ts b/styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.d.ts index 20caa807..ba13705c 100644 --- a/styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.d.ts +++ b/styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.d.ts @@ -1,24 +1,65 @@ -export type Orientation = 'portrait' | 'landscape'; +type UnionToIntersection = ( + U extends unknown ? (arg: U) => 0 : never +) extends (arg: infer I) => 0 + ? I + : never; -type BreakpointKeys = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; -type Min = BreakpointKeys; +/** + * LastInUnion<1 | 2> = 2. + */ +type LastInUnion = + UnionToIntersection 0 : never> extends ( + x: infer L + ) => 0 + ? L + : never; -type Max = Exclude; +/** + * UnionToTuple<1 | 2> = [1, 2]. + */ +export type UnionToTuple> = [U] extends [never] + ? [] + : [...UnionToTuple>, Last]; -interface Options { - breakpoints?: Record; - errorPrefix?: string; -} +type HeadlessTuple = T extends [infer _, ...infer Tail] + ? Tail + : never; -export interface MediaQueries { - up: (min: T, orientation?: Orientation) => string; - down: (max: U, orientation?: Orientation) => string; - between: (min: T, max: U, orientation?: Orientation) => string; - only: (key: T, orientation?: Orientation) => string; -} +export type OmitFirst = HeadlessTuple>[number]; + +export type Breakpoints = Record; +export type ErrorPrefix = `[${string}]: `; + +export type Orientation = 'portrait' | 'landscape'; + +declare const DEFAULT_BREAKPOINTS: { + readonly xs: '0px'; + readonly sm: '576px'; + readonly md: '768px'; + readonly lg: '992px'; + readonly xl: '1200px'; + readonly xxl: '1400px'; +}; + +type DefaultBreakpoints = typeof DEFAULT_BREAKPOINTS; +type DefaultBreakpointKeys = keyof DefaultBreakpoints; + +export type Options = { + breakpoints?: T; + errorPrefix?: ErrorPrefix; +}; -export interface StyledBreakpointsTheme { - breakpoints: T; +interface StyledBreakpointsTheme { + breakpoints: { + up(min: Min, orientation?: Orientation): string; + down(max: Max, orientation?: Orientation): string; + between(min: Min, max: Max, orientation?: Orientation): string; + only(key: Min, orientation?: Orientation): string; + }; } -export function createStyledBreakpointsTheme(options?: Options): any; +export function createStyledBreakpointsTheme< + T extends Breakpoints = DefaultBreakpoints, + Keys extends keyof T = DefaultBreakpointKeys, + KeysWithoutFirst extends OmitFirst = OmitFirst, +>(options?: Options): StyledBreakpointsTheme; diff --git a/styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.js b/styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.js index 3954b07a..af2cca56 100644 --- a/styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.js +++ b/styled-breakpoints/create-styled-breakpoints-theme/create-styled-breakpoints-theme.js @@ -40,13 +40,7 @@ exports.createStyledBreakpointsTheme = ({ }, }; - /** - * Creates a media query for a minimum width breakpoint. - * - * @param {String} min - The minimum breakpoint value. - * @param {String} orientation - Optional orientation value. - * @returns {String} - The media query string. - */ + // Creates a media query for a minimum width breakpoint. function up(min, orientation) { return withOrientationOrNot( withMedia(withMinWidth(api.up(min))), @@ -54,13 +48,7 @@ exports.createStyledBreakpointsTheme = ({ ); } - /** - * Creates a media query for a maximum width breakpoint. - * - * @param {String} max - The maximum breakpoint value. - * @param {String} orientation - Optional orientation value. - * @returns {String} - The media query string. - */ + // Creates a media query for a maximum width breakpoint. function down(max, orientation) { return withOrientationOrNot( withMedia(withMaxWidth(api.down(max))), @@ -68,44 +56,26 @@ exports.createStyledBreakpointsTheme = ({ ); } - /** - * Creates a media query for a range between two breakpoints. - * - * @param {String} min - The minimum breakpoint value. - * @param {String} max - The maximum breakpoint value. - * @param {String} orientation - Optional orientation value. - * @returns {String} - The media query string. - */ + // Creates a media query for a range between two breakpoints. function between(min, max, orientation) { return withOrientationOrNot( - withMinAndMaxMedia(api.between(min, max)), + withRangeMedia(api.between(min, max)), orientation ); } - /** - * Creates a media query for a specific breakpoint or range. - * - * @param {String} key - The breakpoint key. - * @param {String} orientation - Optional orientation value. - * @returns {String} - The media query string. - */ + // Creates a media query for a specific breakpoint or range. function only(key, orientation) { - const mediaQuery = - key === api.keys.at(-1) - ? withMedia(withMinWidth(api.up(key))) - : withMinAndMaxMedia(api.between(key, api.getNextKey(key))); + const isLastKey = key === api.keys.at(-1); + + const mediaQuery = isLastKey + ? withMedia(withMinWidth(api.up(key))) + : withRangeMedia(api.between(key, api.getNextKey(key))); return withOrientationOrNot(mediaQuery, orientation); } - /** - * Applies orientation if provided or returns the media query. - * - * @param {String} orientation - Optional orientation value. - * @param {String} mediaQuery - The media query string. - * @returns {String} - The media query with or without orientation. - */ + // Applies orientation if provided or returns the media query. function withOrientationOrNot(mediaQuery, orientation) { return orientation ? withOrientation({ @@ -115,40 +85,20 @@ exports.createStyledBreakpointsTheme = ({ }) : mediaQuery; } +}; - /** - * @param {String} value - The minimum width value. - * @returns {String} - The media query string. - */ - function withMinWidth(value) { - return `(min-width: ${value})`; - } +function withMinWidth(value) { + return `(min-width: ${value})`; +} - /** - * @param {String} value - The media query string. - * @returns {String} - The media query wrapped with '@media'. - */ - function withMedia(value) { - return `@media ${value}`; - } +function withMedia(value) { + return `@media ${value}`; +} - /** - * @param {String} value - The maximum width value. - * @returns {String} - The media query string. - */ - function withMaxWidth(value) { - return `(max-width: ${value})`; - } +function withMaxWidth(value) { + return `(max-width: ${value})`; +} - /** - * Creates a media query string for a range between minimum and maximum widths. - * - * @param {Object} options - The range options with minimum and maximum values. - * @param {String} options.min - The minimum width value. - * @param {String} options.max - The maximum width value. - * @returns {String} - The media query string for the range. - */ - function withMinAndMaxMedia({ min, max }) { - return `${withMedia(withMinWidth(min))} and ${withMaxWidth(max)}`; - } -}; +function withRangeMedia({ min, max }) { + return `${withMedia(withMinWidth(min))} and ${withMaxWidth(max)}`; +} diff --git a/styled-breakpoints/index.d.ts b/styled-breakpoints/index.d.ts deleted file mode 100644 index 752b22d2..00000000 --- a/styled-breakpoints/index.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { - createStyledBreakpointsTheme, - StyledBreakpointsTheme, - MediaQueries, -} from './create-styled-breakpoints-theme/create-styled-breakpoints-theme'; diff --git a/styled-breakpoints/index.js b/styled-breakpoints/index.js deleted file mode 100644 index d1712f34..00000000 --- a/styled-breakpoints/index.js +++ /dev/null @@ -1,2 +0,0 @@ -exports.createStyledBreakpointsTheme = - require('./create-styled-breakpoints-theme').createStyledBreakpointsTheme; diff --git a/use-media-query/index.d.ts b/use-media-query/index.d.ts index 845a4653..87ea1e1f 100644 --- a/use-media-query/index.d.ts +++ b/use-media-query/index.d.ts @@ -1,3 +1 @@ -declare module 'styled-breakpoints/use-media-query' { - export function useMediaQuery(query?: string): boolean; -} +export function useMediaQuery(query: string): boolean; diff --git a/use-media-query/use-media-query.js b/use-media-query/use-media-query.js index cff91561..ee91772a 100644 --- a/use-media-query/use-media-query.js +++ b/use-media-query/use-media-query.js @@ -3,16 +3,20 @@ const { useState, useLayoutEffect, useEffect } = require('react'); const isBrowser = typeof window !== 'undefined'; const useEnhancedEffect = isBrowser ? useLayoutEffect : useEffect; +exports.useMediaQuery = useMediaQuery; + /** * Custom hook for handling media queries. * - * @param {string} [query=''] - The media query to match. + * @param {string} query - The media query to match. * @returns {boolean} - `true` if the media query matches, otherwise `false`. */ -const useMediaQuery = (query = '') => { - const [isMatch, setIsMatch] = useState(getMatches(query)); +function useMediaQuery(query) { + const [isMatch, setIsMatch] = useState(isBrowser && getMatches(query)); useEnhancedEffect(() => { + if (!isBrowser) return; + let mounted = true; const mediaQueryList = window.matchMedia(query.replace(/^@media\s*/, '')); @@ -24,14 +28,14 @@ const useMediaQuery = (query = '') => { // Safari < 14 can't use addEventListener on a MediaQueryList // https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList#Browser_compatibility - if (mediaQueryList.addListener) { - mediaQueryList.addListener(handleChange); - } else { - mediaQueryList.addEventListener('change', handleChange); - } + const listenerMethod = mediaQueryList.addListener + ? 'addListener' + : 'addEventListener'; + mediaQueryList[listenerMethod]('change', handleChange); setIsMatch(mediaQueryList.matches); + // eslint-disable-next-line consistent-return return () => { mounted = false; @@ -44,15 +48,8 @@ const useMediaQuery = (query = '') => { }, [query]); return isMatch; -}; - -exports.useMediaQuery = useMediaQuery; +} function getMatches(query) { - // Prevents SSR issues - if (typeof window !== 'undefined') { - return window.matchMedia(query).matches; - } - - return false; + return window.matchMedia(query).matches; } diff --git a/yarn.lock b/yarn.lock index 0a880948..52bc369b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1033,6 +1033,19 @@ lodash-es "^4.17.21" micromatch "^4.0.2" +"@semantic-release/commit-analyzer@^9.0.2": + version "9.0.2" + resolved "https://registry.yarnpkg.com/@semantic-release/commit-analyzer/-/commit-analyzer-9.0.2.tgz#a78e54f9834193b55f1073fa6258eecc9a545e03" + integrity sha512-E+dr6L+xIHZkX4zNMe6Rnwg4YQrWNXK+rNsvwOPpdFppvZO1olE2fIgWhv89TkQErygevbjsZFSIxp+u6w2e5g== + dependencies: + conventional-changelog-angular "^5.0.0" + conventional-commits-filter "^2.0.0" + conventional-commits-parser "^3.2.3" + debug "^4.0.0" + import-from "^4.0.0" + lodash "^4.17.4" + micromatch "^4.0.2" + "@semantic-release/error@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@semantic-release/error/-/error-3.0.0.tgz#30a3b97bbb5844d695eb22f9d3aa40f6a92770c2" @@ -1098,6 +1111,22 @@ semver "^7.1.2" tempy "^3.0.0" +"@semantic-release/release-notes-generator@^10.0.3": + version "10.0.3" + resolved "https://registry.yarnpkg.com/@semantic-release/release-notes-generator/-/release-notes-generator-10.0.3.tgz#85f7ca78bfa6b01fb5fda0ac48112855d69171dc" + integrity sha512-k4x4VhIKneOWoBGHkx0qZogNjCldLPRiAjnIpMnlUh6PtaWXp/T+C9U7/TaNDDtgDa5HMbHl4WlREdxHio6/3w== + dependencies: + conventional-changelog-angular "^5.0.0" + conventional-changelog-writer "^5.0.0" + conventional-commits-filter "^2.0.0" + conventional-commits-parser "^3.2.3" + debug "^4.0.0" + get-stream "^6.0.0" + import-from "^4.0.0" + into-stream "^6.0.0" + lodash "^4.17.4" + read-pkg-up "^7.0.0" + "@semantic-release/release-notes-generator@^12.0.0": version "12.1.0" resolved "https://registry.yarnpkg.com/@semantic-release/release-notes-generator/-/release-notes-generator-12.1.0.tgz#7fbe501188c7960db412b96a97c3d6cfb5788d12" @@ -1567,7 +1596,7 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -JSONStream@^1.3.5: +JSONStream@^1.0.4, JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== @@ -2430,6 +2459,14 @@ console-control-strings@^1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== +conventional-changelog-angular@^5.0.0: + version "5.0.13" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" + integrity sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA== + dependencies: + compare-func "^2.0.0" + q "^1.5.1" + conventional-changelog-angular@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz#5eec8edbff15aa9b1680a8dcfbd53e2d7eb2ba7a" @@ -2444,6 +2481,21 @@ conventional-changelog-conventionalcommits@^7.0.2: dependencies: compare-func "^2.0.0" +conventional-changelog-writer@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz#e0757072f045fe03d91da6343c843029e702f359" + integrity sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ== + dependencies: + conventional-commits-filter "^2.0.7" + dateformat "^3.0.0" + handlebars "^4.7.7" + json-stringify-safe "^5.0.1" + lodash "^4.17.15" + meow "^8.0.0" + semver "^6.0.0" + split "^1.0.0" + through2 "^4.0.0" + conventional-changelog-writer@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-7.0.1.tgz#e64ef74fa8e773cab4124af217f3f02b29eb0a9c" @@ -2461,11 +2513,31 @@ conventional-commit-types@^3.0.0: resolved "https://registry.yarnpkg.com/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz#7c9214e58eae93e85dd66dbfbafe7e4fffa2365b" integrity sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg== +conventional-commits-filter@^2.0.0, conventional-commits-filter@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3" + integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA== + dependencies: + lodash.ismatch "^4.4.0" + modify-values "^1.0.0" + conventional-commits-filter@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-4.0.0.tgz#845d713e48dc7d1520b84ec182e2773c10c7bf7f" integrity sha512-rnpnibcSOdFcdclpFwWa+pPlZJhXE7l+XK04zxhbWrhgpR96h33QLz8hITTXbcYICxVr3HZFtbtUAQ+4LdBo9A== +conventional-commits-parser@^3.2.3: + version "3.2.4" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz#a7d3b77758a202a9b2293d2112a8d8052c740972" + integrity sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q== + dependencies: + JSONStream "^1.0.4" + is-text-path "^1.0.1" + lodash "^4.17.15" + meow "^8.0.0" + split2 "^3.0.0" + through2 "^4.0.0" + conventional-commits-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz#57f3594b81ad54d40c1b4280f04554df28627d9a" @@ -2603,6 +2675,11 @@ data-urls@^5.0.0: whatwg-mimetype "^4.0.0" whatwg-url "^14.0.0" +dateformat@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" + integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== + debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -4043,6 +4120,11 @@ import-from-esm@^1.0.3: dependencies: import-meta-resolve "^4.0.0" +import-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-4.0.0.tgz#2710b8d66817d232e16f4166e319248d3d5492e2" + integrity sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ== + import-meta-resolve@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz#0b1195915689f60ab00f830af0f15cc841e8919e" @@ -4153,6 +4235,14 @@ internal-slot@^1.0.4, internal-slot@^1.0.5: hasown "^2.0.0" side-channel "^1.0.4" +into-stream@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-6.0.0.tgz#4bfc1244c0128224e18b8870e85b2de8e66c6702" + integrity sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA== + dependencies: + from2 "^2.3.0" + p-is-promise "^3.0.0" + into-stream@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-7.0.0.tgz#d1a211e146be8acfdb84dabcbf00fe8205e72936" @@ -4409,6 +4499,13 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" +is-text-path@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" + integrity sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w== + dependencies: + text-extensions "^1.0.0" + is-text-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-2.0.0.tgz#b2484e2b720a633feb2e85b67dc193ff72c75636" @@ -4994,6 +5091,11 @@ lodash.isfunction@^3.0.9: resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== +lodash.ismatch@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" + integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g== + lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" @@ -5370,6 +5472,11 @@ mlly@^1.2.0, mlly@^1.4.2: pkg-types "^1.0.3" ufo "^1.3.0" +modify-values@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" + integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -6190,6 +6297,11 @@ punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +q@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== + qrcode-terminal@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819" @@ -6294,7 +6406,7 @@ read-pkg-up@^11.0.0: read-pkg "^9.0.0" type-fest "^4.6.0" -read-pkg-up@^7.0.1: +read-pkg-up@^7.0.0, read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== @@ -6652,6 +6764,14 @@ schema-utils@^3.1.1, schema-utils@^3.2.0: ajv "^6.12.5" ajv-keywords "^3.5.2" +semantic-release-githubsquash@^0.2.12: + version "0.2.12" + resolved "https://registry.yarnpkg.com/semantic-release-githubsquash/-/semantic-release-githubsquash-0.2.12.tgz#bec3288ea81abe304e754a9d6ad1169fdcc9ad0d" + integrity sha512-onS95balQ+R9bscudG5UbRtAxlnOkxMtjUZa4Dm1UWZmAtHmnuCFJLIEsT/b7N3GE6ogv3Vl04nlR1hX6xTMOg== + dependencies: + "@semantic-release/commit-analyzer" "^9.0.2" + "@semantic-release/release-notes-generator" "^10.0.3" + "semver@2 || 3 || 4 || 5": version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" @@ -6664,7 +6784,7 @@ semver@7.5.4, semver@^7.0.0, semver@^7.1.1, semver@^7.1.2, semver@^7.3.4, semver dependencies: lru-cache "^6.0.0" -semver@^6.3.0, semver@^6.3.1: +semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -6862,6 +6982,13 @@ split2@^4.0.0: resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== +split@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -7158,6 +7285,11 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +text-extensions@^1.0.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" + integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== + text-extensions@^2.0.0: version "2.4.0" resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-2.4.0.tgz#a1cfcc50cf34da41bfd047cc744f804d1680ea34" @@ -7175,7 +7307,7 @@ through2@^4.0.0: dependencies: readable-stream "3" -"through@>=2.2.7 <3", through@^2.3.6: +through@2, "through@>=2.2.7 <3", through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==