@kaizen/components 0.0.0-canary-useContainerQueries-20251121043854 → 0.0.0-canary-useContainerQuery-20251123222018

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.
@@ -3,6 +3,7 @@
3
3
  var tslib = require('tslib');
4
4
  var React = require('react');
5
5
  var reactAriaComponents = require('react-aria-components');
6
+ require('use-debounce');
6
7
  var ReversedColors = require('../utils/ReversedColors/ReversedColors.cjs');
7
8
  var mergeClassNames = require('../utils/mergeClassNames.cjs');
8
9
  var PendingContent = require('./subcomponents/PendingContent/PendingContent.cjs');
@@ -11,6 +11,7 @@ require('../Loading/LoadingParagraph/LoadingParagraph.cjs');
11
11
  require('../Loading/LoadingSpinner/LoadingSpinner.cjs');
12
12
  require('../VisuallyHidden/VisuallyHidden.cjs');
13
13
  var ButtonContent = require('../Button/subcomponents/ButtonContent/ButtonContent.cjs');
14
+ require('use-debounce');
14
15
  var ReversedColors = require('../utils/ReversedColors/ReversedColors.cjs');
15
16
  var mergeClassNames = require('../utils/mergeClassNames.cjs');
16
17
  var Button_module = require('../Button/Button.module.css.cjs');
@@ -4,6 +4,7 @@ var tslib = require('tslib');
4
4
  var React = require('react');
5
5
  var classnames = require('classnames');
6
6
  var useMediaQueries = require('../utils/useMediaQueries.cjs');
7
+ require('use-debounce');
7
8
  require('../utils/ReversedColors/ReversedColors.cjs');
8
9
  var DirectionalLink = require('./subcomponents/DirectionalLink/DirectionalLink.cjs');
9
10
  var PaginationLink = require('./subcomponents/PaginationLink/PaginationLink.cjs');
@@ -3,6 +3,7 @@
3
3
  var tslib = require('tslib');
4
4
  var React = require('react');
5
5
  var reactAriaComponents = require('react-aria-components');
6
+ require('use-debounce');
6
7
  var ReversedColors = require('../utils/ReversedColors/ReversedColors.cjs');
7
8
  var mergeClassNames = require('../utils/mergeClassNames.cjs');
8
9
  var OverlayArrow_module = require('./OverlayArrow.module.scss.cjs');
@@ -4,6 +4,7 @@ var tslib = require('tslib');
4
4
  var React = require('react');
5
5
  var reactAriaComponents = require('react-aria-components');
6
6
  var VisuallyHidden = require('../VisuallyHidden/VisuallyHidden.cjs');
7
+ require('use-debounce');
7
8
  var ReversedColors = require('../utils/ReversedColors/ReversedColors.cjs');
8
9
  var mergeClassNames = require('../utils/mergeClassNames.cjs');
9
10
  var OverlayArrow = require('./OverlayArrow.cjs');
@@ -2,39 +2,30 @@
2
2
 
3
3
  var tslib = require('tslib');
4
4
  var React = require('react');
5
+ var useDebounce = require('use-debounce');
5
6
  function _interopDefault(e) {
6
7
  return e && e.__esModule ? e : {
7
8
  default: e
8
9
  };
9
10
  }
10
11
  var React__default = /*#__PURE__*/_interopDefault(React);
11
-
12
+ var DEFAULT_DEBOUNCE_MS = 500;
12
13
  /**
13
- * Tailwind CSS default container query breakpoints
14
+ * Tailwind CSS default container query breakpoints in pixels
14
15
  * These match the default values from @tailwindcss/container-queries plugin
15
16
  */
