breakpoint-utils 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +186 -0
- package/dist/breakpoints.d.ts +9 -0
- package/dist/breakpoints.d.ts.map +1 -0
- package/dist/breakpoints.js +61 -0
- package/dist/breakpoints.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/useViewport.d.ts +3 -0
- package/dist/useViewport.d.ts.map +1 -0
- package/dist/useViewport.js +15 -0
- package/dist/useViewport.js.map +1 -0
- package/dist/viewport.d.ts +11 -0
- package/dist/viewport.d.ts.map +1 -0
- package/dist/viewport.js +25 -0
- package/dist/viewport.js.map +1 -0
- package/package.json +26 -0
- package/src/breakpoints.ts +75 -0
- package/src/index.ts +4 -0
- package/src/useViewport.ts +19 -0
- package/src/viewport.ts +31 -0
- package/tsconfig.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# breakpoint-utils
|
|
2
|
+
|
|
3
|
+
Lightweight utilities for querying responsive breakpoints and viewport width in JavaScript and React.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install breakpoint-utils
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Configurable breakpoints** - Use defaults or define your own
|
|
14
|
+
- **Responsive utilities** - `up`, `down`, `only`, `not`, `between`
|
|
15
|
+
- **React hook** - `useViewport` for reactive viewport width
|
|
16
|
+
- **Lightweight** - Minimal dependencies
|
|
17
|
+
- **TypeScript** - Full type safety
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### Default Breakpoints
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { up, down, only } from 'breakpoint-utils';
|
|
25
|
+
|
|
26
|
+
// Default breakpoints: xs: 480, sm: 640, md: 768, lg: 1024, xl: 1280, 2xl: 1536
|
|
27
|
+
|
|
28
|
+
if (up('md')) {
|
|
29
|
+
// viewport >= 768px
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (down('lg')) {
|
|
33
|
+
// viewport < 1024px
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (only('sm')) {
|
|
37
|
+
// 640px <= viewport < 768px
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Custom Breakpoints
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { configure, up, down } from 'breakpoint-utils';
|
|
45
|
+
|
|
46
|
+
// Define your own breakpoints
|
|
47
|
+
configure({
|
|
48
|
+
mobile: 320,
|
|
49
|
+
tablet: 768,
|
|
50
|
+
desktop: 1024,
|
|
51
|
+
wide: 1440,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (up('tablet')) {
|
|
55
|
+
// viewport >= 768px
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## API
|
|
60
|
+
|
|
61
|
+
### `configure(breakpoints)`
|
|
62
|
+
|
|
63
|
+
Set custom breakpoints. Must be called before using utility functions.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
configure({
|
|
67
|
+
small: 600,
|
|
68
|
+
medium: 900,
|
|
69
|
+
large: 1200,
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `getBreakpoints()`
|
|
74
|
+
|
|
75
|
+
Get the current breakpoint configuration.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
const breakpoints = getBreakpoints();
|
|
79
|
+
// { xs: 480, sm: 640, ... } or your custom config
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `up(size)`
|
|
83
|
+
|
|
84
|
+
Returns `true` if viewport width is >= the breakpoint.
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
up('md') // viewport >= 768px
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### `down(size)`
|
|
91
|
+
|
|
92
|
+
Returns `true` if viewport width is < the breakpoint.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
down('lg') // viewport < 1024px
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### `only(size)`
|
|
99
|
+
|
|
100
|
+
Returns `true` if viewport is within the breakpoint range (>= size and < next breakpoint).
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
only('md') // 768px <= viewport < 1024px
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `not(size)`
|
|
107
|
+
|
|
108
|
+
Returns `true` if viewport is outside the breakpoint range.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
not('md') // viewport < 768px OR viewport >= 1024px
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `between(minSize, maxSize)`
|
|
115
|
+
|
|
116
|
+
Returns `true` if viewport is between two breakpoints.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
between('sm', 'lg') // 640px <= viewport < 1024px
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## React Hook
|
|
123
|
+
|
|
124
|
+
### `useViewport()`
|
|
125
|
+
|
|
126
|
+
React hook that returns the current viewport width and updates on resize.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { useViewport, configure, up } from 'breakpoint-utils';
|
|
130
|
+
|
|
131
|
+
// Optional: configure custom breakpoints
|
|
132
|
+
configure({
|
|
133
|
+
mobile: 375,
|
|
134
|
+
tablet: 768,
|
|
135
|
+
desktop: 1024,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
function MyComponent() {
|
|
139
|
+
const width = useViewport();
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<div>
|
|
143
|
+
<p>Viewport width: {width}px</p>
|
|
144
|
+
{up('tablet') && <p>Tablet or larger</p>}
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Direct Viewport Access
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { viewport } from 'breakpoint-utils';
|
|
154
|
+
|
|
155
|
+
const width = viewport.getWidth();
|
|
156
|
+
|
|
157
|
+
const unsubscribe = viewport.onResize(() => {
|
|
158
|
+
console.log('Viewport resized:', viewport.getWidth());
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Clean up
|
|
162
|
+
unsubscribe();
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## TypeScript
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import { configure, up, type Breakpoints } from 'breakpoint-utils';
|
|
169
|
+
|
|
170
|
+
const myBreakpoints = {
|
|
171
|
+
xs: 320,
|
|
172
|
+
sm: 640,
|
|
173
|
+
md: 768,
|
|
174
|
+
lg: 1024,
|
|
175
|
+
} satisfies Breakpoints;
|
|
176
|
+
|
|
177
|
+
configure(myBreakpoints);
|
|
178
|
+
|
|
179
|
+
// Type-safe breakpoint names
|
|
180
|
+
type MyBreakpoint = keyof typeof myBreakpoints;
|
|
181
|
+
const size: MyBreakpoint = 'md';
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type Breakpoints = Record<string, number>;
|
|
2
|
+
export declare const configure: <T extends Breakpoints>(customBreakpoints: T) => void;
|
|
3
|
+
export declare const getBreakpoints: () => Breakpoints;
|
|
4
|
+
export declare const up: (size: string) => boolean;
|
|
5
|
+
export declare const down: (size: string) => boolean;
|
|
6
|
+
export declare const only: (size: string) => boolean;
|
|
7
|
+
export declare const not: (size: string) => boolean;
|
|
8
|
+
export declare const between: (minSize: string, maxSize: string) => boolean;
|
|
9
|
+
//# sourceMappingURL=breakpoints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import viewport from './viewport';
|
|
2
|
+
const defaultBreakpoints = {
|
|
3
|
+
xs: 480,
|
|
4
|
+
sm: 640,
|
|
5
|
+
md: 768,
|
|
6
|
+
lg: 1024,
|
|
7
|
+
xl: 1280,
|
|
8
|
+
'2xl': 1536,
|
|
9
|
+
};
|
|
10
|
+
let currentBreakpoints = { ...defaultBreakpoints };
|
|
11
|
+
let sortedBreakpoints = [];
|
|
12
|
+
const updateSortedBreakpoints = () => {
|
|
13
|
+
sortedBreakpoints = Object.entries(currentBreakpoints).sort((a, b) => a[1] - b[1]);
|
|
14
|
+
};
|
|
15
|
+
updateSortedBreakpoints();
|
|
16
|
+
export const configure = (customBreakpoints) => {
|
|
17
|
+
currentBreakpoints = customBreakpoints;
|
|
18
|
+
updateSortedBreakpoints();
|
|
19
|
+
};
|
|
20
|
+
export const getBreakpoints = () => currentBreakpoints;
|
|
21
|
+
const validateBreakpoint = (size) => {
|
|
22
|
+
if (!(size in currentBreakpoints)) {
|
|
23
|
+
throw new Error(`Invalid breakpoint: "${size}". Available breakpoints: ${Object.keys(currentBreakpoints).join(', ')}`);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const getNextBreakpoint = (size) => {
|
|
27
|
+
const currentIndex = sortedBreakpoints.findIndex(([name]) => name === size);
|
|
28
|
+
const next = sortedBreakpoints[currentIndex + 1];
|
|
29
|
+
return next ? next[1] : Infinity;
|
|
30
|
+
};
|
|
31
|
+
export const up = (size) => {
|
|
32
|
+
validateBreakpoint(size);
|
|
33
|
+
return viewport.getWidth() >= currentBreakpoints[size];
|
|
34
|
+
};
|
|
35
|
+
export const down = (size) => {
|
|
36
|
+
validateBreakpoint(size);
|
|
37
|
+
return viewport.getWidth() < currentBreakpoints[size];
|
|
38
|
+
};
|
|
39
|
+
export const only = (size) => {
|
|
40
|
+
validateBreakpoint(size);
|
|
41
|
+
const width = viewport.getWidth();
|
|
42
|
+
const min = currentBreakpoints[size];
|
|
43
|
+
const max = getNextBreakpoint(size);
|
|
44
|
+
return width >= min && width < max;
|
|
45
|
+
};
|
|
46
|
+
export const not = (size) => {
|
|
47
|
+
validateBreakpoint(size);
|
|
48
|
+
const width = viewport.getWidth();
|
|
49
|
+
const min = currentBreakpoints[size];
|
|
50
|
+
const max = getNextBreakpoint(size);
|
|
51
|
+
return width < min || width >= max;
|
|
52
|
+
};
|
|
53
|
+
export const between = (minSize, maxSize) => {
|
|
54
|
+
validateBreakpoint(minSize);
|
|
55
|
+
validateBreakpoint(maxSize);
|
|
56
|
+
const width = viewport.getWidth();
|
|
57
|
+
const min = currentBreakpoints[minSize];
|
|
58
|
+
const max = currentBreakpoints[maxSize];
|
|
59
|
+
return width >= min && width < max;
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=breakpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"breakpoints.js","sourceRoot":"","sources":["../src/breakpoints.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { configure, getBreakpoints, up, down, only, not, between } from './breakpoints';
|
|
2
|
+
export type { Breakpoints } from './breakpoints';
|
|
3
|
+
export { default as useViewport } from './useViewport';
|
|
4
|
+
export { default as viewport } from './viewport';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useViewport.d.ts","sourceRoot":"","sources":["../src/useViewport.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,WAAW,cAahB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import viewport from './viewport';
|
|
3
|
+
const useViewport = () => {
|
|
4
|
+
const [width, setWidth] = useState(viewport.getWidth());
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const handler = () => setWidth(viewport.getWidth());
|
|
7
|
+
const removeHandler = viewport.onResize(handler);
|
|
8
|
+
return () => {
|
|
9
|
+
removeHandler();
|
|
10
|
+
};
|
|
11
|
+
}, []);
|
|
12
|
+
return width;
|
|
13
|
+
};
|
|
14
|
+
export default useViewport;
|
|
15
|
+
//# sourceMappingURL=useViewport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare class ViewportHelper {
|
|
2
|
+
private width;
|
|
3
|
+
private eventHandlers;
|
|
4
|
+
constructor();
|
|
5
|
+
private handleResize;
|
|
6
|
+
getWidth(): number;
|
|
7
|
+
onResize(handler: () => void): () => void;
|
|
8
|
+
}
|
|
9
|
+
declare const viewportHelper: ViewportHelper;
|
|
10
|
+
export default viewportHelper;
|
|
11
|
+
//# sourceMappingURL=viewport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
package/dist/viewport.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
class ViewportHelper {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.handleResize = () => {
|
|
4
|
+
this.width = window.innerWidth;
|
|
5
|
+
this.eventHandlers.forEach(handler => handler());
|
|
6
|
+
};
|
|
7
|
+
this.width = typeof window !== 'undefined' ? window.innerWidth : 0;
|
|
8
|
+
this.eventHandlers = [];
|
|
9
|
+
if (typeof window !== 'undefined') {
|
|
10
|
+
window.addEventListener('resize', this.handleResize);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
getWidth() {
|
|
14
|
+
return this.width;
|
|
15
|
+
}
|
|
16
|
+
onResize(handler) {
|
|
17
|
+
this.eventHandlers.push(handler);
|
|
18
|
+
return () => {
|
|
19
|
+
this.eventHandlers = this.eventHandlers.filter(h => h !== handler);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const viewportHelper = new ViewportHelper();
|
|
24
|
+
export default viewportHelper;
|
|
25
|
+
//# sourceMappingURL=viewport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "breakpoint-utils",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Viewport width utility with breakpoint functions for React",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"dev": "tsc --watch"
|
|
10
|
+
},
|
|
11
|
+
"peerDependencies": {
|
|
12
|
+
"react": ">=16.8.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/react": "^18.2.0",
|
|
16
|
+
"react": "^18.2.0",
|
|
17
|
+
"typescript": "^5.0.0"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"breakpoints",
|
|
21
|
+
"viewport",
|
|
22
|
+
"responsive",
|
|
23
|
+
"react"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT"
|
|
26
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import viewport from './viewport';
|
|
2
|
+
|
|
3
|
+
const defaultBreakpoints = {
|
|
4
|
+
xs: 480,
|
|
5
|
+
sm: 640,
|
|
6
|
+
md: 768,
|
|
7
|
+
lg: 1024,
|
|
8
|
+
xl: 1280,
|
|
9
|
+
'2xl': 1536,
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
export type Breakpoints = Record<string, number>;
|
|
13
|
+
|
|
14
|
+
let currentBreakpoints: Breakpoints = { ...defaultBreakpoints };
|
|
15
|
+
let sortedBreakpoints: [string, number][] = [];
|
|
16
|
+
|
|
17
|
+
const updateSortedBreakpoints = () => {
|
|
18
|
+
sortedBreakpoints = Object.entries(currentBreakpoints).sort((a, b) => a[1] - b[1]);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
updateSortedBreakpoints();
|
|
22
|
+
|
|
23
|
+
export const configure = <T extends Breakpoints>(customBreakpoints: T) => {
|
|
24
|
+
currentBreakpoints = customBreakpoints;
|
|
25
|
+
updateSortedBreakpoints();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const getBreakpoints = () => currentBreakpoints;
|
|
29
|
+
|
|
30
|
+
const validateBreakpoint = (size: string): void => {
|
|
31
|
+
if (!(size in currentBreakpoints)) {
|
|
32
|
+
throw new Error(`Invalid breakpoint: "${size}". Available breakpoints: ${Object.keys(currentBreakpoints).join(', ')}`);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getNextBreakpoint = (size: string): number => {
|
|
37
|
+
const currentIndex = sortedBreakpoints.findIndex(([name]) => name === size);
|
|
38
|
+
const next = sortedBreakpoints[currentIndex + 1];
|
|
39
|
+
return next ? next[1] : Infinity;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const up = (size: string) => {
|
|
43
|
+
validateBreakpoint(size);
|
|
44
|
+
return viewport.getWidth() >= currentBreakpoints[size];
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const down = (size: string) => {
|
|
48
|
+
validateBreakpoint(size);
|
|
49
|
+
return viewport.getWidth() < currentBreakpoints[size];
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const only = (size: string) => {
|
|
53
|
+
validateBreakpoint(size);
|
|
54
|
+
const width = viewport.getWidth();
|
|
55
|
+
const min = currentBreakpoints[size];
|
|
56
|
+
const max = getNextBreakpoint(size);
|
|
57
|
+
return width >= min && width < max;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const not = (size: string) => {
|
|
61
|
+
validateBreakpoint(size);
|
|
62
|
+
const width = viewport.getWidth();
|
|
63
|
+
const min = currentBreakpoints[size];
|
|
64
|
+
const max = getNextBreakpoint(size);
|
|
65
|
+
return width < min || width >= max;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const between = (minSize: string, maxSize: string) => {
|
|
69
|
+
validateBreakpoint(minSize);
|
|
70
|
+
validateBreakpoint(maxSize);
|
|
71
|
+
const width = viewport.getWidth();
|
|
72
|
+
const min = currentBreakpoints[minSize];
|
|
73
|
+
const max = currentBreakpoints[maxSize];
|
|
74
|
+
return width >= min && width < max;
|
|
75
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import viewport from './viewport';
|
|
3
|
+
|
|
4
|
+
const useViewport = () => {
|
|
5
|
+
const [width, setWidth] = useState(viewport.getWidth());
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const handler = () => setWidth(viewport.getWidth());
|
|
9
|
+
const removeHandler = viewport.onResize(handler);
|
|
10
|
+
|
|
11
|
+
return () => {
|
|
12
|
+
removeHandler();
|
|
13
|
+
};
|
|
14
|
+
}, []);
|
|
15
|
+
|
|
16
|
+
return width;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default useViewport;
|
package/src/viewport.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class ViewportHelper {
|
|
2
|
+
private width: number;
|
|
3
|
+
private eventHandlers: (() => void)[];
|
|
4
|
+
|
|
5
|
+
constructor() {
|
|
6
|
+
this.width = typeof window !== 'undefined' ? window.innerWidth : 0;
|
|
7
|
+
this.eventHandlers = [];
|
|
8
|
+
if (typeof window !== 'undefined') {
|
|
9
|
+
window.addEventListener('resize', this.handleResize);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
private handleResize = () => {
|
|
14
|
+
this.width = window.innerWidth;
|
|
15
|
+
this.eventHandlers.forEach(handler => handler());
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
getWidth() {
|
|
19
|
+
return this.width;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onResize(handler: () => void) {
|
|
23
|
+
this.eventHandlers.push(handler);
|
|
24
|
+
return () => {
|
|
25
|
+
this.eventHandlers = this.eventHandlers.filter(h => h !== handler);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const viewportHelper = new ViewportHelper();
|
|
31
|
+
export default viewportHelper;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2018",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"lib": ["DOM", "ES2018"],
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"sourceMap": true,
|
|
10
|
+
"outDir": "./dist",
|
|
11
|
+
"rootDir": "./src",
|
|
12
|
+
"strict": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|