@skyscanner/backpack-web 42.10.0-dev-v24496611676.1 → 42.11.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.
Files changed (31) hide show
  1. package/bpk-component-bottom-sheet/src/BpkBottomSheet.js +1 -0
  2. package/bpk-component-layout/index.d.ts +0 -4
  3. package/bpk-component-layout/index.js +0 -2
  4. package/bpk-component-layout/src/BpkBox.js +13 -16
  5. package/bpk-component-layout/src/BpkFlex.js +9 -20
  6. package/bpk-component-layout/src/BpkGrid.js +9 -20
  7. package/bpk-component-layout/src/BpkGridItem.js +15 -23
  8. package/bpk-component-layout/src/BpkProvider.d.ts +10 -7
  9. package/bpk-component-layout/src/BpkProvider.js +98 -12
  10. package/bpk-component-layout/src/BpkStack.constant.js +2 -3
  11. package/bpk-component-layout/src/BpkStack.js +40 -89
  12. package/bpk-component-layout/src/commonProps.d.ts +1 -8
  13. package/bpk-component-layout/src/theme.d.ts +1 -0
  14. package/bpk-component-layout/src/theme.js +301 -27
  15. package/bpk-component-layout/src/tokenUtils.js +11 -34
  16. package/bpk-component-layout/src/types.d.ts +147 -84
  17. package/bpk-component-navigation-bar/src/BpkNavigationBar.d.ts +3 -0
  18. package/bpk-component-navigation-bar/src/BpkNavigationBar.js +2 -1
  19. package/bpk-component-navigation-bar/src/BpkNavigationBar.module.css +1 -1
  20. package/bpk-component-page-indicator/src/NavButton.js +3 -3
  21. package/package.json +3 -2
  22. package/bpk-component-layout/src/BpkArkProvider.d.ts +0 -20
  23. package/bpk-component-layout/src/BpkArkProvider.js +0 -112
  24. package/bpk-component-layout/src/BpkLayoutProvider.d.ts +0 -18
  25. package/bpk-component-layout/src/BpkLayoutProvider.js +0 -36
  26. package/bpk-component-layout/src/resolveTextStyle.d.ts +0 -13
  27. package/bpk-component-layout/src/resolveTextStyle.js +0 -265
  28. package/bpk-component-layout/src/responsiveStyleBuilder.d.ts +0 -22
  29. package/bpk-component-layout/src/responsiveStyleBuilder.js +0 -152
  30. package/bpk-component-layout/src/useCurrentBreakpoint.d.ts +0 -9
  31. package/bpk-component-layout/src/useCurrentBreakpoint.js +0 -89
