match-breakpoint 1.0.0-canary.0 → 1.0.0-canary.1

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.
Files changed (28) hide show
  1. package/README.md +181 -33
  2. package/dist/components/Breakpoint/Breakpoint.d.ts +23 -0
  3. package/dist/{src/components → components}/Breakpoint/Breakpoint.js +23 -14
  4. package/dist/components/Breakpoint/BreakpointChild.d.ts +21 -0
  5. package/dist/{src/components → components}/Breakpoint/BreakpointChild.js +47 -45
  6. package/dist/components/Breakpoint/index.d.ts +1 -0
  7. package/dist/components/Breakpoint/index.js +1 -0
  8. package/dist/{src/components → components}/BreakpointsProvider/BreakpointProvider.js +4 -4
  9. package/dist/{src/components → components}/BreakpointsProvider/BreakpointsProvider.d.ts +5 -5
  10. package/dist/{src/components → components}/BreakpointsProvider/BreakpointsProvider.js +9 -9
  11. package/dist/components/BreakpointsProvider/index.d.ts +1 -0
  12. package/dist/components/BreakpointsProvider/index.js +1 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.js +2 -0
  15. package/dist/types/breakpoints.d.ts +10 -0
  16. package/dist/types/styles.d.ts +6 -0
  17. package/dist/utils/screen-width.d.ts +2 -0
  18. package/dist/utils/screen-width.js +6 -0
  19. package/package.json +32 -15
  20. package/dist/src/components/Breakpoint/Breakpoint.d.ts +0 -17
  21. package/dist/src/components/Breakpoint/BreakpointChild.d.ts +0 -15
  22. package/dist/src/components/Breakpoint/index.d.ts +0 -1
  23. package/dist/src/components/Breakpoint/index.js +0 -1
  24. package/dist/src/components/BreakpointsProvider/index.d.ts +0 -1
  25. package/dist/src/components/BreakpointsProvider/index.js +0 -1
  26. package/dist/src/utils/screen-width.d.ts +0 -3
  27. package/dist/src/utils/screen-width.js +0 -12
  28. /package/dist/{src/components → components}/BreakpointsProvider/BreakpointProvider.d.ts +0 -0
package/README.md CHANGED
@@ -14,15 +14,15 @@ A library of optimized React components and hooks for matching screen widths.
14
14
  # Installation
15
15
 
16
16
  ```bash
17
- yarn add match-breakpoint@latest
17
+ yarn add match-breakpoint
18
18
 
19
19
  // or
20
20
 
21
- npm install match-breakpoint@latest
21
+ npm install match-breakpoint
22
22
 
23
23
  // or
24
24
 
25
- pnpm install match-breakpoint@latest
25
+ pnpm install match-breakpoint
26
26
  ```
27
27
 
28
28
  # Advantages
@@ -31,7 +31,7 @@ pnpm install match-breakpoint@latest
31
31
 
32
32
  ❇️ ✨ Using `Breakpoint` components allows you to avoid cumulative layout shift.
33
33
 
34
- ❇️ 💫 Conditional content display is compatible with most CSS frameworks, preprocessors, etc. In particular, it's possible to use the Tailwind CSS class name preset out of the box.
34
+ ❇️ 🧩 Conditional content display is compatible with most CSS frameworks, preprocessors, etc. In particular, it's possible to use the Tailwind CSS class name preset out of the box.
35
35
 
36
36
  ❇️ 🛡️ The library supports breakpoint typing used in all components and hooks from one place.
37
37
 
@@ -54,11 +54,9 @@ Next you need to define the breakpoints that will be used in the application:
54
54
 
55
55
  ```tsx
56
56
  const BREAKPOINTS = {
57
- // …
58
57
  md: '768px',
59
58
  lg: '1024px',
60
59
  xl: '1280px',
61
- // …
62
60
  };
63
61
 
64
62
  const App: FC = () => (
@@ -75,11 +73,9 @@ You can also pass a value from some configuration as breakpoints, for example fr
75
73
  import tailwindConfig from '../../tailwind.config.ts';
76
74
 
77
75
  const DEFAULT_BREAKPOINTS = {
78
- // …
79
76
  md: '768px',
80
77
  lg: '1024px',
81
78
  xl: '1280px',
82
- // …
83
79
  };
84
80
 
85
81
  const breakpoints = tailwindConfig.theme?.screens ?? DEFAULT_BREAKPOINTS;
@@ -97,7 +93,7 @@ After that you can use the `Breakpoint` component, for example:
97
93
  ```tsx
98
94
  import { Breakpoint } from 'match-breakpoint';
99
95
 
