Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

breakpoint-utils

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

breakpoint-utils - npm Package Compare versions

Comparing version
1.0.0
to
2.0.0
+7
dist/useBreakpoint.d.ts
import { type BreakpointValue } from './breakpoints';
export declare const useUp: (size: BreakpointValue) => boolean;
export declare const useDown: (size: BreakpointValue) => boolean;
export declare const useOnly: (size: string) => boolean;
export declare const useNot: (size: string) => boolean;
export declare const useBetween: (minSize: BreakpointValue, maxSize: BreakpointValue) => boolean;
//# sourceMappingURL=useBreakpoint.d.ts.map
{"version":3,"file":"useBreakpoint.d.ts","sourceRoot":"","sources":["../src/useBreakpoint.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AA0BvB,eAAO,MAAM,KAAK,GAAI,MAAM,eAAe,KAAG,OAA4C,CAAC;AAC3F,eAAO,MAAM,OAAO,GAAI,MAAM,eAAe,KAAG,OAA8C,CAAC;AAC/F,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,KAAG,OAA8C,CAAC;AACtF,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,KAAG,OAA6C,CAAC;AACpF,eAAO,MAAM,UAAU,GAAI,SAAS,eAAe,EAAE,SAAS,eAAe,KAAG,OAA6D,CAAC"}
import { useCallback, useMemo, useSyncExternalStore } from 'react';
import { buildUpQuery, buildDownQuery, buildOnlyQuery, buildNotQuery, buildBetweenQuery, } from './breakpoints';
const useMediaQuery = (query) => {
const mql = useMemo(() => typeof window !== 'undefined' ? window.matchMedia(query) : null, [query]);
const subscribe = useCallback((callback) => {
if (!mql)
return () => { };
mql.addEventListener('change', callback);
return () => mql.removeEventListener('change', callback);
}, [mql]);
const getSnapshot = useCallback(() => {
var _a;
return (_a = mql === null || mql === void 0 ? void 0 : mql.matches) !== null && _a !== void 0 ? _a : false;
}, [mql]);
const getServerSnapshot = useCallback(() => false, []);
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
};
export const useUp = (size) => useMediaQuery(buildUpQuery(size));
export const useDown = (size) => useMediaQuery(buildDownQuery(size));
export const useOnly = (size) => useMediaQuery(buildOnlyQuery(size));
export const useNot = (size) => useMediaQuery(buildNotQuery(size));
export const useBetween = (minSize, maxSize) => useMediaQuery(buildBetweenQuery(minSize, maxSize));
//# sourceMappingURL=useBreakpoint.js.map
{"version":3,"file":"useBreakpoint.js","sourceRoot":"","sources":["../src/useBreakpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AACnE,OAAO,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,iBAAiB,GAElB,MAAM,eAAe,CAAC;AAEvB,MAAM,aAAa,GAAG,CAAC,KAAa,EAAW,EAAE;IAC/C,MAAM,GAAG,GAAG,OAAO,CACjB,GAAG,EAAE,CAAC,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EACrE,CAAC,KAAK,CAAC,CACR,CAAC;IAEF,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,QAAoB,EAAE,EAAE;QACvB,IAAI,CAAC,GAAG;YAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;QAC1B,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACzC,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC3D,CAAC,EACD,CAAC,GAAG,CAAC,CACN,CAAC;IAEF,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;;QACnC,OAAO,MAAA,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,OAAO,mCAAI,KAAK,CAAC;IAC/B,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEV,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAEvD,OAAO,oBAAoB,CAAC,SAAS,EAAE,WAAW,EAAE,iBAAiB,CAAC,CAAC;AACzE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,IAAqB,EAAW,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3F,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAqB,EAAW,EAAE,CAAC,aAAa,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/F,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,aAAa,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;AACtF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AACpF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAwB,EAAE,OAAwB,EAAW,EAAE,CAAC,aAAa,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC"}
+17
-3
export type Breakpoints = Record<string, number>;
export type BreakpointValue = string | number;
/**
* Set custom breakpoints. Call this at app startup before any components mount.
* Calling after mount will not update active hook subscriptions until the next re-render.
*/
export declare const configure: <T extends Breakpoints>(customBreakpoints: T) => void;
export declare const getBreakpoints: () => Breakpoints;
export declare const up: (size: string) => boolean;
export declare const down: (size: string) => boolean;
/**
* @internal Query builders - used by hook layer, not part of public API
*/
declare const buildUpQuery: (size: BreakpointValue) => string;
declare const buildDownQuery: (size: BreakpointValue) => string;
declare const buildOnlyQuery: (size: string) => string;
declare const buildNotQuery: (size: string) => string;
declare const buildBetweenQuery: (minSize: BreakpointValue, maxSize: BreakpointValue) => string;
export declare const up: (size: BreakpointValue) => boolean;
export declare const down: (size: BreakpointValue) => boolean;
export declare const only: (size: string) => boolean;
export declare const not: (size: string) => boolean;
export declare const between: (minSize: string, maxSize: string) => boolean;
export declare const between: (minSize: BreakpointValue, maxSize: BreakpointValue) => boolean;
export { buildUpQuery, buildDownQuery, buildOnlyQuery, buildNotQuery, buildBetweenQuery };
//# sourceMappingURL=breakpoints.d.ts.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"breakpoints.d.ts","sourceRoot":"","sources":["../src/breakpoints.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAWjD,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,WAAW,EAAE,mBAAmB,CAAC,SAGpE,CAAC;AAEF,eAAO,MAAM,cAAc,mBAA2B,CAAC;AAcvD,eAAO,MAAM,EAAE,GAAI,MAAM,MAAM,YAG9B,CAAC;AAEF,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,YAGhC,CAAC;AAEF,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,YAMhC,CAAC;AAEF,eAAO,MAAM,GAAG,GAAI,MAAM,MAAM,YAM/B,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,EAAE,SAAS,MAAM,YAOvD,CAAC"}
{"version":3,"file":"breakpoints.d.ts","sourceRoot":"","sources":["../src/breakpoints.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACjD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AAW9C;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,WAAW,EAAE,mBAAmB,CAAC,SAGpE,CAAC;AAEF,eAAO,MAAM,cAAc,mBAA2B,CAAC;AAoBvD;;GAEG;AACH,QAAA,MAAM,YAAY,GAAI,MAAM,eAAe,KAAG,MAE7C,CAAC;AAEF,QAAA,MAAM,cAAc,GAAI,MAAM,eAAe,KAAG,MAE/C,CAAC;AAEF,QAAA,MAAM,cAAc,GAAI,MAAM,MAAM,KAAG,MAOtC,CAAC;AAEF,QAAA,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,MAOrC,CAAC;AAEF,QAAA,MAAM,iBAAiB,GAAI,SAAS,eAAe,EAAE,SAAS,eAAe,KAAG,MAO/E,CAAC;AAQF,eAAO,MAAM,EAAE,GAAI,MAAM,eAAe,KAAG,OAAyC,CAAC;AACrF,eAAO,MAAM,IAAI,GAAI,MAAM,eAAe,KAAG,OAA2C,CAAC;AACzF,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,KAAG,OAA2C,CAAC;AAChF,eAAO,MAAM,GAAG,GAAI,MAAM,MAAM,KAAG,OAA0C,CAAC;AAC9E,eAAO,MAAM,OAAO,GAAI,SAAS,eAAe,EAAE,SAAS,eAAe,KAAG,OAA0D,CAAC;AAGxI,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,CAAC"}

@@ -1,2 +0,1 @@

import viewport from './viewport';
const defaultBreakpoints = {

@@ -16,2 +15,6 @@ xs: 480,

updateSortedBreakpoints();
/**
* Set custom breakpoints. Call this at app startup before any components mount.
* Calling after mount will not update active hook subscriptions until the next re-render.
*/
export const configure = (customBreakpoints) => {

@@ -27,2 +30,8 @@ currentBreakpoints = customBreakpoints;

};
const resolveSize = (size) => {
if (typeof size === 'number')
return size;
validateBreakpoint(size);
return currentBreakpoints[size];
};
const getNextBreakpoint = (size) => {

@@ -33,32 +42,48 @@ const currentIndex = sortedBreakpoints.findIndex(([name]) => name === size);

};
export const up = (size) => {
validateBreakpoint(size);
return viewport.getWidth() >= currentBreakpoints[size];
/**
* @internal Query builders - used by hook layer, not part of public API
*/
const buildUpQuery = (size) => {
return `(min-width: ${resolveSize(size)}px)`;
};
export const down = (size) => {
validateBreakpoint(size);
return viewport.getWidth() < currentBreakpoints[size];
const buildDownQuery = (size) => {
return `(max-width: ${resolveSize(size) - 0.02}px)`;
};
export const only = (size) => {
const buildOnlyQuery = (size) => {
validateBreakpoint(size);
const width = viewport.getWidth();
const min = currentBreakpoints[size];
const max = getNextBreakpoint(size);
return width >= min && width < max;
return max === Infinity
? `(min-width: ${min}px)`
: `(min-width: ${min}px) and (max-width: ${max - 0.02}px)`;
};
export const not = (size) => {
const buildNotQuery = (size) => {
validateBreakpoint(size);
const width = viewport.getWidth();
const min = currentBreakpoints[size];
const max = getNextBreakpoint(size);
return width < min || width >= max;
return max === Infinity
? `(max-width: ${min - 0.02}px)`
: `(max-width: ${min - 0.02}px), (min-width: ${max}px)`;
};
export const between = (minSize, maxSize) => {
validateBreakpoint(minSize);
validateBreakpoint(maxSize);
const width = viewport.getWidth();
const min = currentBreakpoints[minSize];
const max = currentBreakpoints[maxSize];
return width >= min && width < max;
const buildBetweenQuery = (minSize, maxSize) => {
const min = resolveSize(minSize);
const max = resolveSize(maxSize);
if (min >= max) {
throw new Error(`minSize "${minSize}" (${min}px) must be smaller than maxSize "${maxSize}" (${max}px)`);
}
return `(min-width: ${min}px) and (max-width: ${max - 0.02}px)`;
};
// Imperative API (use in handlers, utils, non-React code)
const matchMedia = (query) => {
if (typeof window === 'undefined')
return false;
return window.matchMedia(query).matches;
};
export const up = (size) => matchMedia(buildUpQuery(size));
export const down = (size) => matchMedia(buildDownQuery(size));
export const only = (size) => matchMedia(buildOnlyQuery(size));
export const not = (size) => matchMedia(buildNotQuery(size));
export const between = (minSize, maxSize) => matchMedia(buildBetweenQuery(minSize, maxSize));
// Export query builders for hook layer
export { buildUpQuery, buildDownQuery, buildOnlyQuery, buildNotQuery, buildBetweenQuery };
//# sourceMappingURL=breakpoints.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"breakpoints.js","sourceRoot":"","sources":["../src/breakpoints.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,kBAAkB,GAAG;IACzB,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,KAAK,EAAE,IAAI;CACH,CAAC;AAIX,IAAI,kBAAkB,GAAgB,EAAE,GAAG,kBAAkB,EAAE,CAAC;AAChE,IAAI,iBAAiB,GAAuB,EAAE,CAAC;AAE/C,MAAM,uBAAuB,GAAG,GAAG,EAAE;IACnC,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrF,CAAC,CAAC;AAEF,uBAAuB,EAAE,CAAC;AAE1B,MAAM,CAAC,MAAM,SAAS,GAAG,CAAwB,iBAAoB,EAAE,EAAE;IACvE,kBAAkB,GAAG,iBAAiB,CAAC;IACvC,uBAAuB,EAAE,CAAC;AAC5B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,kBAAkB,CAAC;AAEvD,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAQ,EAAE;IAChD,IAAI,CAAC,CAAC,IAAI,IAAI,kBAAkB,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,6BAA6B,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzH,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,IAAY,EAAU,EAAE;IACjD,MAAM,YAAY,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,iBAAiB,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACnC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,EAAE;IACjC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,QAAQ,CAAC,QAAQ,EAAE,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC;AACzD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE;IACnC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,QAAQ,CAAC,QAAQ,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;AACxD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE;IACnC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,KAAK,IAAI,GAAG,IAAI,KAAK,GAAG,GAAG,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,EAAE;IAClC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,KAAK,GAAG,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,OAAe,EAAE,OAAe,EAAE,EAAE;IAC1D,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACxC,OAAO,KAAK,IAAI,GAAG,IAAI,KAAK,GAAG,GAAG,CAAC;AACrC,CAAC,CAAC"}
{"version":3,"file":"breakpoints.js","sourceRoot":"","sources":["../src/breakpoints.ts"],"names":[],"mappings":"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"}
export { configure, getBreakpoints, up, down, only, not, between } from './breakpoints';
export type { Breakpoints } from './breakpoints';
export type { Breakpoints, BreakpointValue } from './breakpoints';
export { useUp, useDown, useOnly, useNot, useBetween } from './useBreakpoint';
export { default as useViewport } from './useViewport';
export { default as viewport } from './viewport';
//# sourceMappingURL=index.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxF,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxF,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC"}
export { configure, getBreakpoints, up, down, only, not, between } from './breakpoints';
export { useUp, useDown, useOnly, useNot, useBetween } from './useBreakpoint';
export { default as useViewport } from './useViewport';
export { default as viewport } from './viewport';
//# sourceMappingURL=index.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExF,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExF,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC"}

@@ -1,1 +0,1 @@

{"version":3,"file":"useViewport.d.ts","sourceRoot":"","sources":["../src/useViewport.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,WAAW,cAahB,CAAC;AAEF,eAAe,WAAW,CAAC"}
{"version":3,"file":"useViewport.d.ts","sourceRoot":"","sources":["../src/useViewport.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,WAAW,cAEhB,CAAC;AAEF,eAAe,WAAW,CAAC"}

@@ -1,15 +0,10 @@

import { useEffect, useState } from 'react';
import { useSyncExternalStore } from 'react';
import viewport from './viewport';
const subscribe = (callback) => viewport.onResize(callback);
const getSnapshot = () => viewport.getWidth();
const getServerSnapshot = () => 0;
const useViewport = () => {
const [width, setWidth] = useState(viewport.getWidth());
useEffect(() => {
const handler = () => setWidth(viewport.getWidth());
const removeHandler = viewport.onResize(handler);
return () => {
removeHandler();
};
}, []);
return width;
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
};
export default useViewport;
//# sourceMappingURL=useViewport.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"useViewport.js","sourceRoot":"","sources":["../src/useViewport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IAExD,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;QACpD,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEjD,OAAO,GAAG,EAAE;YACV,aAAa,EAAE,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,eAAe,WAAW,CAAC"}
{"version":3,"file":"useViewport.js","sourceRoot":"","sources":["../src/useViewport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,SAAS,GAAG,CAAC,QAAoB,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACxE,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;AAC9C,MAAM,iBAAiB,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;AAElC,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,OAAO,oBAAoB,CAAC,SAAS,EAAE,WAAW,EAAE,iBAAiB,CAAC,CAAC;AACzE,CAAC,CAAC;AAEF,eAAe,WAAW,CAAC"}

@@ -1,1 +0,1 @@

{"version":3,"file":"viewport.d.ts","sourceRoot":"","sources":["../src/viewport.ts"],"names":[],"mappings":"AAAA,cAAM,cAAc;IAClB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,aAAa,CAAiB;;IAUtC,OAAO,CAAC,YAAY,CAGlB;IAEF,QAAQ;IAIR,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI;CAM7B;AAED,QAAA,MAAM,cAAc,gBAAuB,CAAC;AAC5C,eAAe,cAAc,CAAC"}
{"version":3,"file":"viewport.d.ts","sourceRoot":"","sources":["../src/viewport.ts"],"names":[],"mappings":"AAAA,cAAM,cAAc;IAClB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,aAAa,CAAkB;;IAUvC,OAAO,CAAC,YAAY,CAGlB;IAEF,QAAQ;IAIR,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI;CAM7B;AAED,QAAA,MAAM,cAAc,gBAAuB,CAAC;AAC5C,eAAe,cAAc,CAAC"}

@@ -8,3 +8,3 @@ class ViewportHelper {

this.width = typeof window !== 'undefined' ? window.innerWidth : 0;
this.eventHandlers = [];
this.eventHandlers = new Set();
if (typeof window !== 'undefined') {

@@ -18,5 +18,5 @@ window.addEventListener('resize', this.handleResize);

onResize(handler) {
this.eventHandlers.push(handler);
this.eventHandlers.add(handler);
return () => {
this.eventHandlers = this.eventHandlers.filter(h => h !== handler);
this.eventHandlers.delete(handler);
};

@@ -23,0 +23,0 @@ }

@@ -1,1 +0,1 @@

{"version":3,"file":"viewport.js","sourceRoot":"","sources":["../src/viewport.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc;IAIlB;QAQQ,iBAAY,GAAG,GAAG,EAAE;YAC1B,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC;YAC/B,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,CAAC,CAAC;QAVA,IAAI,CAAC,KAAK,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;QACxB,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAOD,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,QAAQ,CAAC,OAAmB;QAC1B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;QACrE,CAAC,CAAC;IACJ,CAAC;CACF;AAED,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;AAC5C,eAAe,cAAc,CAAC"}
{"version":3,"file":"viewport.js","sourceRoot":"","sources":["../src/viewport.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc;IAIlB;QAQQ,iBAAY,GAAG,GAAG,EAAE;YAC1B,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC;YAC/B,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,CAAC,CAAC;QAVA,IAAI,CAAC,KAAK,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,IAAI,CAAC,aAAa,GAAG,IAAI,GAAG,EAAE,CAAC;QAC/B,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAOD,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,QAAQ,CAAC,OAAmB;QAC1B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC,CAAC;IACJ,CAAC;CACF;AAED,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;AAC5C,eAAe,cAAc,CAAC"}
{
"name": "breakpoint-utils",
"version": "1.0.0",
"description": "Viewport width utility with breakpoint functions for React",
"version": "2.0.0",
"description": "Viewport width utility with optional breakpoint functions for React",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist",
"README.md"
],
"scripts": {

@@ -12,4 +16,9 @@ "build": "tsc",

"peerDependencies": {
"react": ">=16.8.0"
"react": ">=18.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": true
}
},
"devDependencies": {

@@ -16,0 +25,0 @@ "@types/react": "^18.2.0",

+119
-70

@@ -14,35 +14,29 @@ # breakpoint-utils

- **Configurable breakpoints** - Use defaults or define your own
- **Responsive utilities** - `up`, `down`, `only`, `not`, `between`
- **React hook** - `useViewport` for reactive viewport width
- **Imperative API** - `up`, `down`, `only`, `not`, `between` for use anywhere
- **React hooks** - `useUp`, `useDown`, `useOnly`, `useNot`, `useBetween` for reactive components
- **Viewport measurements** - `useViewport` for pixel-based calculations
- **CSS parity** - Uses `matchMedia` for exact CSS behavior
- **Lightweight** - Minimal dependencies
- **TypeScript** - Full type safety
## Quick Start
## Default Breakpoints
### Default Breakpoints
| Name | Min Width |
|------|-----------|
| `xs` | 480px |
| `sm` | 640px |
| `md` | 768px |
| `lg` | 1024px |
| `xl` | 1280px |
| `2xl` | 1536px |
```typescript
import { up, down, only } from 'breakpoint-utils';
## Configuration
// Default breakpoints: xs: 480, sm: 640, md: 768, lg: 1024, xl: 1280, 2xl: 1536
### `configure(breakpoints)`
if (up('md')) {
// viewport >= 768px
}
Replace the default breakpoints with your own. Must be called before any components mount.
if (down('lg')) {
// viewport < 1024px
}
if (only('sm')) {
// 640px <= viewport < 768px
}
```
### Custom Breakpoints
```typescript
import { configure, up, down } from 'breakpoint-utils';
import { configure } from 'breakpoint-utils';
// Define your own breakpoints
configure({

@@ -54,22 +48,4 @@ mobile: 320,

});
if (up('tablet')) {
// viewport >= 768px
}
```
## API
### `configure(breakpoints)`
Set custom breakpoints. Must be called before using utility functions.
```typescript
configure({
small: 600,
medium: 900,
large: 1200,
});
```
### `getBreakpoints()`

@@ -84,2 +60,8 @@

## Imperative API
Use these in event handlers, utility functions, or anywhere outside of React rendering.
All functions accept a named breakpoint string. `up`, `down`, and `between` also accept a number for ad-hoc pixel values.
### `up(size)`

@@ -90,3 +72,4 @@

```typescript
up('md') // viewport >= 768px
up('md') // viewport >= 768px
up(900) // viewport >= 900px
```

@@ -96,6 +79,7 @@

Returns `true` if viewport width is < the breakpoint.
Returns `true` if viewport is **below** the breakpoint (does not include it).
```typescript
down('lg') // viewport < 1024px
down(900) // viewport < 900px
```

@@ -124,46 +108,111 @@

```typescript
between('sm', 'lg') // 640px <= viewport < 1024px
between('sm', 'lg') // 640px <= viewport < 1024px
between(600, 900) // 600px <= viewport < 900px
between('sm', 900) // mix named + numeric
```
## React Hook
> **Note:** These functions return a one-shot result at call time. In React, use the hooks below for reactive updates. Outside React, you can pair with the `viewport` singleton to re-check on viewport changes:
>
> ```typescript
> import { up, viewport } from 'breakpoint-utils';
>
> // viewport exposes getWidth() and onResize() for manual subscription
> const unsubscribe = viewport.onResize(() => {
> console.log('Is desktop:', up('lg'));
> });
>
> // Clean up when no longer needed
> unsubscribe();
> ```
## React Hooks
Each hook mirrors its imperative counterpart but reactively re-renders the component when the result changes. Like the imperative API, `useUp`, `useDown`, and `useBetween` accept numbers as well as named breakpoints.
### `useUp(size)`
Returns `true` if viewport width is >= the breakpoint.
```typescript
const isDesktop = useUp('lg'); // viewport >= 1024px
const isWide = useUp(900); // viewport >= 900px
```
### `useDown(size)`
Returns `true` if viewport is **below** the breakpoint (does not include it).
```typescript
const isMobile = useDown('md'); // viewport < 768px
const isNarrow = useDown(600); // viewport < 600px
```
### `useOnly(size)`
Returns `true` if viewport is within the breakpoint range.
```typescript
const isTabletOnly = useOnly('md'); // 768px <= viewport < 1024px
```
### `useNot(size)`
Returns `true` if viewport is outside the breakpoint range.
```typescript
const isNotTablet = useNot('md'); // viewport < 768px OR viewport >= 1024px
```
### `useBetween(minSize, maxSize)`
Returns `true` if viewport is between two breakpoints.
```typescript
const isSmallToMedium = useBetween('sm', 'lg'); // 640px <= viewport < 1024px
const isCustomRange = useBetween(600, 900); // 600px <= viewport < 900px
```
> **SSR Note:** All hooks return `false` during server-side rendering until hydration completes.
### `useViewport()`
React hook that returns the current viewport width and updates on resize.
Returns the current viewport width in pixels. Use for pixel-based calculations (drag/resize logic, canvas, charts, virtualization):
```typescript
import { useViewport, configure, up } from 'breakpoint-utils';
import { useViewport } from 'breakpoint-utils';
// Optional: configure custom breakpoints
configure({
mobile: 375,
tablet: 768,
desktop: 1024,
});
function ResizablePanel() {
const width = useViewport();
const panelWidth = Math.min(width * 0.8, 600);
function MyComponent() {
const width = useViewport();
return (
<div>
<p>Viewport width: {width}px</p>
{up('tablet') && <p>Tablet or larger</p>}
</div>
);
return <div style={{ width: panelWidth }} />;
}
```
## Direct Viewport Access
> **Note:** Use breakpoint hooks (`useUp`, etc.) for responsive layouts. Use `useViewport` only when you need actual pixel values for calculations.
## Migrating from v1.0.0
In v1.0.0, reactive breakpoint checks required `useViewport()` to trigger re-renders:
```typescript
import { viewport } from 'breakpoint-utils';
import { useViewport, up } from 'breakpoint-utils';
const width = viewport.getWidth();
function MyComponent() {
useViewport(); // re-renders on every pixel change
const isDesktop = up('lg');
return isDesktop ? <DesktopNav /> : <MobileNav />;
}
```
const unsubscribe = viewport.onResize(() => {
console.log('Viewport resized:', viewport.getWidth());
});
This still works, but the dedicated hooks are preferred — they only re-render when a breakpoint boundary is crossed:
// Clean up
unsubscribe();
```typescript
// v2.0.0+ — dedicated hooks
import { useUp } from 'breakpoint-utils';
function MyComponent() {
const isDesktop = useUp('lg'); // re-renders only at 1024px boundary
return isDesktop ? <DesktopNav /> : <MobileNav />;
}
```

@@ -170,0 +219,0 @@

import viewport from './viewport';
const defaultBreakpoints = {
xs: 480,
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
'2xl': 1536,
} as const;
export type Breakpoints = Record<string, number>;
let currentBreakpoints: Breakpoints = { ...defaultBreakpoints };
let sortedBreakpoints: [string, number][] = [];
const updateSortedBreakpoints = () => {
sortedBreakpoints = Object.entries(currentBreakpoints).sort((a, b) => a[1] - b[1]);
};
updateSortedBreakpoints();
export const configure = <T extends Breakpoints>(customBreakpoints: T) => {
currentBreakpoints = customBreakpoints;
updateSortedBreakpoints();
};
export const getBreakpoints = () => currentBreakpoints;
const validateBreakpoint = (size: string): void => {
if (!(size in currentBreakpoints)) {
throw new Error(`Invalid breakpoint: "${size}". Available breakpoints: ${Object.keys(currentBreakpoints).join(', ')}`);
}
};
const getNextBreakpoint = (size: string): number => {
const currentIndex = sortedBreakpoints.findIndex(([name]) => name === size);
const next = sortedBreakpoints[currentIndex + 1];
return next ? next[1] : Infinity;
};
export const up = (size: string) => {
validateBreakpoint(size);
return viewport.getWidth() >= currentBreakpoints[size];
};
export const down = (size: string) => {
validateBreakpoint(size);
return viewport.getWidth() < currentBreakpoints[size];
};
export const only = (size: string) => {
validateBreakpoint(size);
const width = viewport.getWidth();
const min = currentBreakpoints[size];
const max = getNextBreakpoint(size);
return width >= min && width < max;
};
export const not = (size: string) => {
validateBreakpoint(size);
const width = viewport.getWidth();
const min = currentBreakpoints[size];
const max = getNextBreakpoint(size);
return width < min || width >= max;
};
export const between = (minSize: string, maxSize: string) => {
validateBreakpoint(minSize);
validateBreakpoint(maxSize);
const width = viewport.getWidth();
const min = currentBreakpoints[minSize];
const max = currentBreakpoints[maxSize];
return width >= min && width < max;
};
export { configure, getBreakpoints, up, down, only, not, between } from './breakpoints';
export type { Breakpoints } from './breakpoints';
export { default as useViewport } from './useViewport';
export { default as viewport } from './viewport';
import { useEffect, useState } from 'react';
import viewport from './viewport';
const useViewport = () => {
const [width, setWidth] = useState(viewport.getWidth());
useEffect(() => {
const handler = () => setWidth(viewport.getWidth());
const removeHandler = viewport.onResize(handler);
return () => {
removeHandler();
};
}, []);
return width;
};
export default useViewport;
class ViewportHelper {
private width: number;
private eventHandlers: (() => void)[];
constructor() {
this.width = typeof window !== 'undefined' ? window.innerWidth : 0;
this.eventHandlers = [];
if (typeof window !== 'undefined') {
window.addEventListener('resize', this.handleResize);
}
}
private handleResize = () => {
this.width = window.innerWidth;
this.eventHandlers.forEach(handler => handler());
};
getWidth() {
return this.width;
}
onResize(handler: () => void) {
this.eventHandlers.push(handler);
return () => {
this.eventHandlers = this.eventHandlers.filter(h => h !== handler);
};
}
}
const viewportHelper = new ViewportHelper();
export default viewportHelper;
{
"compilerOptions": {
"target": "ES2018",
"module": "ESNext",
"moduleResolution": "node",
"lib": ["DOM", "ES2018"],
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}