diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ce0a144..3f9bf89 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -85,3 +85,10 @@ jobs:
token: ${{ secrets.CODECOV_TOKEN }}
flags: useBreakpoint
files: ./packages/use-breakpoint/coverage/coverage-final.json
+
+ - name: Upload `Autosizer` coverage reports to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ flags: Autosizer
+ files: ./packages/autosizer/coverage/coverage-final.json
diff --git a/apps/docs/package.json b/apps/docs/package.json
index e95587c..d75f4cb 100644
--- a/apps/docs/package.json
+++ b/apps/docs/package.json
@@ -10,7 +10,7 @@
"clean": "rimraf .turbo && rimraf node_modules && rimraf .next"
},
"dependencies": {
- "@react-awesome/components": "1.0.20",
+ "@react-awesome/components": "1.0.21",
"@vercel/speed-insights": "^1.0.10",
"classnames": "^2.5.1",
"lodash": "^4.17.21",
diff --git a/apps/docs/src/components/examples/Autosizer.tsx b/apps/docs/src/components/examples/Autosizer.tsx
new file mode 100644
index 0000000..a7c9527
--- /dev/null
+++ b/apps/docs/src/components/examples/Autosizer.tsx
@@ -0,0 +1,16 @@
+import { Autosizer } from '@react-awesome/components'
+
+export const AutosizerExample = () => {
+ return (
+
+
+ {({ width, height }) => (
+
+
Width: {width}px
+
Height: {height}px
+
+ )}
+
+
+ )
+}
diff --git a/apps/docs/src/components/examples/index.ts b/apps/docs/src/components/examples/index.ts
index 14d2d97..d288f31 100644
--- a/apps/docs/src/components/examples/index.ts
+++ b/apps/docs/src/components/examples/index.ts
@@ -1,2 +1,3 @@
export * from './PhoneInput/Default'
export * from './PhoneInput/SupportCountry'
+export * from './Autosizer'
diff --git a/apps/docs/src/pages/docs/_meta.json b/apps/docs/src/pages/docs/_meta.json
index 9ff5ce4..0848a24 100644
--- a/apps/docs/src/pages/docs/_meta.json
+++ b/apps/docs/src/pages/docs/_meta.json
@@ -7,6 +7,9 @@
"phone-input": {
"title": "PhoneInput"
},
+ "autosizer": {
+ "title": "Autosizer"
+ },
"-- Hooks": {
"type": "separator",
"title": "Hooks"
diff --git a/apps/docs/src/pages/docs/autosizer.mdx b/apps/docs/src/pages/docs/autosizer.mdx
new file mode 100644
index 0000000..b7f5583
--- /dev/null
+++ b/apps/docs/src/pages/docs/autosizer.mdx
@@ -0,0 +1,60 @@
+---
+title: Autosizer
+---
+
+# Autosizer
+
+**Autosizer** keeps tracking of the parent size and reports it to the children.
+
+## Install
+
+To start using **Autosizer** component, you can install the `@react-awesome/autosizer` library or you can import it directly from `@react-awesome/components` if you have installed it before. In your project directory, run
+the following command to install the dependencies:
+
+```sh npm2yarn
+npm i @react-awesome/autosizer
+```
+
+import { Container } from '../../components/Container'
+import { AutosizerExample } from '../../components/examples'
+
+```jsx
+import { Autosizer } from '@react-awesome/components'
+
+const Example = () => {
+ return (
+
+
+ {({ width, height }) => (
+
+
Width: {width}px
+
Height: {height}px
+
+ )}
+
+
+ )
+}
+```
+
+
+
+
+
+## API
+
+**Autosizer** accepts the following props:
+
+#### `children` (optional)
+
+Children of `Autosizer` is rendered as render props.
+
+- Type: `(size : { width: number, height: number }) => React.ReactNode`
+- Default: `undefined`
+
+#### `initialSize` (optional)
+
+Initial size of the parent component.
+
+- Type: `{ width: number, height: number }`
+- Default: `undefined`
diff --git a/packages/autosizer/.eslintrc.js b/packages/autosizer/.eslintrc.js
new file mode 100644
index 0000000..19f3ed1
--- /dev/null
+++ b/packages/autosizer/.eslintrc.js
@@ -0,0 +1,8 @@
+module.exports = {
+ root: true,
+ extends: ["@react-awesome/eslint-config/library.js"],
+ parser: "@typescript-eslint/parser",
+ parserOptions: {
+ project: true,
+ },
+};
diff --git a/packages/autosizer/README.md b/packages/autosizer/README.md
new file mode 100644
index 0000000..62491ec
--- /dev/null
+++ b/packages/autosizer/README.md
@@ -0,0 +1,32 @@
+# @react-awesome/autosizer
+
+
+
+
+
+
+
+
+
+**autosizer** tracks the previous value of a variable.
+
+Please refer to the [documentation](https://react-awesome-components.vercel.app/docs/autosizer) for more information.
+
+## Installation
+
+```sh
+yarn add @react-awesome/autosizer
+# or
+npm i @react-awesome/autosizer
+```
+
+## Contribution
+
+Yes please! See the
+[contributing guidelines](https://github.com/trinhthinh388/react-awesome-components/blob/master/CONTRIBUTING.md)
+for details.
+
+## Licence
+
+This project is licensed under the terms of the
+[MIT license](https://github.com/trinhthinh388/react-awesome-components/blob/master/LICENSE).
diff --git a/packages/autosizer/package.json b/packages/autosizer/package.json
new file mode 100644
index 0000000..e31931a
--- /dev/null
+++ b/packages/autosizer/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "@react-awesome/autosizer",
+ "version": "0.0.0",
+ "main": "./dist/index.cjs",
+ "module": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "sideEffects": false,
+ "license": "MIT",
+ "description": "Autosizer keeps tracking the parent size and report back to its children.",
+ "keywords": [
+ "react",
+ "autosizer",
+ "resize"
+ ],
+ "repository": {
+ "url": "https://github.com/trinhthinh388/react-awesome-components"
+ },
+ "files": [
+ "dist/**"
+ ],
+ "scripts": {
+ "build": "vite --config ../../vite.config.ts build",
+ "dev": "vite --watch --config ../../vite.config.ts build",
+ "lint": "eslint \"src/**/*.ts*\"",
+ "clean": "rimraf .turbo && rimraf node_modules && rimraf dist",
+ "test": "vitest --config ../../vite.config.ts --coverage --run",
+ "test:ui": "vitest --config ../../vite.config.ts --coverage --ui",
+ "typecheck": "tsc --noEmit"
+ },
+ "devDependencies": {
+ "@react-awesome/eslint-config": "*",
+ "@react-awesome/tsconfig": "*",
+ "@types/react": "^18.2.46",
+ "@types/react-dom": "^18.2.18",
+ "eslint": "^8.56.0",
+ "react": "^18.2.0",
+ "typescript": "^5.3.3"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "dependencies": {
+ "react-merge-refs": "^2.1.1"
+ }
+}
diff --git a/packages/autosizer/src/autosizer.spec.tsx b/packages/autosizer/src/autosizer.spec.tsx
new file mode 100644
index 0000000..bd604ef
--- /dev/null
+++ b/packages/autosizer/src/autosizer.spec.tsx
@@ -0,0 +1,34 @@
+import { Mock } from 'vitest'
+import { Autosizer } from './autosizer'
+import { render } from '@testing-library/react'
+
+describe('useBreakpoint', () => {
+ let MockObserverInstance: ResizeObserver
+ let GlobalResizeObserver: Mock
+
+ beforeEach(() => {
+ MockObserverInstance = {
+ observe: vitest.fn(),
+ unobserve: vitest.fn(),
+ disconnect: vitest.fn(),
+ }
+ GlobalResizeObserver = vitest
+ .fn()
+ .mockImplementation(() => MockObserverInstance)
+ global.ResizeObserver = GlobalResizeObserver
+ })
+
+ afterEach(() => {
+ vitest.resetAllMocks()
+ })
+
+ it('Should observe resize event', async () => {
+ const { unmount } = render()
+
+ expect(MockObserverInstance.observe).toHaveBeenCalled()
+
+ unmount()
+
+ expect(MockObserverInstance.disconnect).toHaveBeenCalled()
+ })
+})
diff --git a/packages/autosizer/src/autosizer.tsx b/packages/autosizer/src/autosizer.tsx
new file mode 100644
index 0000000..bacdb0c
--- /dev/null
+++ b/packages/autosizer/src/autosizer.tsx
@@ -0,0 +1,58 @@
+import React, {
+ forwardRef,
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from 'react'
+import { mergeRefs } from 'react-merge-refs'
+
+export type AutosizerProps = {
+ children?: (_: { width: number; height: number }) => React.ReactNode
+ initialSize?: {
+ width?: number
+ height?: number
+ }
+} & Omit, 'children'>
+
+export const Autosizer = forwardRef(
+ ({ children = () => void 0, initialSize = {}, ...props }, ref) => {
+ const elRef = useRef(null)
+ const [size, setSize] = useState({
+ width: initialSize.width || 0,
+ height: initialSize.height || 0,
+ })
+
+ const watch = useCallback(
+ /* istanbul ignore next */ () => {
+ if (!elRef.current) return
+
+ const observer = new ResizeObserver(
+ /* istanbul ignore next */ (entries) => {
+ if (!entries.length) return
+ const [entry] = entries
+ setSize({
+ width: entry.contentRect.width,
+ height: entry.contentRect.height,
+ })
+ },
+ )
+
+ observer.observe(elRef.current)
+
+ return () => {
+ observer.disconnect()
+ }
+ },
+ [],
+ )
+
+ useEffect(() => watch(), [watch])
+
+ return (
+
+ {children(size)}
+
+ )
+ },
+)
diff --git a/packages/autosizer/src/index.ts b/packages/autosizer/src/index.ts
new file mode 100644
index 0000000..c7868db
--- /dev/null
+++ b/packages/autosizer/src/index.ts
@@ -0,0 +1 @@
+export * from './autosizer'
diff --git a/packages/autosizer/tsconfig.json b/packages/autosizer/tsconfig.json
new file mode 100644
index 0000000..a09969e
--- /dev/null
+++ b/packages/autosizer/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "@react-awesome/tsconfig/react-library.json",
+ "compilerOptions": {
+ "types": ["vitest/globals"],
+ },
+ "include": ["."],
+ "exclude": ["dist", "build", "node_modules"],
+}
diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 05d85b2..d0435ff 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -1,5 +1,11 @@
# @react-awesome/components
+## 1.0.21
+
+### Patch Changes
+
+- Added autosizer
+
## 1.0.20
### Patch Changes
diff --git a/packages/components/package.json b/packages/components/package.json
index d79c634..1901ea8 100644
--- a/packages/components/package.json
+++ b/packages/components/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-awesome/components",
- "version": "1.0.20",
+ "version": "1.0.21",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -45,6 +45,7 @@
"@react-awesome/use-selection-range": "0.0.3",
"@react-awesome/use-previous": "0.0.3",
"@react-awesome/use-toggle": "1.0.0",
- "@react-awesome/use-breakpoint": "1.0.0"
+ "@react-awesome/use-breakpoint": "1.0.0",
+ "@react-awesome/autosizer": "0.0.0"
}
}
diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts
index f823fcd..0f26b3a 100644
--- a/packages/components/src/index.ts
+++ b/packages/components/src/index.ts
@@ -1,4 +1,5 @@
export * from '@react-awesome/phone-input'
+export * from '@react-awesome/autosizer'
/**
* Hooks
diff --git a/turbo.json b/turbo.json
index 9cc6146..bed7f0b 100644
--- a/turbo.json
+++ b/turbo.json
@@ -14,7 +14,8 @@
"@react-awesome/use-selection-range#build",
"@react-awesome/use-preserve-input-caret-position#build",
"@react-awesome/use-click-outside#build",
- "@react-awesome/phone-input#build"
+ "@react-awesome/phone-input#build",
+ "@react-awesome/autosizer#build"
]
},
"test": {
diff --git a/yarn.lock b/yarn.lock
index 28fb6bf..eb31ad1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7034,6 +7034,11 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
+react-merge-refs@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/react-merge-refs/-/react-merge-refs-2.1.1.tgz#e46763f8f1b881c0226ee54a1a2a10ffefba0233"
+ integrity sha512-jLQXJ/URln51zskhgppGJ2ub7b2WFKGq3cl3NYKtlHoTG+dN2q7EzWrn3hN3EgPsTMvpR9tpq5ijdp7YwFZkag==
+
react-refresh@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"