Skip to content

Commit

Permalink
refactor: accordion component (#6462)
Browse files Browse the repository at this point in the history
* feat: add merge-refs

* docs: update changelog

* chore: update context

* chore: update context

* chore: add pure

* refactor: accordion package

* docs: add changelog

* fix: update use-callback-ref

* fix: typescript

* chore: add script to update csb

* chore: update context pkg

* chore: update lockfile
  • Loading branch information
segunadebayo committed Aug 11, 2022
1 parent c89a802 commit dffc18b
Show file tree
Hide file tree
Showing 25 changed files with 284 additions and 119 deletions.
5 changes: 5 additions & 0 deletions .changeset/cyan-adults-whisper.md
@@ -0,0 +1,5 @@
---
"@chakra-ui/accordion": patch
---

Reduce bundle size of accordion by leverage smaller packages
5 changes: 5 additions & 0 deletions .changeset/fluffy-walls-beam.md
@@ -0,0 +1,5 @@
---
"@chakra-ui/utils": patch
---

Add pure annotation to utils package
1 change: 1 addition & 0 deletions .changeset/thirty-spiders-pay.md
Expand Up @@ -2,6 +2,7 @@
"@chakra-ui/react-use-callback-ref": patch
"@chakra-ui/react-use-controllable-state": patch
"@chakra-ui/react-context": patch
"@chakra-ui/react-use-merge-refs": patch
---

Initial release
8 changes: 8 additions & 0 deletions .codesandbox/ci.json
Expand Up @@ -2,6 +2,14 @@
"node": "14",
"sandboxes": ["/examples/create-react-app"],
"packages": [
"hooks/context",
"hooks/use-callback-ref",
"hooks/use-controllable-state",
"hooks/use-disclosure",
"hooks/use-event-listener",
"hooks/use-merge-refs",
"hooks/use-size",
"hooks/use-update-effect",
"packages/accordion",
"packages/alert",
"packages/anatomy",
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -3,6 +3,7 @@
# website public/ folder (temporary; copied to root for docs:build and vercel compat)
# public/

dist
node_modules/
npm-debug.log
packages/**/lib
Expand Down
6 changes: 6 additions & 0 deletions hooks/context/package.json
Expand Up @@ -32,5 +32,11 @@
"clean": "rimraf dist .turbo",
"typecheck": "tsc --noEmit",
"build:fast": "tsup src/index.ts --format=esm,cjs"
},
"peerDependencies": {
"react": ">=18"
},
"devDependencies": {
"react": "^18.0.0"
}
}
15 changes: 10 additions & 5 deletions hooks/context/src/index.ts
Expand Up @@ -3,11 +3,13 @@ import {
useContext as useReactContext,
} from "react"