16
17
  var DEFAULT_BREAKPOINTS = {
17
- 'xs': '20rem',
18
- // 320px
19
- 'sm': '24rem',
20
- // 384px
21
- 'md': '28rem',
22
- // 448px
23
- 'lg': '32rem',
24
- // 512px
25
- 'xl': '36rem',
26
- // 576px
27
- '2xl': '42rem',
28
- // 672px
29
- '3xl': '48rem',
30
- // 768px
31
- '4xl': '56rem',
32
- // 896px
33
- '5xl': '64rem',
34
- // 1024px
35
- '6xl': '72rem',
36
- // 1152px
37
- '7xl': '80rem' // 1280px
18
+ 'xs': 320,
19
+ 'sm': 384,
20
+ 'md': 448,
21
+ 'lg': 512,
22
+ 'xl': 576,
23
+ '2xl': 672,
24
+ '3xl': 768,
25
+ '4xl': 896,
26
+ '5xl': 1024,
27
+ '6xl': 1152,
28
+ '7xl': 1280
38
29
  };
39
30
  /**
40
31
  * Convert rem/px values to pixels for comparison
@@ -169,15 +160,6 @@ var useContainerQueries = function (propQueries) {
169
160
  }
170
161
  };
171
162
  }
172
- // Parse all breakpoints to pixel values for comparison
173
- var breakpointsPx = React.useMemo(function () {
174
- return Object.entries(DEFAULT_BREAKPOINTS).reduce(function (acc, _a) {
175
- var key = _a[0],
176
- value = _a[1];
177
- acc[key] = parseBreakpointValue(value);
178
- return acc;
179
- }, {});
180
- }, []);
181
163
  // Parse custom queries
182
164
  var customQueriesPx = React.useMemo(function () {
183
165
  return Object.entries(propQueries).reduce(function (acc, _a) {
@@ -193,6 +175,10 @@ var useContainerQueries = function (propQueries) {
193
175
  setContainerWidth = _a[1];
194
176
  // ResizeObserver ref
195
177
  var resizeObserverRef = React.useRef(null);
178
+ // Debounced width update
179
+ var debouncedSetContainerWidth = useDebounce.useDebouncedCallback(function (width) {
180
+ setContainerWidth(width);
181
+ }, DEFAULT_DEBOUNCE_MS);
196
182
  // Callback ref for the container element
197
183
  var containerRef = React.useCallback(function (node) {
198
184
  // Cleanup previous observer
@@ -208,15 +194,15 @@ var useContainerQueries = function (propQueries) {
208
194
  var entry = entries_1[_i];
209
195
  // Use borderBoxSize for more accurate measurements
210
196
  var width_1 = (_c = (_b = (_a = entry.borderBoxSize) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.inlineSize) !== null && _c !== void 0 ? _c : entry.contentRect.width;
211
- setContainerWidth(width_1);
197
+ debouncedSetContainerWidth(width_1);
212
198
  }
213
199
  });
214
200
  resizeObserverRef.current.observe(node);
215
- // Set initial width
201
+ // Set initial width immediately (no debounce for initial render)
216
202
  var width = node.getBoundingClientRect().width;
217
203
  setContainerWidth(width);
218
204
  }
219
- }, []);
205
+ }, [debouncedSetContainerWidth]);
220
206
  // Cleanup on unmount
221
207
  React.useEffect(function () {
222
208
  return function () {
@@ -228,19 +214,19 @@ var useContainerQueries = function (propQueries) {
228
214
  // Calculate breakpoint matches based on container width
229
215
  var breakpointMatches = React.useMemo(function () {
230
216
  return {
231
- isXs: containerWidth >= breakpointsPx.xs,
232
- isSm: containerWidth >= breakpointsPx.sm,
233
- isMd: containerWidth >= breakpointsPx.md,
234
- isLg: containerWidth >= breakpointsPx.lg,
235
- isXl: containerWidth >= breakpointsPx.xl,
236
- is2xl: containerWidth >= breakpointsPx['2xl'],
237
- is3xl: containerWidth >= breakpointsPx['3xl'],
238
- is4xl: containerWidth >= breakpointsPx['4xl'],
239
- is5xl: containerWidth >= breakpointsPx['5xl'],
240
- is6xl: containerWidth >= breakpointsPx['6xl'],
241
- is7xl: containerWidth >= breakpointsPx['7xl']
217
+ isXs: containerWidth >= DEFAULT_BREAKPOINTS.xs,
218
+ isSm: containerWidth >= DEFAULT_BREAKPOINTS.sm,
219
+ isMd: containerWidth >= DEFAULT_BREAKPOINTS.md,
220
+ isLg: containerWidth >= DEFAULT_BREAKPOINTS.lg,
221
+ isXl: containerWidth >= DEFAULT_BREAKPOINTS.xl,
222
+ is2xl: containerWidth >= DEFAULT_BREAKPOINTS['2xl'],
223
+ is3xl: containerWidth >= DEFAULT_BREAKPOINTS['3xl'],
224
+ is4xl: containerWidth >= DEFAULT_BREAKPOINTS['4xl'],
225
+ is5xl: containerWidth >= DEFAULT_BREAKPOINTS['5xl'],
226
+ is6xl: containerWidth >= DEFAULT_BREAKPOINTS['6xl'],
227
+ is7xl: containerWidth >= DEFAULT_BREAKPOINTS['7xl']
242
228
  };
243
- }, [containerWidth, breakpointsPx]);
229
+ }, [containerWidth]);
244
230
  // Calculate custom query matches
245
231
  var customMatches = React.useMemo(function () {
246
232
  return Object.entries(customQueriesPx).reduce(function (acc, _a) {
@@ -252,7 +238,7 @@ var useContainerQueries = function (propQueries) {
252
238
  }, [containerWidth, customQueriesPx]);
253
239
  // Helper function to check if container is at exact breakpoint (not larger)
254
240
  var isExactBreakpoint = React.useCallback(function (breakpoint) {
255
- var sortedBreakpoints = Object.entries(breakpointsPx).sort(function (_a, _b) {
241
+ var sortedBreakpoints = Object.entries(DEFAULT_BREAKPOINTS).sort(function (_a, _b) {
256
242
  var a = _a[1];
257
243
  var b = _b[1];
258
244
  return a - b;
@@ -262,10 +248,10 @@ var useContainerQueries = function (propQueries) {
262
248
  return key === breakpoint;
263
249
  });
264
250
  var nextBreakpoint = sortedBreakpoints[currentIndex + 1];
265
- var minWidth = breakpointsPx[breakpoint];
251
+ var minWidth = DEFAULT_BREAKPOINTS[breakpoint];
266
252
  var maxWidth = nextBreakpoint ? nextBreakpoint[1] : Infinity;
267
253
  return containerWidth >= minWidth && containerWidth < maxWidth;
268
- }, [containerWidth, breakpointsPx]);
254
+ }, [containerWidth]);
269
255
  // Create helper components for Tailwind breakpoints
270
256
  var components = React.useMemo(function () {
271
257
  return tslib.__assign({
@@ -1,6 +1,7 @@
1
1
  import { __rest, __assign } from 'tslib';
2
2
  import React, { forwardRef } from 'react';
3
3
  import { Button as Button$1 } from 'react-aria-components';
4
+ import 'use-debounce';
4
5
  import { useReversedColors } from '../utils/ReversedColors/ReversedColors.mjs';
5
6
  import { mergeClassNames } from '../utils/mergeClassNames.mjs';
6
7
  import { PendingContent } from './subcomponents/PendingContent/PendingContent.mjs';
@@ -9,6 +9,7 @@ import '../Loading/LoadingParagraph/LoadingParagraph.mjs';
9
9
  import '../Loading/LoadingSpinner/LoadingSpinner.mjs';
10
10
  import '../VisuallyHidden/VisuallyHidden.mjs';
11
11
  import { ButtonContent } from '../Button/subcomponents/ButtonContent/ButtonContent.mjs';
12
+ import 'use-debounce';
12
13
  import { useReversedColors } from '../utils/ReversedColors/ReversedColors.mjs';
13
14
  import { mergeClassNames } from '../utils/mergeClassNames.mjs';
14
15
  import buttonStyles from '../Button/Button.module.css.mjs';
@@ -2,6 +2,7 @@ import { __rest, __assign } from 'tslib';
2
2
  import React from 'react';
3
3
  import classnames from 'classnames';
4
4
  import { useMediaQueries } from '../utils/useMediaQueries.mjs';
5
+ import 'use-debounce';
5
6
  import '../utils/ReversedColors/ReversedColors.mjs';
6
7
  import { DirectionalLink } from './subcomponents/DirectionalLink/DirectionalLink.mjs';
7
8
  import { PaginationLink } from './subcomponents/PaginationLink/PaginationLink.mjs';
@@ -1,6 +1,7 @@
1
1
  import { __assign } from 'tslib';
2
2
  import React from 'react';
3
3
  import { OverlayArrow as OverlayArrow$1 } from 'react-aria-components';
4
+ import 'use-debounce';
4
5
  import { useReversedColors } from '../utils/ReversedColors/ReversedColors.mjs';
5
6
  import { mergeClassNames } from '../utils/mergeClassNames.mjs';
6
7
  import styles from './OverlayArrow.module.scss.mjs';
@@ -3,6 +3,7 @@ import React, { forwardRef, useContext, useState, useLayoutEffect } from 'react'
3
3
  import { useContextProps, TooltipContext, TooltipTriggerStateContext, Tooltip as Tooltip$1 } from 'react-aria-components';
4
4
  export { TooltipContext } from 'react-aria-components';
5
5
  import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden.mjs';
6
+ import 'use-debounce';
6
7
  import { useReversedColors } from '../utils/ReversedColors/ReversedColors.mjs';
7
8
  import { mergeClassNames } from '../utils/mergeClassNames.mjs';
8
9
  import { OverlayArrow } from './OverlayArrow.mjs';
@@ -1,32 +1,23 @@
1
1
  import { __assign } from 'tslib';
2
2
  import React, { useMemo, useState, useRef, useCallback, useEffect } from 'react';
3
-
3
+ import { useDebouncedCallback } from 'use-debounce';
4
+ var DEFAULT_DEBOUNCE_MS = 500;
4
5
  /**
5
- * Tailwind CSS default container query breakpoints
6
+ * Tailwind CSS default container query breakpoints in pixels
6
7
  * These match the default values from @tailwindcss/container-queries plugin
7
8
  */