@@ -1,265 +0,0 @@
1
- /*
2
- * Backpack - Skyscanner's Design System
3
- *
4
- * Copyright 2016 Skyscanner Ltd
5
- *
6
- * Licensed under the Apache License, Version 2.0 (the "License");
7
- * you may not use this file except in compliance with the License.
8
- * You may obtain a copy of the License at
9
- *
10
- * http://www.apache.org/licenses/LICENSE-2.0
11
- *
12
- * Unless required by applicable law or agreed to in writing, software
13
- * distributed under the License is distributed on an "AS IS" BASIS,
14
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- * See the License for the specific language governing permissions and
16
- * limitations under the License.
17
- */
18
-
19
- // Import only the specific tokens needed for text styles, rather than the
20
- // entire foundations module. This avoids pulling unused tokens (colors,
21
- // shadows, borders, etc.) into the layout bundle.
22
- import { fontSizeXs, fontSizeSm, fontSizeBase, fontSizeLg, fontSizeXl, fontSizeXxl, fontSizeXxxl, fontSizeXxxxl, fontSizeXxxxxl, fontSize6Xl, fontSize7Xl, fontSize8Xl, lineHeightXs, lineHeightSm, lineHeightBase, lineHeightBaseTight, lineHeightLg, lineHeightLgTight, lineHeightXl, lineHeightXlTight, lineHeightXxl, lineHeightXxxl, lineHeightXxxxl, lineHeightXxxxxl, lineHeight6Xl, lineHeight7Xl, lineHeight8Xl, fontWeightBook, fontWeightBold, fontWeightBlack, fontWeightLight, letterSpacingTight, letterSpacingHero, fontFamilyLarken } from '@skyscanner/bpk-foundations-web/tokens/base.es6';
23
- import { BpkBreakpointToChakraKey } from "./tokens";
24
- /**
25
- * Maps Backpack text style tokens to concrete CSS properties.
26
- *
27
- * This map is intentionally kept outside the Chakra theme config so that
28
- * layout-only consumers (who never use textStyle) do not pay for it.
29
- * Components that use textStyle expand it inline via `expandTextStyleProps`.
30
- */
31
- const TEXT_STYLE_MAP = {
32
- xs: {
33
- fontSize: fontSizeXs,
34
- lineHeight: lineHeightXs,
35
- fontWeight: fontWeightBook
36
- },
37
- sm: {
38
- fontSize: fontSizeSm,
39
- lineHeight: lineHeightSm,
40
- fontWeight: fontWeightBook
41
- },
42
- base: {
43
- fontSize: fontSizeBase,
44
- lineHeight: lineHeightBase,
45
- fontWeight: fontWeightBook
46
- },
47
- lg: {
48
- fontSize: fontSizeLg,
49
- lineHeight: lineHeightLg,
50
- fontWeight: fontWeightBook
51
- },
52
- xl: {
53
- fontSize: fontSizeXl,
54
- lineHeight: lineHeightXl,
55
- fontWeight: fontWeightBook
56
- },
57
- xxl: {
58
- fontSize: fontSizeXxl,
59
- lineHeight: lineHeightXxl,
60
- fontWeight: fontWeightBold
61
- },
62
- xxxl: {
63
- fontSize: fontSizeXxxl,
64
- lineHeight: lineHeightXxxl,
65
- fontWeight: fontWeightBold
66
- },
67
- xxxxl: {
68
- fontSize: fontSizeXxxxl,
69
- lineHeight: lineHeightXxxxl,
70
- fontWeight: fontWeightBold,
71
- letterSpacing: letterSpacingTight
72
- },
73
- xxxxxl: {
74
- fontSize: fontSizeXxxxxl,
75
- lineHeight: lineHeightXxxxxl,
76
- fontWeight: fontWeightBold,
77
- letterSpacing: letterSpacingTight
78
- },
79
- caption: {
80
- fontSize: fontSizeXs,
81
- lineHeight: lineHeightXs,
82
- fontWeight: fontWeightBook
83
- },
84
- footnote: {
85
- fontSize: fontSizeSm,
86
- lineHeight: lineHeightSm,
87
- fontWeight: fontWeightBook
88
- },
89
- 'label-1': {
90
- fontSize: fontSizeBase,
91
- lineHeight: lineHeightBase,
92
- fontWeight: fontWeightBold
93
- },
94
- 'label-2': {
95
- fontSize: fontSizeSm,
96
- lineHeight: lineHeightSm,
97
- fontWeight: fontWeightBold
98
- },
99
- 'label-3': {
100
- fontSize: fontSizeXs,
101
- lineHeight: lineHeightXs,
102
- fontWeight: fontWeightBold
103
- },
104
- 'body-default': {
105
- fontSize: fontSizeBase,
106
- lineHeight: lineHeightBase,
107
- fontWeight: fontWeightBook
108
- },
109
- 'body-longform': {
110
- fontSize: fontSizeLg,
111
- lineHeight: lineHeightLg,
112
- fontWeight: fontWeightBook
113
- },
114
- subheading: {
115
- fontSize: fontSizeXl,
116
- lineHeight: lineHeightXl,
117
- fontWeight: fontWeightBook
118
- },
119
- 'heading-1': {
120
- fontSize: fontSizeXxxl,
121
- lineHeight: lineHeightXxxl,
122
- fontWeight: fontWeightBold
123
- },
124
- 'heading-2': {
125
- fontSize: fontSizeXxl,
126
- lineHeight: lineHeightXxl,
127
- fontWeight: fontWeightBold
128
- },
129
- 'heading-3': {
130
- fontSize: fontSizeXl,
131
- lineHeight: lineHeightXlTight,
132
- fontWeight: fontWeightBold
133
- },
134
- 'heading-4': {
135
- fontSize: fontSizeLg,
136
- lineHeight: lineHeightLgTight,
137
- fontWeight: fontWeightBold
138
- },
139
- 'heading-5': {
140
- fontSize: fontSizeBase,
141
- lineHeight: lineHeightBaseTight,
142
- fontWeight: fontWeightBold
143
- },
144
- 'hero-1': {
145
- fontSize: fontSize8Xl,
146
- lineHeight: lineHeight8Xl,
147
- fontWeight: fontWeightBlack,
148
- letterSpacing: letterSpacingHero
149
- },
150
- 'hero-2': {
151
- fontSize: fontSize7Xl,
152
- lineHeight: lineHeight7Xl,
153
- fontWeight: fontWeightBlack,
154
- letterSpacing: letterSpacingHero
155
- },
156
- 'hero-3': {
157
- fontSize: fontSize6Xl,
158
- lineHeight: lineHeight6Xl,
159
- fontWeight: fontWeightBlack,
160
- letterSpacing: letterSpacingHero
161
- },
162
- 'hero-4': {
163
- fontSize: fontSizeXxxxxl,
164
- lineHeight: lineHeightXxxxxl,
165
- fontWeight: fontWeightBlack,
166
- letterSpacing: letterSpacingHero
167
- },
168
- 'hero-5': {
169
- fontSize: fontSizeXxxxl,
170
- lineHeight: lineHeightXxxl,
171
- fontWeight: fontWeightBlack,
172
- letterSpacing: letterSpacingHero
173
- },
174
- 'hero-6': {
175
- fontSize: fontSizeXxxl,
176
- lineHeight: lineHeightXxl,
177
- fontWeight: fontWeightBlack,
178
- letterSpacing: letterSpacingHero
179
- },
180
- 'editorial-1': {
181
- fontFamily: `var(--bpk-larken-font-stack, ${fontFamilyLarken})`,
182
- fontSize: fontSizeXxxxl,
183
- lineHeight: lineHeightXxxxl,
184
- fontWeight: fontWeightLight
185
- },
186
- 'editorial-2': {
187
- fontFamily: `var(--bpk-larken-font-stack, ${fontFamilyLarken})`,
188
- fontSize: fontSizeXxl,
189
- lineHeight: lineHeightXxl,
190
- fontWeight: fontWeightLight
191
- },
192
- 'editorial-3': {
193
- fontFamily: `var(--bpk-larken-font-stack, ${fontFamilyLarken})`,
194
- fontSize: fontSizeLg,
195
- lineHeight: lineHeightLg,
196
- fontWeight: fontWeightBook
197
- }
198
- };
199
-
200
- /**
201
- * Expands a textStyle token (or responsive object of tokens) into concrete
202
- * CSS property values that can be spread directly onto a Chakra component.
203
- *
204
- * Supports:
205
- * - Static values: `textStyle="heading-3"` → `{ fontSize, lineHeight, fontWeight }`
206
- * - Responsive objects: `textStyle={{ mobile: 'heading-5', desktop: 'heading-3' }}`
207
- * → `{ fontSize: { md: '...', '2xl': '...' }, lineHeight: { ... }, ... }`
208
- *
209
- * @param {any} value - A textStyle token string, responsive object, or undefined/null.
210
- * @returns {Record<string, any>} An object of CSS props to spread, or an empty object if no match.
211
- */
212
- // eslint-disable-next-line import/prefer-default-export
213
- export function expandTextStyleProps(value) {
214
- if (value == null) return {};
215
-
216
- // Responsive object: { mobile: 'heading-5', desktop: 'heading-3' }
217
- if (typeof value === 'object' && !Array.isArray(value)) {
218
- // Normalise Backpack breakpoint keys to Chakra keys inline (avoids
219
- // circular dependency on tokenUtils).
220
- const normalized = {};
221
- Object.entries(value).forEach(([key, val]) => {
222
- if (key === 'base') {
223
- normalized.base = val;
224
- } else {
225
- const chakraKey = BpkBreakpointToChakraKey[key];
226
- if (chakraKey) {
227
- normalized[chakraKey] = val;
228
- }
229
- }
230
- });
231
-
232
- // Pivot from { bp -> token } to { cssProp -> { bp -> cssValue } }
233
- const result = {};
234
- Object.entries(normalized).forEach(([bp, token]) => {
235
- const style = TEXT_STYLE_MAP[String(token)];
236
- if (!style) {
237
- if (process.env.NODE_ENV !== 'production') {
238
- // eslint-disable-next-line no-console
239
- console.warn(`Unknown textStyle token "${String(token)}" at breakpoint "${bp}".`);
240
- }
241
- return;
242
- }
243
- Object.entries(style).forEach(([cssProp, cssValue]) => {
244
- if (!result[cssProp]) {
245
- result[cssProp] = {};
246
- }
247
- result[cssProp][bp] = cssValue;
248
- });
249
- });
250
- return result;
251
- }
252
-
253
- // Static string value
254
- const style = TEXT_STYLE_MAP[String(value)];
255
- if (!style) {
256
- if (process.env.NODE_ENV !== 'production') {
257
- // eslint-disable-next-line no-console
258
- console.warn(`Unknown textStyle token "${String(value)}".`);
259
- }
260
- return {};
261
- }
262
- return {
263
- ...style
264
- };
265
- }
@@ -1,22 +0,0 @@
1
- import type { CSSProperties } from 'react';
2
- export type LayoutStyleOutput = {
3
- /** Inline styles (all values resolved for the current breakpoint) */
4
- style: CSSProperties & Record<string, string>;
5
- /** Non-style props to spread on the DOM element */
6
- passthrough: Record<string, any>;
7
- };
8
- /**
9
- * Converts processed layout props into an output suitable for a plain DOM element.
10
- *
11
- * - Scalar values → inline `style` properties
12
- * - Responsive objects → resolved to the current breakpoint's value via fill-forward,
13
- * then set as inline `style` properties
14
- * - Non-style props (id, role, aria-*, data-*, event handlers) → `passthrough`
15
- *
16
- * @param {Record<string, any>} processedProps - Props after token conversion and validation
17
- * by `processBpkComponentProps`. Values are already resolved to CSS values (e.g. '.5rem').
18
- * Responsive values are objects keyed by Chakra breakpoint keys (base, sm, md, lg, xl, 2xl).
19
- * @param {string} currentBreakpoint - The currently active breakpoint key from useCurrentBreakpoint
20
- * @returns {LayoutStyleOutput} Style and passthrough props.
21
- */
22
- export declare function buildLayoutOutput(processedProps: Record<string, any>, currentBreakpoint: string): LayoutStyleOutput;
@@ -1,152 +0,0 @@
1
- /*
2
- * Backpack - Skyscanner's Design System
3
- *
4
- * Copyright 2016 Skyscanner Ltd
5
- *
6
- * Licensed under the Apache License, Version 2.0 (the "License");
7
- * you may not use this file except in compliance with the License.
8
- * You may obtain a copy of the License at
9
- *
10
- * http://www.apache.org/licenses/LICENSE-2.0
11
- *
12
- * Unless required by applicable law or agreed to in writing, software
13
- * distributed under the License is distributed on an "AS IS" BASIS,
14
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- * See the License for the specific language governing permissions and
16
- * limitations under the License.
17
- */
18
-
19
- /**
20
- * All style props that participate in the layout system.
21
- * These are recognised as CSS-settable properties and will be
22
- * placed into the inline `style` object.
23
- */
24
- const STYLE_PROPS = new Set([
25
- // Spacing
26
- 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'paddingStart', 'paddingEnd', 'paddingInline', 'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'marginStart', 'marginEnd', 'marginInline', 'gap', 'spacing', 'rowGap', 'columnGap',
27
- // Size
28
- 'width', 'height', 'minWidth', 'minHeight', 'maxWidth', 'maxHeight',
29
- // Position offsets
30
- 'top', 'right', 'bottom', 'left',
31
- // Display & position
32
- 'display', 'position', 'overflow', 'overflowX', 'overflowY',
33
- // Flex container
34
- 'flexDirection', 'flexWrap', 'justifyContent', 'alignItems', 'alignContent',
35
- // Flex item
36
- 'flex', 'flexGrow', 'flexShrink', 'flexBasis', 'order', 'alignSelf', 'justifySelf',
37
- // Grid container
38
- 'gridTemplateColumns', 'gridTemplateRows', 'gridTemplateAreas', 'gridAutoFlow', 'gridAutoRows', 'gridAutoColumns',
39
- // Grid item
40
- 'gridColumn', 'gridRow',
41
- // Typography
42
- 'fontSize', 'lineHeight', 'fontWeight', 'letterSpacing', 'fontFamily', 'textAlign', 'whiteSpace',
43
- // Visual
44
- 'cursor', 'opacity', 'visibility', 'pointerEvents', 'userSelect']);
45
-
46
- /**
47
- * Maps camelCase JS prop names to their CSS property equivalents.
48
- * Used for setting inline styles on props whose JS name differs from CSS.
49
- */
50
- const PROP_TO_CSS_PROPERTY = {
51
- paddingStart: 'paddingInlineStart',
52
- paddingEnd: 'paddingInlineEnd',
53
- marginStart: 'marginInlineStart',
54
- marginEnd: 'marginInlineEnd',
55
- spacing: 'gap' // Chakra Stack alias
56
- };
57
-
58
- /**
59
- * Props that are passed through to the DOM element as-is (not style props).
60
- */
61
- const PASSTHROUGH_KEYS = new Set(['id', 'role', 'tabIndex', 'onClick', 'onKeyDown', 'onFocus', 'onBlur', 'onMouseEnter', 'onMouseLeave', 'onMouseOver', 'onMouseOut', 'onMouseDown', 'onMouseUp', 'onKeyUp', 'onKeyPress', 'children']);
62
- const PASSTHROUGH_PREFIXES = ['aria-', 'data-'];
63
- function isPassthroughProp(key) {
64
- if (PASSTHROUGH_KEYS.has(key)) return true;
65
- return PASSTHROUGH_PREFIXES.some(prefix => key.startsWith(prefix));
66
- }
67
-
68
- /**
69
- * Props that are handled separately by components (not style, not passthrough).
70
- * These are stripped from the style output and handled in the component layer.
71
- */
72
- const COMPONENT_HANDLED_KEYS = new Set(['color', 'backgroundColor', 'className', 'style', 'zIndex']);
73
-
74
- /**
75
- * Breakpoint order (ascending, mobile-first).
76
- * Used by the fill-forward resolution to determine which value applies
77
- * at the current breakpoint.
78
- */
79
- const BP_ORDER = ['sm', 'md', 'lg', 'xl', '2xl'];
80
-
81
- /**
82
- * Resolves a responsive value object to the effective value for a given breakpoint.
83
- * Uses fill-forward: the most recently specified value at or below the current
84
- * breakpoint wins.
85
- *
86
- * @param {Record<string, string>} responsive - Object keyed by breakpoint (base, sm, md, lg, xl, 2xl)
87
- * @param {string} currentBp - The currently active breakpoint key
88
- * @returns {string | undefined} The resolved value, or undefined if no value applies
89
- */
90
- function resolveResponsive(responsive, currentBp) {
91
- let result = responsive.base !== undefined ? String(responsive.base) : undefined;
92
- for (const bp of BP_ORDER) {
93
- if (responsive[bp] !== undefined) {
94
- result = String(responsive[bp]);
95
- }
96
- if (bp === currentBp) break;
97
- }
98
- return result;
99
- }
100
- /**
101
- * Converts processed layout props into an output suitable for a plain DOM element.
102
- *
103
- * - Scalar values → inline `style` properties
104
- * - Responsive objects → resolved to the current breakpoint's value via fill-forward,
105
- * then set as inline `style` properties
106
- * - Non-style props (id, role, aria-*, data-*, event handlers) → `passthrough`
107
- *
108
- * @param {Record<string, any>} processedProps - Props after token conversion and validation
109
- * by `processBpkComponentProps`. Values are already resolved to CSS values (e.g. '.5rem').
110
- * Responsive values are objects keyed by Chakra breakpoint keys (base, sm, md, lg, xl, 2xl).
111
- * @param {string} currentBreakpoint - The currently active breakpoint key from useCurrentBreakpoint
112
- * @returns {LayoutStyleOutput} Style and passthrough props.
113
- */
114
- export function buildLayoutOutput(processedProps, currentBreakpoint) {
115
- const style = {};
116
- const passthrough = {};
117
- Object.entries(processedProps).forEach(([key, value]) => {
118
- if (value === undefined || value === null) return;
119
-
120
- // Passthrough props go directly to the DOM element
121
- if (isPassthroughProp(key)) {
122
- passthrough[key] = value;
123
- return;
124
- }
125
-
126
- // Component-handled props are skipped (handled by the component)
127
- if (COMPONENT_HANDLED_KEYS.has(key)) return;
128
-
129
- // Not a known style prop — pass through
130
- if (!STYLE_PROPS.has(key)) {
131
- passthrough[key] = value;
132
- return;
133
- }
134
- const cssPropName = PROP_TO_CSS_PROPERTY[key] || key;
135
-
136
- // Responsive object → resolve to current breakpoint value
137
- if (typeof value === 'object' && !Array.isArray(value)) {
138
- const resolved = resolveResponsive(value, currentBreakpoint);
139
- if (resolved !== undefined) {
140
- style[cssPropName] = resolved;
141
- }
142
- return;
143
- }
144
-
145
- // Scalar value → inline style
146
- style[cssPropName] = String(value);
147
- });
148
- return {
149
- style: style,
150
- passthrough
151
- };
152
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Returns the current active breakpoint key based on viewport width.
3
- * Uses `window.matchMedia` listeners to re-render when breakpoints change.
4
- * SSR-safe: returns `'base'` when `window` is unavailable.
5
- *
6
- * @returns {string} The active breakpoint key ('base' | 'sm' | 'md' | 'lg' | 'xl' | '2xl')
7
- */
8
- declare const useCurrentBreakpoint: () => string;
9
- export default useCurrentBreakpoint;
@@ -1,89 +0,0 @@
1
- /*
2
- * Backpack - Skyscanner's Design System
3
- *
4
- * Copyright 2016 Skyscanner Ltd
5
- *
6
- * Licensed under the Apache License, Version 2.0 (the "License");
7
- * you may not use this file except in compliance with the License.
8
- * You may obtain a copy of the License at
9
- *
10
- * http://www.apache.org/licenses/LICENSE-2.0
11
- *
12
- * Unless required by applicable law or agreed to in writing, software
13
- * distributed under the License is distributed on an "AS IS" BASIS,
14
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- * See the License for the specific language governing permissions and
16
- * limitations under the License.
17
- */
18
-
19
- import { useEffect, useState } from 'react';
20
-
21
- /**
22
- * Breakpoint min-widths in ascending order (mobile-first).
23
- * Must match the breakpoint definitions in tokens.ts
24
- * and the breakpoint mapping in tokens.ts.
25
- */
26
- const BREAKPOINTS = [{
27
- key: 'sm',
28
- query: '(min-width: 20rem)'
29
- },
30
- // 320px — small-mobile
31
- {
32
- key: 'md',
33
- query: '(min-width: 22.5rem)'
34
- },
35
- // 360px — mobile
36
- {
37
- key: 'lg',
38
- query: '(min-width: 32.0625rem)'
39
- },
40
- // 513px — small-tablet
41
- {
42
- key: 'xl',
43
- query: '(min-width: 48.0625rem)'
44
- },
45
- // 769px — tablet
46
- {
47
- key: '2xl',
48
- query: '(min-width: 64.0625rem)'
49
- } // 1025px — desktop
50
- ];
51
- function getCurrentBreakpoint() {
52
- if (typeof window === 'undefined' || !window.matchMedia) return 'base';
53
- let active = 'base';
54
- for (const {
55
- key,
56
- query
57
- } of BREAKPOINTS) {
58
- if (window.matchMedia(query).matches) active = key;
59
- }
60
- return active;
61
- }
62
-
63
- /**
64
- * Returns the current active breakpoint key based on viewport width.
65
- * Uses `window.matchMedia` listeners to re-render when breakpoints change.
66
- * SSR-safe: returns `'base'` when `window` is unavailable.
67
- *
68
- * @returns {string} The active breakpoint key ('base' | 'sm' | 'md' | 'lg' | 'xl' | '2xl')
69
- */
70
- const useCurrentBreakpoint = () => {
71
- const [breakpoint, setBreakpoint] = useState(getCurrentBreakpoint);
72
- useEffect(() => {
73
- if (typeof window === 'undefined' || !window.matchMedia) {
74
- return undefined;
75
- }
76
- const mqls = BREAKPOINTS.map(({
77
- query
78
- }) => window.matchMedia(query));
79
- const update = () => {
80
- setBreakpoint(getCurrentBreakpoint());
81
- };
82
- mqls.forEach(mql => mql.addEventListener('change', update));
83
- return () => {
84
- mqls.forEach(mql => mql.removeEventListener('change', update));
85
- };
86
- }, []);
87
- return breakpoint;
88
- };
89
- export default useCurrentBreakpoint;