export interface CreateContextOptions {
export interface CreateContextOptions<T> {
strict?: boolean
hookName?: string
providerName?: string
errorMessage?: string
name?: string
defaultValue?: T
}

export type CreateContextReturn<T> = [
Expand All @@ -17,15 +19,16 @@ export type CreateContextReturn<T> = [
]

function getErrorMessage(hook: string, provider: string) {
return `${hook} returned \`undefined\`. Seems you forgot to wrap component within the ${provider}`
return `${hook} returned \`undefined\`. Seems you forgot to wrap component within ${provider}`
}

export function createContext<T>(options: CreateContextOptions = {}) {
export function createContext<T>(options: CreateContextOptions<T> = {}) {
const {
name,
strict = true,
hookName = "useContext",
providerName = "Provider",
name,
errorMessage,
} = options

const Context = createReactContext<T | undefined>(undefined)
Expand All @@ -36,7 +39,9 @@ export function createContext<T>(options: CreateContextOptions = {}) {
const context = useReactContext(Context)

if (!context && strict) {
const error = new Error(getErrorMessage(hookName, providerName))
const error = new Error(
errorMessage ?? getErrorMessage(hookName, providerName),
)
error.name = "ContextError"
Error.captureStackTrace?.(error, useContext)
throw error
Expand Down
5 changes: 3 additions & 2 deletions hooks/use-callback-ref/src/index.ts
@@ -1,13 +1,14 @@
import { useEffect, useMemo, useRef } from "react"
import { useCallback, useEffect, useRef } from "react"

export function useCallbackRef<T extends (...args: any[]) => any>(
callback: T | undefined,
deps: React.DependencyList = [],
) {
const callbackRef = useRef(callback)

useEffect(() => {
callbackRef.current = callback
})

return useMemo<T>((...args) => callbackRef.current?.(...args), [])
return useCallback(((...args) => callbackRef.current?.(...args)) as T, deps)
}
24 changes: 24 additions & 0 deletions hooks/use-merge-refs/README.md
@@ -0,0 +1,24 @@
# @chakra-ui/use-merge-refs

A Quick description of the component

> This is an internal utility, not intended for public usage.
## Installation

```sh
yarn add @chakra-ui/use-merge-refs
# or
npm i @chakra-ui/use-merge-refs
```

## Contribution

Yes please! See the
[contributing guidelines](https://github.com/chakra-ui/chakra-ui/blob/master/CONTRIBUTING.md)
for details.

## Licence

This project is licensed under the terms of the
[MIT license](https://github.com/chakra-ui/chakra-ui/blob/master/LICENSE).
1 change: 1 addition & 0 deletions hooks/use-merge-refs/index.ts
@@ -0,0 +1 @@
export * from "./src"
42 changes: 42 additions & 0 deletions hooks/use-merge-refs/package.json
@@ -0,0 +1,42 @@
{
"name": "@chakra-ui/react-use-merge-refs",
"version": "1.0.0",
"description": "",
"keywords": [
"use-merge-refs"
],
"author": "Segun Adebayo <sage@adebayosegun.com>",
"homepage": "https://github.com/chakra-ui/chakra-ui#readme",
"license": "MIT",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"sideEffects": false,
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/chakra-ui/chakra-ui.git",
"directory": "hooks/use-merge-refs"
},
"bugs": {
"url": "https://github.com/chakra-ui/chakra-ui/issues"
},
"scripts": {
"build": "tsup src/index.ts --format=esm,cjs --dts",
"dev": "pnpm build -- --watch",
"clean": "rimraf dist .turbo",
"typecheck": "tsc --noEmit",
"build:fast": "tsup src/index.ts --format=esm,cjs"
},
"peerDependencies": {
"react": ">=18"
},
"devDependencies": {
"react": "^18.0.0"
}
}
33 changes: 33 additions & 0 deletions hooks/use-merge-refs/src/index.ts
@@ -0,0 +1,33 @@
import { useMemo } from "react"

export type ReactRef<T> = React.RefCallback<T> | React.MutableRefObject<T>

export function assignRef<T = any>(
ref: ReactRef<T> | null | undefined,
value: T,
) {
if (ref == null) return

if (typeof ref === "function") {
ref(value)
return
}

try {
ref.current = value
} catch (error) {
throw new Error(`Cannot assign value '${value}' to ref '${ref}'`)
}
}

export function mergeRefs<T>(...refs: (ReactRef<T> | null | undefined)[]) {
return (node: T | null) => {
refs.forEach((ref) => {
assignRef(ref, node)
})
}
}

export function useMergeRefs<T>(...refs: (ReactRef<T> | null | undefined)[]) {
return useMemo(() => mergeRefs(...refs), refs)
}
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -35,6 +35,7 @@
"discord": "tsx scripts/discord.ts",
"twitter:gen": "tsx scripts/twitter-generate.ts",
"twitter:write": "tsx scripts/twitter-write.ts",
"csb": "tsx scripts/csb.ts",
"create:pkg": "plop component",
"version": "changeset version",
"release": "changeset publish",
Expand Down
10 changes: 6 additions & 4 deletions packages/accordion/package.json
Expand Up @@ -38,15 +38,17 @@
},
"dependencies": {
"@chakra-ui/descendant": "workspace:*",
"@chakra-ui/hooks": "workspace:*",
"@chakra-ui/react-use-controllable-state": "workspace:*",
"@chakra-ui/react-use-merge-refs": "workspace:*",
"@chakra-ui/react-context": "workspace:*",
"@chakra-ui/icon": "workspace:*",
"@chakra-ui/react-utils": "workspace:*",
"@chakra-ui/transition": "workspace:*",
"@chakra-ui/utils": "workspace:*"
"@chakra-ui/transition": "workspace:*"
},
"devDependencies": {
"@chakra-ui/layout": "workspace:*",
"@chakra-ui/button": "workspace:*",
"@chakra-ui/utils": "workspace:*",
"@chakra-ui/react-use-disclosure": "workspace:*",
"@chakra-ui/system": "workspace:*",
"@chakra-ui/modal": "workspace:*",
"framer-motion": "^6.2.9",
Expand Down
7 changes: 3 additions & 4 deletions packages/accordion/src/accordion-button.tsx
Expand Up @@ -4,7 +4,7 @@ import {
HTMLChakraProps,
SystemStyleObject,
} from "@chakra-ui/system"
import { cx, __DEV__ } from "@chakra-ui/utils"
import { cx } from "@chakra-ui/utils"
import {
useAccordionItemContext,
useAccordionStyles,
Expand Down Expand Up @@ -43,6 +43,5 @@ export const AccordionButton = forwardRef<AccordionButtonProps, "button">(
)
},
)
if (__DEV__) {
AccordionButton.displayName = "AccordionButton"
}

AccordionButton.displayName = "AccordionButton"
14 changes: 7 additions & 7 deletions packages/accordion/src/accordion-context.ts
@@ -1,23 +1,23 @@
import { createDescendantContext } from "@chakra-ui/descendant"
import { createContext } from "@chakra-ui/react-utils"
import { createContext } from "@chakra-ui/react-context"
import { SystemStyleObject } from "@chakra-ui/system"
import { Dict } from "@chakra-ui/utils"
import { UseAccordionItemReturn } from "./use-accordion"

export const [AccordionStylesProvider, useAccordionStyles] = createContext<
Dict<SystemStyleObject>
Record<string, SystemStyleObject>
>({
name: `AccordionStylesContext`,
errorMessage: `useAccordionStyles returned is 'undefined'. Seems you forgot to wrap the components in "<Accordion />" `,
name: "AccordionStylesContext",
hookName: "useAccordionStyles",
providerName: "<Accordion />",
})

type AccordionItemContext = Omit<UseAccordionItemReturn, "htmlProps">

export const [AccordionItemProvider, useAccordionItemContext] =
createContext<AccordionItemContext>({
name: "AccordionItemContext",
errorMessage:
"useAccordionItemContext: `context` is undefined. Seems you forgot to wrap the accordion item parts in `<AccordionItem />` ",
hookName: "useAccordionItemContext",
providerName: "<AccordionItem />",
})

/* -------------------------------------------------------------------------------------------------
Expand Down
7 changes: 3 additions & 4 deletions packages/accordion/src/accordion-icon.tsx
@@ -1,6 +1,6 @@
import { Icon, IconProps } from "@chakra-ui/icon"
import { SystemStyleObject } from "@chakra-ui/system"
import { cx, __DEV__ } from "@chakra-ui/utils"
import { cx } from "@chakra-ui/utils"
import {
useAccordionItemContext,
useAccordionStyles,
Expand Down Expand Up @@ -42,6 +42,5 @@ export function AccordionIcon(props: IconProps) {
</Icon>
)
}
if (__DEV__) {
AccordionIcon.displayName = "AccordionIcon"
}

AccordionIcon.displayName = "AccordionIcon"
25 changes: 12 additions & 13 deletions packages/accordion/src/accordion-item.tsx
@@ -1,11 +1,10 @@
import { MaybeRenderProp } from "@chakra-ui/react-utils"
import {
chakra,
forwardRef,
HTMLChakraProps,
SystemStyleObject,
} from "@chakra-ui/system"
import { cx, Omit, runIfFn, __DEV__ } from "@chakra-ui/utils"
import { cx } from "@chakra-ui/utils"
import { useMemo } from "react"
import {
AccordionItemProvider,
Expand All @@ -20,10 +19,9 @@ export interface AccordionItemProps
keyof UseAccordionItemProps | "children"
>,
UseAccordionItemProps {
children?: MaybeRenderProp<{
isExpanded: boolean
isDisabled: boolean
}>
children?:
| React.ReactNode
| ((props: { isExpanded: boolean; isDisabled: boolean }) => React.ReactNode)
}
/**
* AccordionItem is a single accordion that provides the open-close
Expand Down Expand Up @@ -53,18 +51,19 @@ export const AccordionItem = forwardRef<AccordionItemProps, "div">(
className={cx("chakra-accordion__item", className)}
__css={containerStyles}
>
{runIfFn(children, {
isExpanded: !!context.isOpen,
isDisabled: !!context.isDisabled,
})}
{typeof children === "function"
? children({
isExpanded: !!context.isOpen,
isDisabled: !!context.isDisabled,
})
: children}
</chakra.div>
</AccordionItemProvider>
)
},
)
if (__DEV__) {
AccordionItem.displayName = "AccordionItem"
}

AccordionItem.displayName = "AccordionItem"

/**
* React hook to get the state and actions of an accordion item
Expand Down
6 changes: 2 additions & 4 deletions packages/accordion/src/accordion-panel.tsx
@@ -1,6 +1,6 @@
import { chakra, forwardRef, HTMLChakraProps } from "@chakra-ui/system"
import { Collapse } from "@chakra-ui/transition"
import { cx, __DEV__ } from "@chakra-ui/utils"
import { cx } from "@chakra-ui/utils"
import {
useAccordionItemContext,
useAccordionStyles,
Expand Down Expand Up @@ -42,6 +42,4 @@ export const AccordionPanel = forwardRef<AccordionPanelProps, "div">(
},
)

if (__DEV__) {
AccordionPanel.displayName = "AccordionPanel"
}
AccordionPanel.displayName = "AccordionPanel"

1 comment on commit dffc18b

@vercel
Copy link

@vercel vercel bot commented on dffc18b Aug 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.