Skip to content
This repository was archived by the owner on Sep 20, 2024. It is now read-only.

Commit bf67c21

Browse files
Merge pull request #277 from chakra-ui/feat/use-breakpoint-value
feat: add use-breakpoint hook
2 parents 7c452f9 + 6ffe484 commit bf67c21

File tree

16 files changed

+389
-11
lines changed

16 files changed

+389
-11
lines changed

@types/components.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/**
2-
* Typescript support for @chakra-ui/vue-next2.1.0-beta.2 auto-imported
2+
* Typescript support for @chakra-ui/vue-next2.1.0-beta.3 auto-imported
33
* components using `unplugin-vue-components,`
44
*
55
* @see: https://github.com/antfu/unplugin-vue-components/#typescript
66
*
77
* This is a generated file. Do not edit it's contents.
88
*
9-
* This file was generated on 2023-02-25T17:54:59.918Z
9+
* This file was generated on 2023-02-26T13:58:05.623Z
1010
*/
1111

1212
import { ChakraProps, chakra } from "@chakra-ui/vue-system"

components.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/**
2-
* Typescript support for @chakra-ui/vue-next2.1.0-beta.2 auto-imported
2+
* Typescript support for @chakra-ui/vue-next2.1.0-beta.3 auto-imported
33
* components using `unplugin-vue-components,`
44
*
55
* @see: https://github.com/antfu/unplugin-vue-components/#typescript
66
*
77
* This is a generated file. Do not edit it's contents.
88
*
9-
* This file was generated on 2023-02-25T17:54:59.918Z
9+
* This file was generated on 2023-02-26T13:58:05.623Z
1010
*/
1111

1212
import { ChakraProps, chakra } from "@chakra-ui/vue-system"