8
9
  var DEFAULT_BREAKPOINTS = {
9
- 'xs': '20rem',
10
- // 320px
11
- 'sm': '24rem',
12
- // 384px
13
- 'md': '28rem',
14
- // 448px
15
- 'lg': '32rem',
16
- // 512px
17
- 'xl': '36rem',
18
- // 576px
19
- '2xl': '42rem',
20
- // 672px
21
- '3xl': '48rem',
22
- // 768px
23
- '4xl': '56rem',
24
- // 896px
25
- '5xl': '64rem',
26
- // 1024px
27
- '6xl': '72rem',
28
- // 1152px
29
- '7xl': '80rem' // 1280px
10
+ 'xs': 320,
11
+ 'sm': 384,
12
+ 'md': 448,
13
+ 'lg': 512,
14
+ 'xl': 576,
15
+ '2xl': 672,
16
+ '3xl': 768,
17
+ '4xl': 896,
18
+ '5xl': 1024,
19
+ '6xl': 1152,
20
+ '7xl': 1280
30
21
  };
31
22
  /**
32
23
  * Convert rem/px values to pixels for comparison
@@ -161,15 +152,6 @@ var useContainerQueries = function (propQueries) {
161
152
  }
162
153
  };
163
154
  }
164
- // Parse all breakpoints to pixel values for comparison
165
- var breakpointsPx = useMemo(function () {
166
- return Object.entries(DEFAULT_BREAKPOINTS).reduce(function (acc, _a) {
167
- var key = _a[0],
168
- value = _a[1];
169
- acc[key] = parseBreakpointValue(value);
170
- return acc;
171
- }, {});
172
- }, []);
173
155
  // Parse custom queries
174
156
  var customQueriesPx = useMemo(function () {
175
157
  return Object.entries(propQueries).reduce(function (acc, _a) {
@@ -185,6 +167,10 @@ var useContainerQueries = function (propQueries) {
185
167
  setContainerWidth = _a[1];
186
168
  // ResizeObserver ref
187
169
  var resizeObserverRef = useRef(null);
170
+ // Debounced width update
171
+ var debouncedSetContainerWidth = useDebouncedCallback(function (width) {
172
+ setContainerWidth(width);
173
+ }, DEFAULT_DEBOUNCE_MS);
188
174
  // Callback ref for the container element
189
175
  var containerRef = useCallback(function (node) {
190
176
  // Cleanup previous observer
@@ -200,15 +186,15 @@ var useContainerQueries = function (propQueries) {
200
186
  var entry = entries_1[_i];
201
187
  // Use borderBoxSize for more accurate measurements
202
188
  var width_1 = (_c = (_b = (_a = entry.borderBoxSize) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.inlineSize) !== null && _c !== void 0 ? _c : entry.contentRect.width;
203
- setContainerWidth(width_1);
189
+ debouncedSetContainerWidth(width_1);
204
190
  }
205
191
  });
206
192
  resizeObserverRef.current.observe(node);
207
- // Set initial width
193
+ // Set initial width immediately (no debounce for initial render)
208
194
  var width = node.getBoundingClientRect().width;
209
195
  setContainerWidth(width);
210
196
  }
211
- }, []);
197
+ }, [debouncedSetContainerWidth]);
212
198
  // Cleanup on unmount
213
199
  useEffect(function () {
214
200
  return function () {
@@ -220,19 +206,19 @@ var useContainerQueries = function (propQueries) {
220
206
  // Calculate breakpoint matches based on container width
221
207
  var breakpointMatches = useMemo(function () {
222
208
  return {
223
- isXs: containerWidth >= breakpointsPx.xs,
224
- isSm: containerWidth >= breakpointsPx.sm,
225
- isMd: containerWidth >= breakpointsPx.md,
226
- isLg: containerWidth >= breakpointsPx.lg,
227
- isXl: containerWidth >= breakpointsPx.xl,
228
- is2xl: containerWidth >= breakpointsPx['2xl'],
229
- is3xl: containerWidth >= breakpointsPx['3xl'],
230
- is4xl: containerWidth >= breakpointsPx['4xl'],
231
- is5xl: containerWidth >= breakpointsPx['5xl'],
232
- is6xl: containerWidth >= breakpointsPx['6xl'],
233
- is7xl: containerWidth >= breakpointsPx['7xl']
209
+ isXs: containerWidth >= DEFAULT_BREAKPOINTS.xs,
210
+ isSm: containerWidth >= DEFAULT_BREAKPOINTS.sm,
211
+ isMd: containerWidth >= DEFAULT_BREAKPOINTS.md,
212
+ isLg: containerWidth >= DEFAULT_BREAKPOINTS.lg,
213
+ isXl: containerWidth >= DEFAULT_BREAKPOINTS.xl,
214
+ is2xl: containerWidth >= DEFAULT_BREAKPOINTS['2xl'],
215
+ is3xl: containerWidth >= DEFAULT_BREAKPOINTS['3xl'],
216
+ is4xl: containerWidth >= DEFAULT_BREAKPOINTS['4xl'],
217
+ is5xl: containerWidth >= DEFAULT_BREAKPOINTS['5xl'],
218
+ is6xl: containerWidth >= DEFAULT_BREAKPOINTS['6xl'],
219
+ is7xl: containerWidth >= DEFAULT_BREAKPOINTS['7xl']
234
220
  };
235
- }, [containerWidth, breakpointsPx]);
221
+ }, [containerWidth]);
236
222
  // Calculate custom query matches
237
223
  var customMatches = useMemo(function () {
238
224
  return Object.entries(customQueriesPx).reduce(function (acc, _a) {
@@ -244,7 +230,7 @@ var useContainerQueries = function (propQueries) {
244
230
  }, [containerWidth, customQueriesPx]);
245
231
  // Helper function to check if container is at exact breakpoint (not larger)
246
232
  var isExactBreakpoint = useCallback(function (breakpoint) {
247
- var sortedBreakpoints = Object.entries(breakpointsPx).sort(function (_a, _b) {
233
+ var sortedBreakpoints = Object.entries(DEFAULT_BREAKPOINTS).sort(function (_a, _b) {
248
234
  var a = _a[1];
249
235
  var b = _b[1];
250
236
  return a - b;
@@ -254,10 +240,10 @@ var useContainerQueries = function (propQueries) {
254
240
  return key === breakpoint;
255
241
  });
256
242
  var nextBreakpoint = sortedBreakpoints[currentIndex + 1];
257
- var minWidth = breakpointsPx[breakpoint];
243
+ var minWidth = DEFAULT_BREAKPOINTS[breakpoint];
258
244
  var maxWidth = nextBreakpoint ? nextBreakpoint[1] : Infinity;
259
245
  return containerWidth >= minWidth && containerWidth < maxWidth;
260
- }, [containerWidth, breakpointsPx]);
246
+ }, [containerWidth]);
261
247
  // Create helper components for Tailwind breakpoints
262
248
  var components = useMemo(function () {
263
249
  return __assign({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaizen/components",
3
- "version": "0.0.0-canary-useContainerQueries-20251121043854",
3
+ "version": "0.0.0-canary-useContainerQuery-20251123222018",
4
4
  "description": "Kaizen component library",
5
5
  "author": "Geoffrey Chong <geoff.chong@cultureamp.com>",
6
6
  "homepage": "https://cultureamp.design",
@@ -135,6 +135,8 @@ describe('useContainerQueries()', () => {
135
135
  // Trigger resize to 400px (sm breakpoint is 384px)
136
136
  await act(async () => {
137
137
  resizeObserverInstance?.trigger(400)
138
+ // Wait for debounce (500ms + buffer)
139
+ await new Promise((resolve) => setTimeout(resolve, 550))
138
140
  })
139
141
 
140
142
  expect(screen.queryByRole('button', { name: /Small query boolean/i })).toBeInTheDocument()
@@ -145,6 +147,8 @@ describe('useContainerQueries()', () => {
145
147
  // Trigger resize to 500px (md breakpoint is 448px)
146
148
  await act(async () => {
147
149
  resizeObserverInstance?.trigger(500)
150
+ // Wait for debounce (500ms + buffer)
151
+ await new Promise((resolve) => setTimeout(resolve, 550))
148
152
  })
149
153
 
150
154
  expect(screen.queryByRole('button', { name: /Small query boolean/i })).toBeInTheDocument()
@@ -179,6 +183,8 @@ describe('useContainerQueries()', () => {
179
183
  // Trigger resize to 450px (compact is 400px)
180
184
  await act(async () => {
181
185
  resizeObserverInstance?.trigger(450)
186
+ // Wait for debounce (500ms + buffer)
187
+ await new Promise((resolve) => setTimeout(resolve, 550))
182
188
  })
183
189
 
184
190
  expect(screen.queryByRole('button', { name: /Compact query boolean/i })).toBeInTheDocument()
@@ -1,25 +1,28 @@
1
1
  /* eslint-disable react-hooks/rules-of-hooks */
