diff --git a/packages/core/use-size/README.md b/packages/core/use-size/README.md new file mode 100644 index 000000000..f05912cd7 --- /dev/null +++ b/packages/core/use-size/README.md @@ -0,0 +1,10 @@ +# `@oku-ui/use-size` + +## Installation + +```sh +$ pnpm add @oku-ui/use-size +``` + +## Usage +... \ No newline at end of file diff --git a/packages/core/use-size/package.json b/packages/core/use-size/package.json new file mode 100644 index 000000000..15e0a0ab1 --- /dev/null +++ b/packages/core/use-size/package.json @@ -0,0 +1,43 @@ +{ + "name": "@oku-ui/use-size", + "type": "module", + "version": "1.0.0", + "license": "MIT", + "source": "src/index.ts", + "funding": "https://github.com/sponsors/productdevbook", + "homepage": "https://oku-ui.com/primitives", + "repository": { + "type": "git", + "url": "git+https://github.com/oku-ui/primitives.git" + }, + "bugs": { + "url": "https://github.com/oku-ui/primitives/issues" + }, + "exports": { + ".": { + "types": "./dist/types/index.d.ts", + "require": "./dist/use-size.cjs", + "import": "./dist/use-size.js" + } + }, + "main": "dist/use-size.cjs", + "module": "dist/use-size.js", + "types": "dist/types/index.d.ts", + "files": [ + "dist", + "README.md" + ], + "scripts": { + "clean": "rm -rf dist", + "build": "vite build --mode production", + "lint": "eslint .", + "lint:fix": "eslint . --fix" + }, + "peerDependencies": { + "vue": "^3.2.47" + }, + "devDependencies": { + "@types/resize-observer-browser": "^0.1.7", + "tsconfig": "workspace:^" + } +} diff --git a/packages/core/use-size/src/index.ts b/packages/core/use-size/src/index.ts new file mode 100644 index 000000000..18de6d75b --- /dev/null +++ b/packages/core/use-size/src/index.ts @@ -0,0 +1 @@ +export { useSize } from './use-size' diff --git a/packages/core/use-size/src/use-size.ts b/packages/core/use-size/src/use-size.ts new file mode 100644 index 000000000..cd8b957be --- /dev/null +++ b/packages/core/use-size/src/use-size.ts @@ -0,0 +1,75 @@ +/// + +import type { WatchStopHandle } from 'vue' +import { onMounted, onUnmounted, ref, watch } from 'vue' + +interface Size { + width: number + height: number +} + +function useSize(element: HTMLElement | null) { + const size = ref() + let stopHandle: WatchStopHandle + let resizeObserver: ResizeObserver + + onMounted(() => { + if (element) { + size.value = { width: element.offsetWidth, height: element.offsetHeight } + + resizeObserver = new ResizeObserver((entries) => { + if (!Array.isArray(entries)) + return + + // Since we only observe the one element, we don't need to loop over the + // array + if (!entries.length) + return + + const entry = entries[0] + let width: number + let height: number + + if ('borderBoxSize' in entry) { + const borderSizeEntry = entry.borderBoxSize + // iron out differences between browsers + const borderSize = Array.isArray(borderSizeEntry) ? borderSizeEntry[0] : borderSizeEntry + width = borderSize.inlineSize + height = borderSize.blockSize + } + else { + // for browsers that don't support `borderBoxSize` + // we calculate it ourselves to get the correct border box. + width = element.offsetWidth + height = element.offsetHeight + } + + size.value = { width, height } + }) + + resizeObserver.observe(element) + + stopHandle = watch(element, (newValue, oldValue) => { + if (oldValue) + resizeObserver.unobserve(oldValue) + + if (newValue) + resizeObserver.observe(newValue) + }) + } + else { + size.value = undefined + } + }) + + onUnmounted(() => { + if (element) { + stopHandle() + resizeObserver.unobserve(element) + } + }) + + return size +} + +export { useSize } diff --git a/packages/core/use-size/tsconfig.json b/packages/core/use-size/tsconfig.json new file mode 100644 index 000000000..01616135e --- /dev/null +++ b/packages/core/use-size/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./../../../tsconfig.json", + "compilerOptions": { + "baseUrl": "." + }, + "include": [ + "./" + ] +} diff --git a/packages/core/use-size/vite.config.ts b/packages/core/use-size/vite.config.ts new file mode 100644 index 000000000..206f3258c --- /dev/null +++ b/packages/core/use-size/vite.config.ts @@ -0,0 +1,48 @@ +import path, { resolve } from 'node:path' + +import Vue from '@vitejs/plugin-vue' +import { defineConfig } from 'vite' + +// https://github.com/qmhc/vite-plugin-dts +import dtsPlugin from 'vite-plugin-dts' + +// https://github.com/sxzz/unplugin-vue-macros +import VueMacros from 'unplugin-vue-macros/vite' + +import * as pkg from './package.json' + +const externals = [ + ...Object.keys(pkg.peerDependencies || {}), + ...Object.keys(pkg.dependencies || {}), +] +export default defineConfig({ + plugins: [ + dtsPlugin({ + include: ['./src/**/*.ts', './src/**/*.tsx', './src/**/*.vue'], + skipDiagnostics: false, + staticImport: true, + outputDir: ['./dist/types'], + cleanVueFileName: false, + }), + VueMacros({ + plugins: { + vue: Vue(), + }, + }), + ], + resolve: { + alias: { + '@': resolve(__dirname, 'src'), + }, + }, + build: { + target: 'modules', + lib: { + entry: path.resolve(__dirname, './src/index.ts'), + formats: ['es', 'cjs'], + }, + rollupOptions: { + external: externals, + }, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c463926dd..2526eb3df 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -127,6 +127,16 @@ importers: specifier: ^3.3.0-beta.3 version: 3.3.0-beta.3 + packages/core/compose-refs: + dependencies: + vue: + specifier: ^3.2.47 + version: 3.2.47 + devDependencies: + tsconfig: + specifier: workspace:^ + version: link:../../tsconfig + packages/core/primitive: dependencies: vue: @@ -170,6 +180,25 @@ importers: specifier: workspace:^ version: link:../../tsconfig + packages/core/use-previous: + dependencies: + vue: + specifier: ^3.2.47 + version: 3.2.47 + devDependencies: + tsconfig: + specifier: workspace:^ + version: link:../../tsconfig + + packages/core/use-size: + devDependencies: + '@types/resize-observer-browser': + specifier: ^0.1.7 + version: 0.1.7 + tsconfig: + specifier: workspace:^ + version: link:../../tsconfig + packages/eslint-config-custom: dependencies: '@antfu/eslint-config': @@ -3715,6 +3744,10 @@ packages: csstype: 3.1.2 dev: true + /@types/resize-observer-browser@0.1.7: + resolution: {integrity: sha512-G9eN0Sn0ii9PWQ3Vl72jDPgeJwRWhv2Qk/nQkJuWmRmOB4HX3/BhD5SE1dZs/hzPZL/WKnvF0RHdTSG54QJFyg==} + dev: true + /@types/resolve@1.20.2: resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} dev: true