packages/c-media-query/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
"dependencies": {
3333
"@chakra-ui/vue-composables": "workspace:*",
3434
"@chakra-ui/vue-system": "workspace:*",
35-
"@chakra-ui/vue-utils": "workspace:*"
35+
"@chakra-ui/vue-utils": "workspace:*",
36+
"@chakra-ui/utils": "2.0.14"
3637
},
3738
"devDependencies": {
3839
"vue": "3.2.47"

packages/c-media-query/src/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ export { CHide } from "./c-hide"
22
export { CShow } from "./c-show"
33
export { CVisibility } from "./c-visibility"
44
export { useQuery } from "./use-query"
5+
export { useBreakpointValue } from "./use-breakpoint-value"
6+
export { useBreakpoint } from "./use-breakpoint"
7+
export { getClosestValue } from "./media.utils"
58

69
export type { CHideProps } from "./c-hide"
710
export type { CShowProps } from "./c-show"
811
export type { CVisbilityProps } from "./c-visibility"
912
export type { UseQueryProps } from "./use-query"
13+
export type { UseBreakpointOptions } from "./use-breakpoint"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { breakpoints as defaultBreakpoints } from "@chakra-ui/utils"
2+
3+
/**
4+
* Returns the closest value to the given breakpoint from
5+
* the given set of breakpoints
6+
*/
7+
export function getClosestValue<T = any>(
8+
values: Record<string, T>,
9+
breakpoint: string,
10+
breakpoints = defaultBreakpoints
11+
) {
12+
let index = Object.keys(values).indexOf(breakpoint)
13+
14+
if (index !== -1) {
15+
return values[breakpoint]
16+
}
17+
18+
let stopIndex = breakpoints.indexOf(breakpoint)
19+
20+
while (stopIndex >= 0) {
21+
const key = breakpoints[stopIndex]
22+
23+
if (values.hasOwnProperty(key)) {
24+
index = stopIndex
25+
break
26+
}
27+
28+
stopIndex -= 1
29+
}
30+
31+
if (index !== -1) {
32+
const key = breakpoints[index]
33+
return values[key]
34+
}
35+
36+
return undefined
37+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { arrayToObjectNotation, isObject } from "@chakra-ui/utils"
2+
import { useTheme } from "@chakra-ui/vue-system"
3+
import { getClosestValue } from "./media.utils"
4+
import { useBreakpoint, UseBreakpointOptions } from "./use-breakpoint"
5+
6+
export function useBreakpointValue<T = any>(
7+
values: Partial<Record<string, T>> | T[],
8+
arg?: UseBreakpointOptions | string
9+
): T | undefined {
10+
const opts = isObject(arg) ? arg : { fallback: arg ?? "base" }
11+
const breakpoint = useBreakpoint(opts)
12+
const theme = useTheme()
13+
14+
if (!breakpoint) return
15+
16+
const breakpoints: string[] = Array.from(theme.__breakpoints?.keys || [])
17+
18+
const obj = Array.isArray(values)
19+
? Object.fromEntries<any>(
20+
Object.entries(arrayToObjectNotation(values, breakpoints)).map(
21+
([key, value]) => [key, value]
22+
)
23+
)
24+
: values
25+
26+
return getClosestValue(obj, breakpoint, breakpoints)
27+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { unref } from "vue"
2+
import { isObject } from "@chakra-ui/utils"
3+
import { useTheme } from "@chakra-ui/vue-system"
4+
import { useMediaQuery } from "@vueuse/core"
5+
6+
export type UseBreakpointOptions = {
7+
fallback?: string
8+
}
9+
10+
/**
11+
* Composable used to get the current responsive media breakpoint
12+
*/
13+
export function useBreakpoint(arg?: string | UseBreakpointOptions) {
14+
const opts = isObject(arg) ? arg : { fallback: arg ?? "base" }
15+
const theme = useTheme()
16+
17+
// Explicitly creating the type due to the typing of
18+
// `theme.__breakpoints` not being deep enough to recognize it's properties
19+
type BreakpointsObjectType = {
20+
query: string
21+
breakpoint: string
22+
}
23+
24+
const breakpoints: BreakpointsObjectType[] = theme.__breakpoints!.details.map(
25+
({ minMaxQuery, breakpoint }: any) => ({
26+
breakpoint,
27+
query: minMaxQuery.replace("@media screen and ", ""),
28+
})
29+
)
30+
const values = breakpoints.map((bp) => {
31+
const bpQuery = useMediaQuery(bp.query)
32+
33+
return bpQuery
34+
})
35+
36+
const index = unref(values).findIndex((value) => value.value == true)
37+
38+
return breakpoints[index]?.breakpoint ?? opts.fallback
39+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/// <reference types="jest" />
2+
3+
import { getClosestValue } from "../src/media.utils"
4+
5+
describe("`getClosestValue` function", () => {
6+
test("should get the closest responsive value", () => {
7+
expect(getClosestValue({ base: "40px", md: "500px" }, "xl")).toBe("500px")
8+
expect(getClosestValue({ base: "40px", md: "500px" }, "sm")).toBe("40px")
9+
expect(getClosestValue({ base: "40px" }, "lg")).toBe("40px")
10+
expect(getClosestValue({ sm: "40px", md: "500px" }, "sm")).toBe("40px")
11+
expect(getClosestValue({ sm: "40px", md: "500px" }, "base")).toBe(undefined)
12+
expect(getClosestValue({}, "")).toBe(undefined)
13+
})
14+
15+
test("should get the closest responsive value even if values contains nullable value", () => {
16+
expect(getClosestValue({ base: "40px", md: undefined }, "xl")).toBe(
17+
undefined
18+
)
19+
expect(getClosestValue({ base: "40px", md: null }, "xl")).toBe(null)
20+
expect(getClosestValue({ sm: "40px", md: undefined }, "xl")).toBe(undefined)
21+
expect(getClosestValue({ sm: "40px", md: null }, "xl")).toBe(null)
22+
})
23+
24+
test("should get the closest responsive value with custom breakpoints", () => {
25+
const customBreakPoints = ["base", "sm", "md", "custom", "xl"]
26+
expect(
27+
getClosestValue(
28+
{ base: "40px", md: "500px", custom: "600px" },
29+
"xl",
30+
customBreakPoints
31+
)
32+
).toBe("600px")
33+
expect(
34+
getClosestValue({ base: "40px", md: "500px" }, "sm", customBreakPoints)
35+
).toBe("40px")
36+
expect(getClosestValue({ base: "40px" }, "custom", customBreakPoints)).toBe(
37+
"40px"
38+
)
39+
expect(
40+
getClosestValue({ sm: "40px", md: "500px" }, "sm", customBreakPoints)
41+
).toBe("40px")
42+
expect(
43+
getClosestValue({ sm: "40px", md: "500px" }, "base", customBreakPoints)
44+
).toBe(undefined)
45+
expect(getClosestValue({}, "")).toBe(undefined)
46+
})
47+
})

packages/c-motion/examples/with-collapse.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
</template>
3232

3333
<script lang="ts" setup>
34+
import { chakra } from "../../vue"
3435
import { useToggle } from "@vueuse/core"
3536
import { CCollapse } from "../src"
3637

packages/c-motion/src/c-collapse.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
watch,
1111
withDirectives,
1212
onMounted,
13-
watchEffect,
1413
} from "vue"
1514
import { TransitionEasings, TransitionVariants } from "./motion-utils"
1615
import { warn } from "@chakra-ui/utils"

0 commit comments

Comments
 (0)