2
2
  import React, { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
3
+ import { useDebouncedCallback } from 'use-debounce'
3
4
 
4
5
  type Props = Record<string, string>
5
6
  type GenericChildrenType = { children?: ReactNode }
6
7
 
8
+ const DEFAULT_DEBOUNCE_MS = 500
9
+
7
10
  /**
8
- * Tailwind CSS default container query breakpoints
11
+ * Tailwind CSS default container query breakpoints in pixels
9
12
  * These match the default values from @tailwindcss/container-queries plugin
10
13
  */
11
14
  const DEFAULT_BREAKPOINTS = {
12
- 'xs': '20rem', // 320px
13
- 'sm': '24rem', // 384px
14
- 'md': '28rem', // 448px
15
- 'lg': '32rem', // 512px
16
- 'xl': '36rem', // 576px
17
- '2xl': '42rem', // 672px
18
- '3xl': '48rem', // 768px
19
- '4xl': '56rem', // 896px
20
- '5xl': '64rem', // 1024px
21
- '6xl': '72rem', // 1152px
22
- '7xl': '80rem', // 1280px
15
+ 'xs': 320,
16
+ 'sm': 384,
17
+ 'md': 448,
18
+ 'lg': 512,
19
+ 'xl': 576,
20
+ '2xl': 672,
21
+ '3xl': 768,
22
+ '4xl': 896,
23
+ '5xl': 1024,
24
+ '6xl': 1152,
25
+ '7xl': 1280,
23
26
  } as const
24
27
 
25
28
  /**
@@ -167,19 +170,6 @@ export const useContainerQueries = (
167
170
  }
168
171
  }
169
172
 
170
- // Parse all breakpoints to pixel values for comparison
171
- const breakpointsPx = useMemo(
172
- () =>
173
- Object.entries(DEFAULT_BREAKPOINTS).reduce(
174
- (acc, [key, value]) => {
175
- acc[key] = parseBreakpointValue(value)
176
- return acc
177
- },
178
- {} as Record<string, number>,
179
- ),
180
- [],
181
- )
182
-
183
173
  // Parse custom queries
184
174
  const customQueriesPx = useMemo(
185
175
  () =>
@@ -199,31 +189,39 @@ export const useContainerQueries = (
199
189
  // ResizeObserver ref
200
190
  const resizeObserverRef = useRef<ResizeObserver | null>(null)
201
191
 
192
+ // Debounced width update
193
+ const debouncedSetContainerWidth = useDebouncedCallback((width: number) => {
194
+ setContainerWidth(width)
195
+ }, DEFAULT_DEBOUNCE_MS)
196
+
202
197
  // Callback ref for the container element
203
- const containerRef = useCallback((node: HTMLElement | null) => {
204
- // Cleanup previous observer
205
- if (resizeObserverRef.current) {
206
- resizeObserverRef.current.disconnect()
207
- resizeObserverRef.current = null
208
- }
198
+ const containerRef = useCallback(
199
+ (node: HTMLElement | null) => {
200
+ // Cleanup previous observer
201
+ if (resizeObserverRef.current) {
202
+ resizeObserverRef.current.disconnect()
203
+ resizeObserverRef.current = null
204
+ }
209
205
 
210
- if (node) {
211
- // Create new ResizeObserver
212
- resizeObserverRef.current = new ResizeObserver((entries) => {
213
- for (const entry of entries) {
214
- // Use borderBoxSize for more accurate measurements
215
- const width = entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width
216
- setContainerWidth(width)
217
- }
218
- })
206
+ if (node) {
207
+ // Create new ResizeObserver
208
+ resizeObserverRef.current = new ResizeObserver((entries) => {
209
+ for (const entry of entries) {
210
+ // Use borderBoxSize for more accurate measurements
211
+ const width = entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width
212
+ debouncedSetContainerWidth(width)
213
+ }
214
+ })
219
215
 
220
- resizeObserverRef.current.observe(node)
216
+ resizeObserverRef.current.observe(node)
221
217
 
222
- // Set initial width
223
- const width = node.getBoundingClientRect().width
224
- setContainerWidth(width)
225
- }
226
- }, [])
218
+ // Set initial width immediately (no debounce for initial render)
219
+ const width = node.getBoundingClientRect().width
220
+ setContainerWidth(width)
221
+ }
222
+ },
223
+ [debouncedSetContainerWidth],
224
+ )
227
225
 
228
226
  // Cleanup on unmount
229
227
  useEffect(
@@ -238,19 +236,19 @@ export const useContainerQueries = (
238
236
  // Calculate breakpoint matches based on container width
239
237
  const breakpointMatches = useMemo(
240
238
  () => ({
241
- isXs: containerWidth >= breakpointsPx.xs,
242
- isSm: containerWidth >= breakpointsPx.sm,
243
- isMd: containerWidth >= breakpointsPx.md,
244
- isLg: containerWidth >= breakpointsPx.lg,
245
- isXl: containerWidth >= breakpointsPx.xl,
246
- is2xl: containerWidth >= breakpointsPx['2xl'],
247
- is3xl: containerWidth >= breakpointsPx['3xl'],
248
- is4xl: containerWidth >= breakpointsPx['4xl'],
249
- is5xl: containerWidth >= breakpointsPx['5xl'],
250
- is6xl: containerWidth >= breakpointsPx['6xl'],
251
- is7xl: containerWidth >= breakpointsPx['7xl'],
239
+ isXs: containerWidth >= DEFAULT_BREAKPOINTS.xs,
240
+ isSm: containerWidth >= DEFAULT_BREAKPOINTS.sm,
241
+ isMd: containerWidth >= DEFAULT_BREAKPOINTS.md,
242
+ isLg: containerWidth >= DEFAULT_BREAKPOINTS.lg,
243
+ isXl: containerWidth >= DEFAULT_BREAKPOINTS.xl,
244
+ is2xl: containerWidth >= DEFAULT_BREAKPOINTS['2xl'],
245
+ is3xl: containerWidth >= DEFAULT_BREAKPOINTS['3xl'],
246
+ is4xl: containerWidth >= DEFAULT_BREAKPOINTS['4xl'],
247
+ is5xl: containerWidth >= DEFAULT_BREAKPOINTS['5xl'],
248
+ is6xl: containerWidth >= DEFAULT_BREAKPOINTS['6xl'],
249
+ is7xl: containerWidth >= DEFAULT_BREAKPOINTS['7xl'],
252
250
  }),
253
- [containerWidth, breakpointsPx],
251
+ [containerWidth],
254
252
  )
255
253
 
256
254
  // Calculate custom query matches
@@ -268,17 +266,17 @@ export const useContainerQueries = (
268
266
 
269
267
  // Helper function to check if container is at exact breakpoint (not larger)
270
268
  const isExactBreakpoint = useCallback(
271
- (breakpoint: keyof typeof breakpointsPx): boolean => {
272
- const sortedBreakpoints = Object.entries(breakpointsPx).sort(([, a], [, b]) => a - b)
269
+ (breakpoint: keyof typeof DEFAULT_BREAKPOINTS): boolean => {
270
+ const sortedBreakpoints = Object.entries(DEFAULT_BREAKPOINTS).sort(([, a], [, b]) => a - b)
273
271
  const currentIndex = sortedBreakpoints.findIndex(([key]) => key === breakpoint)
274
272
  const nextBreakpoint = sortedBreakpoints[currentIndex + 1]
275
273
 
276
- const minWidth = breakpointsPx[breakpoint]
274
+ const minWidth = DEFAULT_BREAKPOINTS[breakpoint]
277
275
  const maxWidth = nextBreakpoint ? nextBreakpoint[1] : Infinity
278
276
 
279
277
  return containerWidth >= minWidth && containerWidth < maxWidth
280
278
  },
281
- [containerWidth, breakpointsPx],
279
+ [containerWidth],
282
280
  )
283
281
 
284
282
  // Create helper components for Tailwind breakpoints