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 @@
-
-
@@ -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==