100
- const Content: FC = () => (
96
+ const Page: FC = () => (
101
97
  <>
102
98
  <Breakpoint size="md">Desktop Device Content</Breakpoint>
103
99
 
@@ -108,19 +104,15 @@ const Content: FC = () => (
108
104
  );
109
105
  ```
110
106
 
111
- Or using the `useBreakpoint` hook:
107
+ Or this using the `useBreakpoint` hook:
112
108
 
113
109
  ```tsx
114
110
  import { useBreakpoint } from 'match-breakpoint';
115
111
 
116
112
  const Content: FC = () => {
117
- const isScreenMinMd = useBreakpoint('md');
113
+ const isDesktop = useBreakpoint('md');
118
114
 
119
- if (isScreenMinMd) {
120
- return 'Desktop Device Content';
121
- }
122
-
123
- return 'Mobile Device Content';
115
+ return isDesktop ? 'Desktop Device Content' : 'Mobile Device Content';
124
116
  };
125
117
  ```
126
118
 
@@ -128,7 +120,7 @@ const Content: FC = () => {
128
120
 
129
121
  ## BreakpointsProvider
130
122
 
131
- Defined breakpoint contexts.
123
+ Defines breakpoint contexts. Required for the library to function.
132
124
 
133
125
  ### Usage:
134
126
 
@@ -136,18 +128,17 @@ Example:
136
128
 
137
129
  ```tsx
138
130
  const BREAKPOINTS = {
139
- md: 768, // Same as '768px'
140
- lg: '1024px',
141
- xl: {
142
- min: '1280px',
143
- minClassName: 'max-xl:hidden',
131
+ sm: 640, // Same as '640px'
132
+ md: '768px',
133
+ lg: {
134
+ value: 1024, // same as '1024px'
135
+ minClassName: 'max-lg:hidden',
136
+ maxClassName: 'lg:hidden',
144
137
  },
145
- combined: {
146
- max: '768px',
147
- maxClassName: 'md:hidden',
148
-
149
- min: '1280px',
138
+ xl: {
139
+ value: '1280px',
150
140
  minClassName: 'max-xl:hidden',
141
+ maxClassName: 'xl:hidden',
151
142
  },
152
143
  };
153
144
 
@@ -161,9 +152,166 @@ const App: FC = () => (
161
152
 
162
153
  ### Properties:
163
154
 
164
- | Property | Type | Default value | Description |
165
- | -------------------- | ---------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
166
- | breakpoints | `Record<string, string \| number \| BreakpointData>` | - | Defines the set of breakpoints used in the application. |
167
- | classNamePreset | `'tailwind' \| undefined` | `undefined` | Defines a preset of class names used to hide elements. |
168
- | mergeClassesFunction | `MergeClassesFunction \| undefined` | `(...classes) => classes.filter(Boolean).join(' ')` | Defines a function for merging classes when adding them to elements. For example, you can pass a function to prevent class name conflicts. |
169
- | children | `ReactNode` | - | Required child elements. |
155
+ #### 1. breakpoints
156
+
157
+ Defines the set of breakpoints used in the application. The property is required.
158
+
159
+ **Type:** `Record<string, string | number | BreakpointData>`
160
+
161
+ **Default value:** —
162
+
163
+ #### 2. cssPreset
164
+
165
+ Preset of class names added to elements for conditional display. The property is optional.
166
+
167
+ **Type:** `'tailwind' | undefined`
168
+
169
+ **Default value:** `undefined`
170
+
171
+ #### 3. mergeClassesFunction
172
+
173
+ Function for merging class names when displaying elements conditionally. The property is optional.
174
+
175
+ **Type:** `MergeClassesFunction | undefined`
176
+
177
+ **Default value:** `(...classes) => classes.filter(Boolean).join(' ')`
178
+
179
+ #### 4. children
180
+
181
+ Child elements. The property is required.
182
+
183
+ **Type:** `ReactNode`
184
+
185
+ **Default value:** —
186
+
187
+ ## Breakpoint
188
+
189
+ Renders content based on the current screen size.
190
+
191
+ ### Usage:
192
+
193
+ Example:
194
+
195
+ ```tsx
196
+ const Page: FC = () => (
197
+ <>
198
+ <Breakpoint size="md">Desktop Device Content</Breakpoint>
199
+
200
+ <Breakpoint size="md" matchTo="max">
201
+ Mobile Device Content
202
+ </Breakpoint>
203
+ </>
204
+ );
205
+ ```
206
+
207
+ ### Properties:
208
+
209
+ #### 1. size
210
+
211
+ The breakpoint size specified when setting the `breakpoints` property in the `BreakpointsProvider` component. The property is required.
212
+
213
+ **Type:** `ScreenSize`
214
+
215
+ **Default value:** —
216
+
217
+ #### 2. matchTo
218
+
219
+ Sets which side of the breakpoint the match is made on. The property is optional.
220
+
221
+ **Type:** `'min' | 'max' | undefined`
222
+
223
+ **Default value:** `'min'`
224
+
225
+ #### 3. isDefaultMatches
226
+
227
+ Default match value that determines the match until handlers are initialized. The property is optional.
228
+
229
+ **Type:** `boolean | undefined`
230
+
231
+ **Default value:** `true`
232
+
233
+ #### 4. children
234
+
235
+ Child elements. The property is required.
236
+
237
+ **Type:** `ReactNode`
238
+
239
+ **Default value:** —
240
+
241
+ #### 5. as
242
+
243
+ Specifies which element the current `Breakpoint` should be rendered as. Once specified, props for a specified element can be passed. The property is optional.
244
+
245
+ **Type:** `ElementType | undefined`
246
+
247
+ **Default value:** `Fragment`
248
+
249
+ # Hooks
250
+
251
+ ## useBreakpoint
252
+
253
+ Checks whether the breakpoint matches the current screen size.
254
+
255
+ ### Usage:
256
+
257
+ Example:
258
+
259
+ ```tsx
260
+ import { useBreakpoint } from 'match-breakpoint';
261
+
262
+ const Content: FC = () => {
263
+ const isDesktop = useBreakpoint('md');
264
+
265
+ return isDesktop ? 'Desktop Device Content' : 'Mobile Device Content';
266
+ };
267
+ ```
268
+
269
+ ### Parameters
270
+
271
+ #### 1. size
272
+
273
+ The breakpoint size specified when setting the `breakpoints` property in the `BreakpointsProvider` component. The parameter is required.
274
+
275
+ **Type:** `ScreenSize`
276
+
277
+ **Default value:** —
278
+
279
+ #### 2. matchTo
280
+
281
+ Sets which side of the breakpoint the match is made on. The parameter is optional.
282
+
283
+ **Type:** `'min' | 'max' | undefined`
284
+
285
+ **Default value:** `'min'`
286
+
287
+ #### 3. defaultValue
288
+
289
+ Default match value that determines the match until handlers are initialized. The parameter is optional.
290
+
291
+ **Type:** `boolean | undefined`
292
+
293
+ **Default value:** `true`
294
+
295
+ # Typing through an application
296
+
297
+ You can typify breakpoint names and values by extending the `Breakpoints` interface:
298
+
299
+ ```tsx
300
+ declare module 'match-breakpoint' {
301
+ interface Breakpoints {
302
+ sm: BreakpointData;
303
+ md: BreakpointData;
304
+ }
305
+ }
306
+ ```
307
+
308
+ Then, when using the `BreakpointProvider` and `Breakpoint` components and the `useBreakpoint` hook, this typing will be applied to their properties and parameters:
309
+
310
+ ```tsx
311
+ const Content: FC = () => {
312
+ const isDesktop = useBreakpoint('lg'); // ⛔️ TypeError: Type '"lg"' is not assignable to type '"sm" | "md"'
313
+
314
+ // ⛔️ TypeError: Type '"lg"' is not assignable to type '"sm" | "md"'
315
+ return <Breakpoint size="lg">{/* … */}</Breakpoint>;
316
+ };
317
+ ```
@@ -0,0 +1,23 @@
1
+ import { type ComponentPropsWithoutRef, type ElementType, type ExoticComponent, type FC, Fragment, type LegacyRef, type ReactNode } from 'react';
2
+ import { type MatchTo, type ScreenSize } from '../../types/breakpoints';
3
+ type FragmentFC = typeof Fragment;
4
+ type ExtendedElementType = ElementType | ExoticComponent;
5
+ type BreakpointHTMLElement<TElement extends ElementType> = TElement extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[TElement] : HTMLElement;
6
+ type BreakpointLegacyRef<TElement extends ElementType> = LegacyRef<BreakpointHTMLElement<TElement>>;
7
+ type BreakpointControlledProps<TElement extends ElementType> = {
8
+ as?: TElement;
9
+ size: ScreenSize;
10
+ matchTo?: MatchTo;
11
+ isDefaultMatches?: boolean;
12
+ children: ReactNode;
13
+ };
14
+ type BreakpointNativeProps<TElement extends ExtendedElementType> = TElement extends ExoticComponent ? ComponentPropsWithoutRef<TElement> : Omit<ComponentPropsWithoutRef<TElement>, keyof BreakpointControlledProps<TElement>>;
15
+ type BreakpointProps<TElement extends ElementType> = BreakpointNativeProps<TElement> & BreakpointControlledProps<TElement>;
16
+ type BreakpointPropsWithRef<TElement extends ElementType> = BreakpointProps<TElement> & {
17
+ ref?: BreakpointLegacyRef<TElement>;
18
+ };
19
+ interface BreakpointFunctionComponent extends FC {
20
+ <TElement extends ElementType = FragmentFC>(props: BreakpointPropsWithRef<TElement>): ReactNode;
21
+ }
22
+ declare const Breakpoint: BreakpointFunctionComponent;
23
+ export { Breakpoint };
@@ -52,12 +52,22 @@ function _object_spread_props(target, source) {
52
52
  }
53
53
  function _object_without_properties(source, excluded) {
54
54
  if (source == null) return {};
55
- var target = _object_without_properties_loose(source, excluded);
56
- var key, i;
55
+ var target = {}, sourceKeys, key, i;
56
+ if (typeof Reflect !== "undefined" && Reflect.ownKeys) {
57
+ sourceKeys = Reflect.ownKeys(source);
58
+ for(i = 0; i < sourceKeys.length; i++){
59
+ key = sourceKeys[i];
60
+ if (excluded.indexOf(key) >= 0) continue;
61
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
62
+ target[key] = source[key];
63
+ }
64
+ return target;
65
+ }
66
+ target = _object_without_properties_loose(source, excluded);
57
67
  if (Object.getOwnPropertySymbols) {
58
- var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
59
- for(i = 0; i < sourceSymbolKeys.length; i++){
60
- key = sourceSymbolKeys[i];
68
+ sourceKeys = Object.getOwnPropertySymbols(source);
69
+ for(i = 0; i < sourceKeys.length; i++){
70
+ key = sourceKeys[i];
61
71
  if (excluded.indexOf(key) >= 0) continue;
62
72
  if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
63
73
  target[key] = source[key];
@@ -67,12 +77,11 @@ function _object_without_properties(source, excluded) {
67
77
  }
68
78
  function _object_without_properties_loose(source, excluded) {
69
79
  if (source == null) return {};
70
- var target = {};
71
- var sourceKeys = Object.keys(source);
72
- var key, i;
80
+ var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
73
81
  for(i = 0; i < sourceKeys.length; i++){
74
82
  key = sourceKeys[i];
75
83
  if (excluded.indexOf(key) >= 0) continue;
84
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
76
85
  target[key] = source[key];
77
86
  }
78
87
  return target;
@@ -80,17 +89,16 @@ function _object_without_properties_loose(source, excluded) {
80
89
  import { jsx as _jsx } from "react/jsx-runtime";
81
90
  import { Children, forwardRef, Fragment } from "react";
82
91
  import { BreakpointChild } from "./BreakpointChild";
83
- import { useMatchBreakpoint } from "../BreakpointsProvider";
84
- const DEFAULT_COMPONENT = Fragment;
85
- const BreakpointRenderFunction = (props, ref)=>{
86
- const { as = DEFAULT_COMPONENT, size, matchTo = 'min', isDefaultMatches = true, children } = props, componentProps = _object_without_properties(props, [
92
+ import { useBreakpoint } from "../BreakpointsProvider";
93
+ const _Breakpoint = (props, ref)=>{
94
+ const { as = Fragment, size, matchTo = 'min', isDefaultMatches = true, children } = props, componentProps = _object_without_properties(props, [
87
95
  "as",
88
96
  "size",
89
97
  "matchTo",
90
98
  "isDefaultMatches",
91
99
  "children"
92
100
  ]);
93
- const shouldRenderChildren = useMatchBreakpoint(size, matchTo, isDefaultMatches);
101
+ const shouldRenderChildren = useBreakpoint(size, matchTo, isDefaultMatches);
94
102
  if (!shouldRenderChildren) return null;
95
103
  return Children.map(children, (child)=>/*#__PURE__*/ _jsx(BreakpointChild, _object_spread_props(_object_spread({}, componentProps), {
96
104
  ref: ref,
@@ -100,4 +108,5 @@ const BreakpointRenderFunction = (props, ref)=>{
100
108
  child: child
101
109
  })));
102
110
  };
103
- export const Breakpoint = /*#__PURE__*/ forwardRef(BreakpointRenderFunction);
111
+ const Breakpoint = /*#__PURE__*/ forwardRef(_Breakpoint);
112
+ export { Breakpoint };
@@ -0,0 +1,21 @@
1
+ import { type ComponentPropsWithoutRef, type ElementType, type ExoticComponent, type FC, type LegacyRef, type ReactNode } from 'react';
2
+ import { type MatchTo, type ScreenSize } from '../../types/breakpoints';
3
+ type ExtendedElementType = ElementType | ExoticComponent;
4
+ type BreakpointChildHTMLElement<TElement extends ElementType> = TElement extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[TElement] : HTMLElement;
5
+ type BreakpointChildLegacyRef<TElement extends ElementType> = LegacyRef<BreakpointChildHTMLElement<TElement>>;
6
+ type BreakpointChildControlledProps<TElement extends ElementType> = {
7
+ as: TElement;
8
+ size: ScreenSize;
9
+ matchTo: MatchTo;
10
+ child: ReactNode;
11
+ };
12
+ type BreakpointChildNativeProps<TElement extends ExtendedElementType> = TElement extends ExoticComponent ? ComponentPropsWithoutRef<TElement> : Omit<ComponentPropsWithoutRef<TElement>, keyof BreakpointChildControlledProps<TElement>>;
13
+ type BreakpointChildProps<TElement extends ElementType> = BreakpointChildNativeProps<TElement> & BreakpointChildControlledProps<TElement>;
14
+ type BreakpointChildPropsWithRef<TElement extends ElementType> = BreakpointChildProps<TElement> & {
15
+ ref?: BreakpointChildLegacyRef<TElement>;
16
+ };
17
+ interface BreakpointChildFunctionComponent extends FC {
18
+ <TElement extends ElementType>(props: BreakpointChildPropsWithRef<TElement>): ReactNode;
19
+ }
20
+ declare const BreakpointChild: BreakpointChildFunctionComponent;
21
+ export { BreakpointChild };
@@ -52,12 +52,22 @@ function _object_spread_props(target, source) {
52
52
  }
53
53
  function _object_without_properties(source, excluded) {
54
54
  if (source == null) return {};
55
- var target = _object_without_properties_loose(source, excluded);
56
- var key, i;
55
+ var target = {}, sourceKeys, key, i;
56
+ if (typeof Reflect !== "undefined" && Reflect.ownKeys) {
57
+ sourceKeys = Reflect.ownKeys(source);
58
+ for(i = 0; i < sourceKeys.length; i++){
59
+ key = sourceKeys[i];
60
+ if (excluded.indexOf(key) >= 0) continue;
61
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
62
+ target[key] = source[key];
63
+ }
64
+ return target;
65
+ }
66
+ target = _object_without_properties_loose(source, excluded);
57
67
  if (Object.getOwnPropertySymbols) {
58
- var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
59
- for(i = 0; i < sourceSymbolKeys.length; i++){
60
- key = sourceSymbolKeys[i];
68
+ sourceKeys = Object.getOwnPropertySymbols(source);
69
+ for(i = 0; i < sourceKeys.length; i++){
70
+ key = sourceKeys[i];
61
71
  if (excluded.indexOf(key) >= 0) continue;
62
72
  if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
63
73
  target[key] = source[key];
@@ -67,89 +77,81 @@ function _object_without_properties(source, excluded) {
67
77
  }
68
78
  function _object_without_properties_loose(source, excluded) {
69
79
  if (source == null) return {};
70
- var target = {};
71
- var sourceKeys = Object.keys(source);
72
- var key, i;
80
+ var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
73
81
  for(i = 0; i < sourceKeys.length; i++){
74
82
  key = sourceKeys[i];
75
83
  if (excluded.indexOf(key) >= 0) continue;
84
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
76
85
  target[key] = source[key];
77
86
  }
78
87
  return target;
79
88
  }
80
89
  import { jsx as _jsx } from "react/jsx-runtime";
81
90
  import { cloneElement, forwardRef, Fragment, isValidElement } from "react";
82
- import { getMaxScreenWidth, getMinScreenWidth } from "../../utils/screen-width";
91
+ import { ensurePx } from "../../utils/screen-width";
83
92
  import { useBreakpointsContext } from "../BreakpointsProvider/BreakpointsProvider";
84
- const DEFAULT_COMPONENT = Fragment;
85
93
  const CLASS_NAME_PRESETS = {
86
94
  tailwind: {
87
- maxClassName: 'min-[var(--max-screen-width)]:hidden',
88
- minClassName: 'max-[var(--min-screen-width)]:hidden'
95
+ maxClassName: 'min-[var(--breakpoint)]:hidden',
96
+ minClassName: 'max-[var(--breakpoint)]:hidden'
89
97
  }
90
98
  };
91
- const buildProps = (options)=>{
92
- const { ref, initialProps, matchTo, breakpoint, classNamePreset, mergeClassesFunction } = options;
93
- const classNamePresetData = classNamePreset !== undefined ? CLASS_NAME_PRESETS[classNamePreset] : null;
94
- if (matchTo === 'max') {
95
- var _breakpoint_data_maxClassName;
96
- return _object_spread_props(_object_spread({}, initialProps), {
97
- ref,
98
- style: _object_spread_props(_object_spread({}, initialProps === null || initialProps === void 0 ? void 0 : initialProps.style), {
99
- ['--max-screen-width']: getMaxScreenWidth(breakpoint.data)
100
- }),
101
- className: mergeClassesFunction(initialProps === null || initialProps === void 0 ? void 0 : initialProps.className, typeof breakpoint.data === 'object' ? (_breakpoint_data_maxClassName = breakpoint.data.maxClassName) !== null && _breakpoint_data_maxClassName !== void 0 ? _breakpoint_data_maxClassName : classNamePresetData === null || classNamePresetData === void 0 ? void 0 : classNamePresetData.maxClassName : classNamePresetData === null || classNamePresetData === void 0 ? void 0 : classNamePresetData.maxClassName)
102
- });
103
- }
104
- var _breakpoint_data_minClassName;
99
+ const buildComponentProps = (options)=>{
100
+ const { ref, initialProps, matchTo, breakpoint, cssPreset, mergeClassesFunction } = options;
101
+ const preset = cssPreset ? CLASS_NAME_PRESETS[cssPreset] : null;
102
+ const presetKey = `${matchTo}ClassName`;
103
+ const className = typeof breakpoint.data === 'object' ? breakpoint.data[presetKey] || (preset === null || preset === void 0 ? void 0 : preset[presetKey]) : preset === null || preset === void 0 ? void 0 : preset[presetKey];
105
104
  return _object_spread_props(_object_spread({}, initialProps), {
106
105
  ref,
107
106
  style: _object_spread_props(_object_spread({}, initialProps === null || initialProps === void 0 ? void 0 : initialProps.style), {
108
- ['--min-screen-width']: getMinScreenWidth(breakpoint.data)
107
+ ['--breakpoint']: ensurePx(breakpoint.data)
109
108
  }),
110
- className: mergeClassesFunction(initialProps === null || initialProps === void 0 ? void 0 : initialProps.className, typeof breakpoint.data === 'object' ? (_breakpoint_data_minClassName = breakpoint.data.minClassName) !== null && _breakpoint_data_minClassName !== void 0 ? _breakpoint_data_minClassName : classNamePresetData === null || classNamePresetData === void 0 ? void 0 : classNamePresetData.minClassName : classNamePresetData === null || classNamePresetData === void 0 ? void 0 : classNamePresetData.minClassName)
109
+ className: mergeClassesFunction(initialProps === null || initialProps === void 0 ? void 0 : initialProps.className, className)
111
110
  });
112
111
  };
113
- const BreakpointChildRenderFunction = (props, ref)=>{
114
- const { as: Component = DEFAULT_COMPONENT, size, matchTo, child } = props, componentProps = _object_without_properties(props, [
112
+ const _BreakpointChild = (props, ref)=>{
113
+ const context = useBreakpointsContext();
114
+ const { as: Component, size, matchTo, child } = props, componentProps = _object_without_properties(props, [
115
115
  "as",
116
116
  "size",
117
117
  "matchTo",
118
118
  "child"
119
119
  ]);
120
- const { breakpoints, classNamePreset, mergeClassesFunction } = useBreakpointsContext();
120
+ const { breakpoints, cssPreset, mergeClassesFunction } = context;
121
121
  const breakpoint = breakpoints[size];
122
122
  if (!breakpoint) {
123
123
  throw new Error(`Breakpoint with screen size "${size}" is not defined`);
124
124
  }
125
125
  if (Component === Fragment && /*#__PURE__*/ isValidElement(child)) {
126
- return /*#__PURE__*/ cloneElement(child, buildProps({
126
+ return /*#__PURE__*/ cloneElement(child, buildComponentProps({
127
127
  initialProps: child.props,
128
128
  matchTo,
129
129
  breakpoint,
130
- classNamePreset,
130
+ cssPreset,
131
131
  mergeClassesFunction
132
132
  }));
133
133
  }
134
134
  if (Component !== Fragment) {
135
- return /*#__PURE__*/ _jsx(Component, _object_spread_props(_object_spread({}, buildProps({
136
- initialProps: componentProps,
135
+ return /*#__PURE__*/ _jsx(Component, _object_spread({}, buildComponentProps({
136
+ initialProps: _object_spread_props(_object_spread({}, componentProps), {
137
+ children: child
138
+ }),
137
139
  ref,
138
140
  matchTo,
139
141
  breakpoint,
140
- classNamePreset,
142
+ cssPreset,
141
143
  mergeClassesFunction
142
- })), {
143
- children: child
144
- }));
144
+ })));
145
145
  }
146
- return /*#__PURE__*/ _jsx("div", _object_spread_props(_object_spread({}, buildProps({
146
+ return /*#__PURE__*/ _jsx("div", _object_spread({}, buildComponentProps({
147
+ initialProps: {
148
+ children: child
149
+ },
147
150
  matchTo,
148
151
  breakpoint,
149
- classNamePreset,
152
+ cssPreset,
150
153
  mergeClassesFunction
151
- })), {
152
- children: child
153
- }));
154
+ })));
154
155
  };
155
- export const BreakpointChild = /*#__PURE__*/ forwardRef(BreakpointChildRenderFunction);
156
+ const BreakpointChild = /*#__PURE__*/ forwardRef(_BreakpointChild);
157
+ export { BreakpointChild };
@@ -0,0 +1 @@
1
+ export { Breakpoint } from '../../components/Breakpoint/Breakpoint';
@@ -0,0 +1 @@
1
+ export { Breakpoint } from "./Breakpoint";
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from "react";
3
- import { getMinScreenWidth } from "../../utils/screen-width";
3
+ import { ensurePx } from "../../utils/screen-width";
4
4
  export const DEFAULT_BREAKPOINT_CONTEXT = {
5
5
  isMatches: null
6
6
  };
@@ -8,7 +8,7 @@ export const BreakpointProvider = (props)=>{
8
8
  const { breakpoint, children } = props;
9
9
  const { Provider } = breakpoint.context;
10
10
  const [isMatches, setIsMatches] = useState(DEFAULT_BREAKPOINT_CONTEXT.isMatches);
11
- const minScreenWidth = getMinScreenWidth(breakpoint.data);
11
+ const minScreenWidth = ensurePx(breakpoint.data);
12
12
  useEffect(()=>{
13
13
  const media = window.matchMedia(`(min-width: ${minScreenWidth})`);
14
14
  setIsMatches(media.matches);
@@ -22,13 +22,13 @@ export const BreakpointProvider = (props)=>{
22
22
  }, [
23
23
  minScreenWidth
24
24
  ]);
25
- const value = useMemo(()=>({
25
+ const context = useMemo(()=>({
26
26
  isMatches
27
27
  }), [
28
28
  isMatches
29
29
  ]);
30
30
  return /*#__PURE__*/ _jsx(Provider, {
31
- value: value,
31
+ value: context,
32
32
  children: children
33
33
  });
34
34
  };
@@ -1,20 +1,20 @@
1
1
  import { type FC, type ReactNode } from 'react';
2
2
  import { type Breakpoints, type MatchTo, type ScreenSize } from '../../types/breakpoints';
3
- import { type ClassNamePreset, type MergeClassesFunction } from '../../types/styles';
3
+ import { type CSSPresetName, type MergeClassesFunction } from '../../types/styles';
4
4
  import { type ContextualizedBreakpointData } from '../../components/BreakpointsProvider/BreakpointProvider';
5
5
  type ContextualizedBreakpoints = Record<ScreenSize, ContextualizedBreakpointData>;
6
6
  type BreakpointsContext = {
7
7
  breakpoints: ContextualizedBreakpoints;
8
- classNamePreset?: ClassNamePreset;
8
+ cssPreset?: CSSPresetName;
9
9
  mergeClassesFunction: MergeClassesFunction;
10
10
  };
11
11
  type BreakpointsProviderProps = {
12
12
  breakpoints: Breakpoints;
13
- classNamePreset?: ClassNamePreset;
13
+ cssPreset?: CSSPresetName;
14
14
  children: ReactNode;
15
15
  mergeClassesFunction?: MergeClassesFunction;
16
16
  };
17
17
  export declare const useBreakpointsContext: () => BreakpointsContext;
18
- export declare const useMatchBreakpoint: (size: ScreenSize, matchTo?: MatchTo, defaultValue?: boolean) => boolean;
19
- export declare const MatchBreakpointProvider: FC<BreakpointsProviderProps>;
18
+ export declare const useBreakpoint: (size: ScreenSize, matchTo?: MatchTo, defaultValue?: boolean) => boolean;
19
+ export declare const BreakpointsProvider: FC<BreakpointsProviderProps>;
20
20
  export {};
@@ -59,7 +59,7 @@ const DEFAULT_BREAKPOINTS_CONTEXT = {
59
59
  };
60
60
  const BreakpointsContextInstance = /*#__PURE__*/ createContext(DEFAULT_BREAKPOINTS_CONTEXT);
61
61
  export const useBreakpointsContext = ()=>useContext(BreakpointsContextInstance);
62
- export const useMatchBreakpoint = (size, matchTo = 'min', defaultValue = false)=>{
62
+ export const useBreakpoint = (size, matchTo = 'min', defaultValue = false)=>{
63
63
  const { breakpoints } = useBreakpointsContext();
64
64
  const breakpoint = breakpoints[size];
65
65
  if (!breakpoint) {
@@ -69,26 +69,26 @@ export const useMatchBreakpoint = (size, matchTo = 'min', defaultValue = false)=
69
69
  if (isMatches === null) return defaultValue;
70
70
  return matchTo === 'min' ? isMatches : !isMatches;
71
71
  };
72
- export const MatchBreakpointProvider = (props)=>{
73
- const { breakpoints, classNamePreset, children, mergeClassesFunction = DEFAULT_BREAKPOINTS_CONTEXT.mergeClassesFunction } = props;
74
- const value = useMemo(()=>({
72
+ export const BreakpointsProvider = (props)=>{
73
+ const { breakpoints, cssPreset, children, mergeClassesFunction = DEFAULT_BREAKPOINTS_CONTEXT.mergeClassesFunction } = props;
74
+ const context = useMemo(()=>({
75
75
  breakpoints: Object.keys(breakpoints).reduce((acc, key)=>_object_spread_props(_object_spread({}, acc), {
76
76
  [key]: {
77
77
  data: breakpoints[key],
78
78
  context: /*#__PURE__*/ createContext(_object_spread({}, DEFAULT_BREAKPOINT_CONTEXT))
79
79
  }
80
80
  }), {}),
81
- classNamePreset,
81
+ cssPreset,
82
82
  mergeClassesFunction
83
83
  }), [
84
84
  breakpoints,
85
- classNamePreset,
85
+ cssPreset,
86
86
  mergeClassesFunction
87
87
  ]);
88
88
  return /*#__PURE__*/ _jsx(BreakpointsContextInstance.Provider, {
89
- value: value,
90
- children: Object.keys(value.breakpoints).reduce((acc, size)=>/*#__PURE__*/ _jsx(BreakpointProvider, {
91
- breakpoint: value.breakpoints[size],
89
+ value: context,
90
+ children: Object.keys(context.breakpoints).reduce((acc, size)=>/*#__PURE__*/ _jsx(BreakpointProvider, {
91
+ breakpoint: context.breakpoints[size],
92
92
  children: acc
93
93
  }), children)
94
94
  });
@@ -0,0 +1 @@
1
+ export { BreakpointsProvider, useBreakpoint, } from '../../components/BreakpointsProvider/BreakpointsProvider';
@@ -0,0 +1 @@
1
+ export { BreakpointsProvider, useBreakpoint } from "./BreakpointsProvider";
@@ -0,0 +1,3 @@
1
+ export * from './components/Breakpoint';
2
+ export * from './components/BreakpointsProvider';
3
+ export { type BreakpointData, type Breakpoints } from './types/breakpoints';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./components/Breakpoint";
2
+ export * from "./components/BreakpointsProvider";
@@ -0,0 +1,10 @@
1
+ export type MatchTo = 'min' | 'max';
2
+ export type BreakpointDataDetails = {
3
+ value: string | number;
4
+ minClassName?: string;
5
+ maxClassName?: string;
6
+ };
7
+ export type BreakpointData = number | string | BreakpointDataDetails;
8
+ export interface Breakpoints {
9
+ }
10
+ export type ScreenSize = keyof Breakpoints extends never ? string : keyof Breakpoints;
@@ -0,0 +1,6 @@
1
+ export type CSSPresetName = 'tailwind';
2
+ type ClassDictionary = Record<string, unknown>;
3
+ type ClassArray = ClassValue[];
4
+ type ClassValue = ClassArray | ClassDictionary | string | number | null | boolean | undefined;
5
+ export type MergeClassesFunction = (...classes: ClassValue[]) => string;
6
+ export {};
@@ -0,0 +1,2 @@
1
+ import { type BreakpointData } from '../types/breakpoints';
2
+ export declare const ensurePx: (data: BreakpointData) => string;
@@ -0,0 +1,6 @@
1
+ export const ensurePx = (data)=>{
2
+ if (typeof data === 'string') return data;
3
+ if (typeof data === 'number') return `${data}px`;
4
+ if (typeof data.value === 'string') return data.value;
5
+ return `${data.value}px`;
6
+ };
package/package.json CHANGED
@@ -1,10 +1,18 @@
1
1
  {
2
2
  "name": "match-breakpoint",
3
- "version": "1.0.0-canary.0",
4
- "description": "",
3
+ "version": "1.0.0-canary.1",
4
+ "description": "A library of optimized React components and hooks for matching screen widths",
5
5
  "license": "MIT",
6
6
  "author": "Oleg Putseiko <oleg.putseiko@gmail.com> (https://github.com/oleg-putseiko)",
7
- "keywords": [],
7
+ "keywords": [
8
+ "react",
9
+ "typescript",
10
+ "breakpoint",
11
+ "media-query",
12
+ "match-media",
13
+ "performance",
14
+ "tailwindcss"
15
+ ],
8
16
  "homepage": "https://github.com/oleg-putseiko/match-breakpoint",
9
17
  "repository": {
10
18
  "type": "git",
@@ -13,32 +21,41 @@
13
21
  "bugs": {
14
22
  "url": "https://github.com/oleg-putseiko/match-breakpoint/issues"
15
23
  },
16
- "main": "dist/src/index.js",
24
+ "main": "dist/index.js",
17
25
  "files": [
18
- "dist/src/components/**/*",
19
- "dist/src/utils/**/*",
20
- "dist/src/index.js"
26
+ "dist/components/**/*.d.ts",
27
+ "dist/components/**/*.js",
28
+ "dist/types/**/*.d.ts",
29
+ "dist/utils/**/*.d.ts",
30
+ "dist/utils/**/*.js",
31
+ "dist/index.d.ts",
32
+ "dist/index.js"
21
33
  ],
22
- "exports": "./dist/src/index.js",
34
+ "exports": "./dist/index.js",
23
35
  "scripts": {
24
- "build": "swc ./src/**/* -d dist && tsc --emitDeclarationOnly && tsc-alias",
36
+ "build": "swc src -d dist --strip-leading-paths && tsc --emitDeclarationOnly && tsc-alias",
25
37
  "format": "prettier -c .",
26
38
  "format:fix": "prettier -w .",
27
39
  "lint": "eslint ./src/**/*.{js,ts,tsx,json}",
28
40
  "lint:fix": "eslint ./src/**/*.{js,ts,tsx,json} --fix && yarn format:fix",
29
41
  "lint:strict": "eslint ./src/**/*.{js,ts,tsx,json} --max-warnings=0 && yarn format",
30
42
  "prepare": "husky install | chmod +x ./.husky/*",
31
- "test": "jest",
32
43
  "typecheck": "tsc --noEmit --incremental false"
33
44
  },
34
45
  "peerDependencies": {
35
- "react": "^18.2.0",
36
- "react-dom": "^18.2.0"
46
+ "react": ">=18.2.0",
47
+ "react-dom": ">=18.2.0",
48
+ "tailwindcss": ">=3.2.0"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "tailwindcss": {
52
+ "optional": true
53
+ }
37
54
  },
38
55
  "devDependencies": {
39
56
  "@commitlint/cli": "^18.2.0",
40
57
  "@commitlint/config-conventional": "^18.1.0",
41
- "@swc/cli": "^0.5.1",
58
+ "@swc/cli": "^0.5.2",
42
59
  "@swc/core": "^1.9.3",
43
60
  "@types/react": "^18.0.0",
44
61
  "@typescript-eslint/eslint-plugin": "^6.9.1",
@@ -57,8 +74,8 @@
57
74
  "typescript": "~5.2.2"
58
75
  },
59
76
  "engines": {
60
- "node": "18.18.0",
61
- "yarn": "3.6.4"
77
+ "node": ">=18.18.0",
78
+ "yarn": "^3.6.4"
62
79
  },
63
80
  "volta": {
64
81
  "node": "18.18.0",
@@ -1,17 +0,0 @@
1
- import { type ComponentPropsWithoutRef, type ElementType, type ReactNode } from 'react';
2
- import { type Breakpoints, type MatchTo, type ScreenSize } from '../../types/breakpoints';
3
- import { type ExtractRef } from '../../types/react';
4
- type BreakpointControlledProps<T extends ElementType> = {
5
- as?: T;
6
- size: ScreenSize;
7
- breakpoints?: Breakpoints;
8
- matchTo?: MatchTo;
9
- isDefaultMatches?: boolean;
10
- children: ReactNode;
11
- };
12
- type BreakpointComponentNativeProps<T extends ElementType> = Omit<ComponentPropsWithoutRef<T>, keyof BreakpointControlledProps<T>>;
13
- type BreakpointProps<T extends ElementType> = BreakpointComponentNativeProps<T> & BreakpointControlledProps<T>;
14
- export declare const Breakpoint: <T extends ElementType = import("react").ExoticComponent<{
15
- children?: ReactNode;
16
- }>>(props: BreakpointProps<T>, ref: ExtractRef<BreakpointComponentNativeProps<T>>) => import("react/jsx-runtime").JSX.Element[] | null | undefined;
17
- export {};
@@ -1,15 +0,0 @@
1
- import { type ComponentProps, type ElementType, type ReactNode } from 'react';
2
- import { type MatchTo, type ScreenSize } from '../../types/breakpoints';
3
- import { type ExtractRef } from '../../types/react';
4
- type ControlledProps<E extends ElementType> = {
5
- as?: E;
6
- size: ScreenSize;
7
- matchTo: MatchTo;
8
- child: ReactNode;
9
- };
10
- type ComponentNativeProps<E extends ElementType> = Omit<ComponentProps<E>, 'children' | keyof ControlledProps<E>>;
11
- type TailwindBreakpointProps<E extends ElementType> = ComponentNativeProps<E> & ControlledProps<E>;
12
- export declare const BreakpointChild: <T extends ElementType = import("react").ExoticComponent<{
13
- children?: ReactNode;
14
- }>>(props: TailwindBreakpointProps<T>, ref: ExtractRef<ComponentNativeProps<T>>) => import("react/jsx-runtime").JSX.Element;
15
- export {};
@@ -1 +0,0 @@
1
- export * from '../../components/Breakpoint/Breakpoint';
@@ -1 +0,0 @@
1
- export * from "./Breakpoint";
@@ -1 +0,0 @@
1
- export * from '../../components/BreakpointsProvider/BreakpointsProvider';
@@ -1 +0,0 @@
1
- export * from "./BreakpointsProvider";
@@ -1,3 +0,0 @@
1
- import { type BreakpointData } from '../types/breakpoints';
2
- export declare const getMaxScreenWidth: (breakpointData: BreakpointData) => string;
3
- export declare const getMinScreenWidth: (breakpointData: BreakpointData) => string;
@@ -1,12 +0,0 @@
1
- export const getMaxScreenWidth = (breakpointData)=>{
2
- if (typeof breakpointData === 'string') return breakpointData;
3
- if (typeof breakpointData === 'number') return `${breakpointData}px`;
4
- if (typeof breakpointData.max === 'string') return breakpointData.max;
5
- return `${breakpointData.max}px`;
6
- };
7
- export const getMinScreenWidth = (breakpointData)=>{
8
- if (typeof breakpointData === 'string') return breakpointData;
9
- if (typeof breakpointData === 'number') return `${breakpointData}px`;
10
- if (typeof breakpointData.min === 'string') return breakpointData.min;
11
- return `${breakpointData.min}px`;
12
- };