@kaizen/components 0.0.0-canary-useContainerQueries-20251121043854 → 0.0.0-canary-useContainerQueries-20251125215952

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.
@@ -1,91 +0,0 @@
1
- import React, { type ReactNode } from 'react';
2
- type Props = Record<string, string>;
3
- type GenericChildrenType = {
4
- children?: ReactNode;
5
- };
6
- type ContainerQueries = {
7
- isXs: boolean;
8
- isSm: boolean;
9
- isMd: boolean;
10
- isLg: boolean;
11
- isXl: boolean;
12
- is2xl: boolean;
13
- is3xl: boolean;
14
- is4xl: boolean;
15
- is5xl: boolean;
16
- is6xl: boolean;
17
- is7xl: boolean;
18
- [key: string]: boolean;
19
- };
20
- type ContainerComponents = {
21
- 'XsOnly': (props: GenericChildrenType) => JSX.Element;
22
- 'SmOnly': (props: GenericChildrenType) => JSX.Element;
23
- 'MdOnly': (props: GenericChildrenType) => JSX.Element;
24
- 'LgOnly': (props: GenericChildrenType) => JSX.Element;
25
- 'XlOnly': (props: GenericChildrenType) => JSX.Element;
26
- '2xlOnly': (props: GenericChildrenType) => JSX.Element;
27
- '3xlOnly': (props: GenericChildrenType) => JSX.Element;
28
- '4xlOnly': (props: GenericChildrenType) => JSX.Element;
29
- '5xlOnly': (props: GenericChildrenType) => JSX.Element;
30
- '6xlOnly': (props: GenericChildrenType) => JSX.Element;
31
- '7xlOnly': (props: GenericChildrenType) => JSX.Element;
32
- 'XsOrLarger': (props: GenericChildrenType) => JSX.Element;
33
- 'SmOrLarger': (props: GenericChildrenType) => JSX.Element;
34
- 'MdOrLarger': (props: GenericChildrenType) => JSX.Element;
35
- 'LgOrLarger': (props: GenericChildrenType) => JSX.Element;
36
- 'XlOrLarger': (props: GenericChildrenType) => JSX.Element;
37
- [key: string]: (props: GenericChildrenType) => JSX.Element;
38
- };
39
- /**
40
- * A React hook for responding to container size changes using Tailwind CSS container query breakpoints.
41
- *
42
- * This hook uses ResizeObserver to detect when a container element crosses breakpoint thresholds,
43
- * enabling component-level responsive behavior independent of viewport size.
44
- *
45
- * @param propQueries - Optional custom container size queries in the format { queryName: 'minWidth' }
46
- * Example: { large: '600px', extraLarge: '48rem' }
47
- *
48
- * @returns An object containing:
49
- * - containerRef: A ref to attach to your container element
50
- * - queries: Boolean flags for each breakpoint (isXs, isSm, isMd, etc.) and custom queries
51
- * - components: React components for conditional rendering (XsOnly, SmOrLarger, etc.)
52
- *
53
- * @example
54
- * ```tsx
55
- * const MyComponent = () => {
56
- * const { containerRef, queries, components } = useContainerQueries()
57
- * const { MdOrLarger } = components
58
- *
59
- * return (
60
- * <div ref={containerRef}>
61
- * {queries.isSm && <p>Small container</p>}
62
- * <MdOrLarger>
63
- * <p>Medium or larger container</p>
64
- * </MdOrLarger>
65
- * </div>
66
- * )
67
- * }
68
- * ```
69
- *
70
- * @example With custom queries
71
- * ```tsx
72
- * const { containerRef, queries, components } = useContainerQueries({
73
- * compact: '400px',
74
- * spacious: '800px',
75
- * })
76
- * const { Compact, Spacious } = components
77
- *
78
- * return (
79
- * <div ref={containerRef}>
80
- * <Compact><p>Compact view</p></Compact>
81
- * <Spacious><p>Spacious view</p></Spacious>
82
- * </div>
83
- * )
84
- * ```
85
- */
86
- export declare const useContainerQueries: (propQueries?: Props) => {
87
- containerRef: React.RefCallback<HTMLElement>;
88
- queries: ContainerQueries;
89
- components: ContainerComponents;
90
- };
91
- export {};
@@ -1,242 +0,0 @@
1
- import React from 'react'
2
- import { act, render, screen } from '@testing-library/react'
3
- import { vi } from 'vitest'
4
- import { useContainerQueries } from './useContainerQueries'
5
-
6
- const ExampleComponent = (): JSX.Element => {
7
- const { containerRef, queries, components } = useContainerQueries({
8
- compact: '400px',
9
- wide: '800px',
10
- })
11
- const { MdOrLarger, Compact } = components
12
-
13
- return (
14
- <div ref={containerRef} data-testid="container">
15
- {queries.isSm && <button type="button">Small query boolean</button>}
16
- <MdOrLarger>
17
- <button type="button">Medium or larger component</button>
18
- </MdOrLarger>
19
- {queries.compact && <button type="button">Compact query boolean</button>}
20
- <Compact>
21
- <button type="button">Compact component</button>
22
- </Compact>
23
- </div>
24
- )
25
- }
26
-
27
- // Mock ResizeObserver
28
- class ResizeObserverMock {
29
- callback: ResizeObserverCallback
30
- elements: Set<Element>
31
-
32
- constructor(callback: ResizeObserverCallback) {
33
- this.callback = callback
34
- this.elements = new Set()
35
- }
36
-
37
- observe(target: Element): void {
38
- this.elements.add(target)
39
- }
40
-
41
- unobserve(target: Element): void {
42
- this.elements.delete(target)
43
- }
44
-
45
- disconnect(): void {
46
- this.elements.clear()
47
- }
48
-
49
- // Helper method to trigger resize
50
- trigger(width: number): void {
51
- const entries: ResizeObserverEntry[] = Array.from(this.elements).map((element) => ({
52
- target: element,
53
- contentRect: {
54
- width,
55
- height: 100,
56
- top: 0,
57
- left: 0,
58
- bottom: 100,
59
- right: width,
60
- x: 0,
61
- y: 0,
62
- } as DOMRectReadOnly,
63
- borderBoxSize: [
64
- {
65
- inlineSize: width,
66
- blockSize: 100,
67
- },
68
- ],
69
- contentBoxSize: [
70
- {
71
- inlineSize: width,
72
- blockSize: 100,
73
- },
74
- ],
75
- devicePixelContentBoxSize: [
76
- {
77
- inlineSize: width,
78
- blockSize: 100,
79
- },
80
- ],
81
- })) as ResizeObserverEntry[]
82
-
83
- this.callback(entries, this as unknown as ResizeObserver)
84
- }
85
- }
86
-
87
- let resizeObserverInstance: ResizeObserverMock | null = null
88
-
89
- const setupResizeObserver = (): ResizeObserverMock => {
90
- const mockObserver = vi.fn((callback: ResizeObserverCallback) => {
91
- resizeObserverInstance = new ResizeObserverMock(callback)
92
- return resizeObserverInstance
93
- })
94
-
95
- global.ResizeObserver = mockObserver as unknown as typeof ResizeObserver
96
-
97
- return resizeObserverInstance!
98
- }
99
-
100
- describe('useContainerQueries()', () => {
101
- beforeEach(() => {
102
- resizeObserverInstance = null
103
- })
104
-
105
- afterEach(() => {
106
- vi.restoreAllMocks()
107
- })
108
-
109
- it('shows and hides content based on Tailwind container breakpoints', async () => {
110
- setupResizeObserver()
111
-
112
- // Mock getBoundingClientRect to return a small width initially
113
- const mockGetBoundingClientRect = vi.fn(() => ({
114
- width: 300,
115
- height: 100,
116
- top: 0,
117
- left: 0,
118
- bottom: 100,
119
- right: 300,
120
- x: 0,
121
- y: 0,
122
- // eslint-disable-next-line @typescript-eslint/no-empty-function
123
- toJSON: () => {},
124
- }))
125
- Element.prototype.getBoundingClientRect = mockGetBoundingClientRect
126
-
127
- render(<ExampleComponent />)
128
-
129
- // Initially at 300px, should not show sm (384px) or md (448px) content
130
- expect(screen.queryByRole('button', { name: /Small query boolean/i })).not.toBeInTheDocument()
131
- expect(
132
- screen.queryByRole('button', { name: /Medium or larger component/i }),
133
- ).not.toBeInTheDocument()
134
-
135
- // Trigger resize to 400px (sm breakpoint is 384px)
136
- await act(async () => {
137
- resizeObserverInstance?.trigger(400)
138
- })
139
-
140
- expect(screen.queryByRole('button', { name: /Small query boolean/i })).toBeInTheDocument()
141
- expect(
142
- screen.queryByRole('button', { name: /Medium or larger component/i }),
143
- ).not.toBeInTheDocument()
144
-
145
- // Trigger resize to 500px (md breakpoint is 448px)
146
- await act(async () => {
147
- resizeObserverInstance?.trigger(500)
148
- })
149
-
150
- expect(screen.queryByRole('button', { name: /Small query boolean/i })).toBeInTheDocument()
151
- expect(
152
- screen.queryByRole('button', { name: /Medium or larger component/i }),
153
- ).toBeInTheDocument()
154
- })
155
-
156
- it('shows and hides content based on custom queries', async () => {
157
- setupResizeObserver()
158
-
159
- const mockGetBoundingClientRect = vi.fn(() => ({
160
- width: 300,
161
- height: 100,
162
- top: 0,
163
- left: 0,
164
- bottom: 100,
165
- right: 300,
166
- x: 0,
167
- y: 0,
168
- // eslint-disable-next-line @typescript-eslint/no-empty-function
169
- toJSON: () => {},
170
- }))
171
- Element.prototype.getBoundingClientRect = mockGetBoundingClientRect
172
-
173
- render(<ExampleComponent />)
174
-
175
- // Initially at 300px, custom 'compact' query (400px) should not match
176
- expect(screen.queryByRole('button', { name: /Compact query boolean/i })).not.toBeInTheDocument()
177
- expect(screen.queryByRole('button', { name: /Compact component/i })).not.toBeInTheDocument()
178
-
179
- // Trigger resize to 450px (compact is 400px)
180
- await act(async () => {
181
- resizeObserverInstance?.trigger(450)
182
- })
183
-
184
- expect(screen.queryByRole('button', { name: /Compact query boolean/i })).toBeInTheDocument()
185
- expect(screen.queryByRole('button', { name: /Compact component/i })).toBeInTheDocument()
186
- })
187
-
188
- it('returns SSR-safe defaults when window is undefined', () => {
189
- // This test verifies the SSR code path exists
190
- // In actual SSR environment, the hook returns safe defaults
191
- expect(useContainerQueries).toBeDefined()
192
- })
193
-
194
- it('cleans up ResizeObserver on unmount', () => {
195
- setupResizeObserver()
196
-
197
- const mockGetBoundingClientRect = vi.fn(() => ({
198
- width: 500,
199
- height: 100,
200
- top: 0,
201
- left: 0,
202
- bottom: 100,
203
- right: 500,
204
- x: 0,
205
- y: 0,
206
- // eslint-disable-next-line @typescript-eslint/no-empty-function
207
- toJSON: () => {},
208
- }))
209
- Element.prototype.getBoundingClientRect = mockGetBoundingClientRect
210
-
211
- const { unmount } = render(<ExampleComponent />)
212
-
213
- const disconnectSpy = vi.spyOn(resizeObserverInstance!, 'disconnect')
214
-
215
- unmount()
216
-
217
- expect(disconnectSpy).toHaveBeenCalled()
218
- })
219
-
220
- it('observes the container element', () => {
221
- setupResizeObserver()
222
-
223
- const mockGetBoundingClientRect = vi.fn(() => ({
224
- width: 500,
225
- height: 100,
226
- top: 0,
227
- left: 0,
228
- bottom: 100,
229
- right: 500,
230
- x: 0,
231
- y: 0,
232
- // eslint-disable-next-line @typescript-eslint/no-empty-function
233
- toJSON: () => {},
234
- }))
235
- Element.prototype.getBoundingClientRect = mockGetBoundingClientRect
236
-
237
- render(<ExampleComponent />)
238
-
239
- // Verify that the ResizeObserver is observing the container
240
- expect(resizeObserverInstance?.elements.size).toBe(1)
241
- })
242
- })
@@ -1,333 +0,0 @@
1
- /* eslint-disable react-hooks/rules-of-hooks */
2
- import React, { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
3
-
4
- type Props = Record<string, string>
5
- type GenericChildrenType = { children?: ReactNode }
6
-
7
- /**
8
- * Tailwind CSS default container query breakpoints
9
- * These match the default values from @tailwindcss/container-queries plugin
10
- */
11
- 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
23
- } as const
24
-
25
- /**
26
- * Convert rem/px values to pixels for comparison
27
- */
28
- const parseBreakpointValue = (value: string): number => {
29
- if (value.endsWith('rem')) {
30
- return parseFloat(value) * 16 // Assuming 1rem = 16px
31
- }
32
- if (value.endsWith('px')) {
33
- return parseFloat(value)
34
- }
35
- return parseFloat(value)
36
- }
37
-
38
- type HelperComponentProps = {
39
- children?: ReactNode
40
- }
41
-
42
- type ContainerQueries = {
43
- isXs: boolean
44
- isSm: boolean
45
- isMd: boolean
46
- isLg: boolean
47
- isXl: boolean
48
- is2xl: boolean
49
- is3xl: boolean
50
- is4xl: boolean
51
- is5xl: boolean
52
- is6xl: boolean
53
- is7xl: boolean
54
- [key: string]: boolean
55
- }
56
-
57
- type ContainerComponents = {
58
- 'XsOnly': (props: GenericChildrenType) => JSX.Element
59
- 'SmOnly': (props: GenericChildrenType) => JSX.Element
60
- 'MdOnly': (props: GenericChildrenType) => JSX.Element
61
- 'LgOnly': (props: GenericChildrenType) => JSX.Element
62
- 'XlOnly': (props: GenericChildrenType) => JSX.Element
63
- '2xlOnly': (props: GenericChildrenType) => JSX.Element
64
- '3xlOnly': (props: GenericChildrenType) => JSX.Element
65
- '4xlOnly': (props: GenericChildrenType) => JSX.Element
66
- '5xlOnly': (props: GenericChildrenType) => JSX.Element
67
- '6xlOnly': (props: GenericChildrenType) => JSX.Element
68
- '7xlOnly': (props: GenericChildrenType) => JSX.Element
69
- 'XsOrLarger': (props: GenericChildrenType) => JSX.Element
70
- 'SmOrLarger': (props: GenericChildrenType) => JSX.Element
71
- 'MdOrLarger': (props: GenericChildrenType) => JSX.Element
72
- 'LgOrLarger': (props: GenericChildrenType) => JSX.Element
73
- 'XlOrLarger': (props: GenericChildrenType) => JSX.Element
74
- [key: string]: (props: GenericChildrenType) => JSX.Element
75
- }
76
-
77
- /**
78
- * A React hook for responding to container size changes using Tailwind CSS container query breakpoints.
79
- *
80
- * This hook uses ResizeObserver to detect when a container element crosses breakpoint thresholds,
81
- * enabling component-level responsive behavior independent of viewport size.
82
- *
83
- * @param propQueries - Optional custom container size queries in the format { queryName: 'minWidth' }
84
- * Example: { large: '600px', extraLarge: '48rem' }
85
- *
86
- * @returns An object containing:
87
- * - containerRef: A ref to attach to your container element
88
- * - queries: Boolean flags for each breakpoint (isXs, isSm, isMd, etc.) and custom queries
89
- * - components: React components for conditional rendering (XsOnly, SmOrLarger, etc.)
90
- *
91
- * @example
92
- * ```tsx
93
- * const MyComponent = () => {
94
- * const { containerRef, queries, components } = useContainerQueries()
95
- * const { MdOrLarger } = components
96
- *
97
- * return (
98
- * <div ref={containerRef}>
99
- * {queries.isSm && <p>Small container</p>}
100
- * <MdOrLarger>
101
- * <p>Medium or larger container</p>
102
- * </MdOrLarger>
103
- * </div>
104
- * )
105
- * }
106
- * ```
107
- *
108
- * @example With custom queries
109
- * ```tsx
110
- * const { containerRef, queries, components } = useContainerQueries({
111
- * compact: '400px',
112
- * spacious: '800px',
113
- * })
114
- * const { Compact, Spacious } = components
115
- *
116
- * return (
117
- * <div ref={containerRef}>
118
- * <Compact><p>Compact view</p></Compact>
119
- * <Spacious><p>Spacious view</p></Spacious>
120
- * </div>
121
- * )
122
- * ```
123
- */
124
- export const useContainerQueries = (
125
- propQueries: Props = {},
126
- ): {
127
- containerRef: React.RefCallback<HTMLElement>
128
- queries: ContainerQueries
129
- components: ContainerComponents
130
- } => {
131
- // SSR support - return safe defaults when window is undefined
132
- if (typeof window === 'undefined') {
133
- return {
134
- // eslint-disable-next-line @typescript-eslint/no-empty-function
135
- containerRef: () => {},
136
- queries: {
137
- isXs: false,
138
- isSm: false,
139
- isMd: false,
140
- isLg: false,
141
- isXl: false,
142
- is2xl: false,
143
- is3xl: false,
144
- is4xl: false,
145
- is5xl: false,
146
- is6xl: false,
147
- is7xl: true, // Default to largest for SSR
148
- },
149
- components: {
150
- 'XsOnly': () => <></>,
151
- 'SmOnly': () => <></>,
152
- 'MdOnly': () => <></>,
153
- 'LgOnly': () => <></>,
154
- 'XlOnly': () => <></>,
155
- '2xlOnly': () => <></>,
156
- '3xlOnly': () => <></>,
157
- '4xlOnly': () => <></>,
158
- '5xlOnly': () => <></>,
159
- '6xlOnly': () => <></>,
160
- '7xlOnly': (props: HelperComponentProps) => <>{props.children}</>,
161
- 'XsOrLarger': (props: HelperComponentProps) => <>{props.children}</>,
162
- 'SmOrLarger': (props: HelperComponentProps) => <>{props.children}</>,
163
- 'MdOrLarger': (props: HelperComponentProps) => <>{props.children}</>,
164
- 'LgOrLarger': (props: HelperComponentProps) => <>{props.children}</>,
165
- 'XlOrLarger': (props: HelperComponentProps) => <>{props.children}</>,
166
- },
167
- }
168
- }
169
-
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
- // Parse custom queries
184
- const customQueriesPx = useMemo(
185
- () =>
186
- Object.entries(propQueries).reduce(
187
- (acc, [key, value]) => {
188
- acc[key] = parseBreakpointValue(value)
189
- return acc
190
- },
191
- {} as Record<string, number>,
192
- ),
193
- [propQueries],
194
- )
195
-
196
- // State to track container width
197
- const [containerWidth, setContainerWidth] = useState<number>(0)
198
-
199
- // ResizeObserver ref
200
- const resizeObserverRef = useRef<ResizeObserver | null>(null)
201
-
202
- // 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
- }
209
-
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
- })
219
-
220
- resizeObserverRef.current.observe(node)
221
-
222
- // Set initial width
223
- const width = node.getBoundingClientRect().width
224
- setContainerWidth(width)
225
- }
226
- }, [])
227
-
228
- // Cleanup on unmount
229
- useEffect(
230
- () => () => {
231
- if (resizeObserverRef.current) {
232
- resizeObserverRef.current.disconnect()
233
- }
234
- },
235
- [],
236
- )
237
-
238
- // Calculate breakpoint matches based on container width
239
- const breakpointMatches = useMemo(
240
- () => ({
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'],
252
- }),
253
- [containerWidth, breakpointsPx],
254
- )
255
-
256
- // Calculate custom query matches
257
- const customMatches = useMemo(
258
- () =>
259
- Object.entries(customQueriesPx).reduce(
260
- (acc, [key, value]) => {
261
- acc[key] = containerWidth >= value
262
- return acc
263
- },
264
- {} as Record<string, boolean>,
265
- ),
266
- [containerWidth, customQueriesPx],
267
- )
268
-
269
- // Helper function to check if container is at exact breakpoint (not larger)
270
- const isExactBreakpoint = useCallback(
271
- (breakpoint: keyof typeof breakpointsPx): boolean => {
272
- const sortedBreakpoints = Object.entries(breakpointsPx).sort(([, a], [, b]) => a - b)
273
- const currentIndex = sortedBreakpoints.findIndex(([key]) => key === breakpoint)
274
- const nextBreakpoint = sortedBreakpoints[currentIndex + 1]
275
-
276
- const minWidth = breakpointsPx[breakpoint]
277
- const maxWidth = nextBreakpoint ? nextBreakpoint[1] : Infinity
278
-
279
- return containerWidth >= minWidth && containerWidth < maxWidth
280
- },
281
- [containerWidth, breakpointsPx],
282
- )
283
-
284
- // Create helper components for Tailwind breakpoints
285
- const components = useMemo(
286
- () => ({
287
- 'XsOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('xs') && props.children}</>,
288
- 'SmOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('sm') && props.children}</>,
289
- 'MdOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('md') && props.children}</>,
290
- 'LgOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('lg') && props.children}</>,
291
- 'XlOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('xl') && props.children}</>,
292
- '2xlOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('2xl') && props.children}</>,
293
- '3xlOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('3xl') && props.children}</>,
294
- '4xlOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('4xl') && props.children}</>,
295
- '5xlOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('5xl') && props.children}</>,
296
- '6xlOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('6xl') && props.children}</>,
297
- '7xlOnly': (props: HelperComponentProps) => <>{isExactBreakpoint('7xl') && props.children}</>,
298
- 'XsOrLarger': (props: HelperComponentProps) => (
299
- <>{breakpointMatches.isXs && props.children}</>
300
- ),
301
- 'SmOrLarger': (props: HelperComponentProps) => (
302
- <>{breakpointMatches.isSm && props.children}</>
303
- ),
304
- 'MdOrLarger': (props: HelperComponentProps) => (
305
- <>{breakpointMatches.isMd && props.children}</>
306
- ),
307
- 'LgOrLarger': (props: HelperComponentProps) => (
308
- <>{breakpointMatches.isLg && props.children}</>
309
- ),
310
- 'XlOrLarger': (props: HelperComponentProps) => (
311
- <>{breakpointMatches.isXl && props.children}</>
312
- ),
313
- // Custom query components
314
- ...Object.keys(customQueriesPx).reduce(
315
- (acc, key) => {
316
- const componentName = key.charAt(0).toUpperCase() + key.slice(1)
317
- acc[componentName] = (props: HelperComponentProps): JSX.Element => (
318
- <>{customMatches[key] && props.children}</>
319
- )
320
- return acc
321
- },
322
- {} as Record<string, (props: GenericChildrenType) => JSX.Element>,
323
- ),
324
- }),
325
- [breakpointMatches, customMatches, isExactBreakpoint, customQueriesPx],
326
- )
327
-
328
- return {
329
- containerRef,
330
- queries: { ...breakpointMatches, ...customMatches },
331
- components,
332
- }
333
- }