Skip to content

Commit c7ed401

Browse files
authored
Merge pull request #17 from microcipcip/feature/useSize
feat(useSize): Adding useSize feature
2 parents dd7c8aa + caae765 commit c7ed401

File tree

10 files changed

+286
-2
lines changed

10 files changed

+286
-2
lines changed

Diff for: README.md

+2
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ export default Vue.extend({
8888
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-usemouseleavepage--demo)
8989
- [`useOrientation`](./src/functions/useOrientation/stories/useOrientation.md) — tracks state of device's screen orientation.
9090
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-useorientation--demo)
91+
- [`useSize`](./src/functions/useSize/stories/useSize.md) — tracks size of an HTML element.
92+
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-usesize--demo)
9193
- [`useScroll`](./src/functions/useScroll/stories/useScroll.md) — tracks an HTML element's scroll position.
9294
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-usescroll--demo)
9395
- [`useSearchParams`](./src/functions/useSearchParams/stories/useSearchParams.md) — tracks browser's location search params.

Diff for: src/functions/useIntersection/stories/useIntersection.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ function useIntersection(
2727
### Returns
2828

2929
- `observedEntry: Ref<IntersectionObserverEntry | null>` the [observed entry](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry)
30-
- `start: Function` the function used for starting observing
31-
- `stop: Function` the function used for stopping observing
30+
- `start: Function` the function used for start observing
31+
- `stop: Function` the function used for stop observing
3232

3333
## Usage
3434

Diff for: src/functions/useSize/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './useSize'

Diff for: src/functions/useSize/stories/UseSizeDemo.vue

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<template>
2+
<div>
3+
<div class="box-actions">
4+
<button class="button is-primary" @click="start" v-if="!isTracking">
5+
Start tracking resize
6+
</button>
7+
<button class="button is-danger" @click="stop" v-else>
8+
Stop tracking resize
9+
</button>
10+
</div>
11+
<div class="box" ref="elRef">
12+
<div class="box__feedback">
13+
{{ Math.ceil(width) }}px - {{ Math.ceil(height) }}px
14+
</div>
15+
<div class="box__container">
16+
<div class="box__message">Resize me!</div>
17+
</div>
18+
</div>
19+
</div>
20+
</template>
21+
22+
<script lang="ts">
23+
import Vue from 'vue'
24+
import { useSize } from '@src/vue-use-kit'
25+
import { ref, watch } from '@src/api'
26+
27+
export default Vue.extend({
28+
name: 'UseSizeDemo',
29+
setup() {
30+
const elRef = ref(null)
31+
const width = ref(0)
32+
const height = ref(0)
33+
const { observedEntry, isTracking, start, stop } = useSize(elRef)
34+
watch(observedEntry, () => {
35+
if (!observedEntry.value) return
36+
width.value = observedEntry.value.contentRect.width
37+
height.value = observedEntry.value.contentRect.height
38+
})
39+
return { elRef, width, height, isTracking, start, stop }
40+
}
41+
})
42+
</script>
43+
44+
<style scoped>
45+
.box-actions {
46+
margin-bottom: 20px;
47+
}
48+
49+
.box {
50+
display: flex;
51+
position: relative;
52+
flex-direction: column;
53+
justify-content: center;
54+
align-items: center;
55+
padding: 0;
56+
resize: both;
57+
overflow: auto;
58+
}
59+
60+
.box__feedback {
61+
position: absolute;
62+
top: 10px;
63+
right: 10px;
64+
color: #666;
65+
text-transform: uppercase;
66+
font-size: 12px;
67+
}
68+
69+
.box__container {
70+
padding: 20px;
71+
}
72+
73+
.box__message {
74+
text-transform: uppercase;
75+
font-weight: bold;
76+
}
77+
</style>

Diff for: src/functions/useSize/stories/useSize.md

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# useSize
2+
3+
Vue function that tracks the size of an HTML element.
4+
5+
This function is based on the [ResizeObserver API](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).
6+
7+
Please note that **ResizeObserver does not work on certain browsers such as IE/Edge/Safari**,
8+
therefore you should add a polyfill such as:
9+
10+
```js
11+
import { ResizeObserver } from '@juggle/resize-observer'
12+
window.ResizeObserver = window.ResizeObserver || ResizeObserver
13+
```
14+
15+
## Reference
16+
17+
```typescript
18+
function useSize(
19+
elRef: Ref<null | HTMLElement>,
20+
options?: ResizeObserverObserveOptions,
21+
runOnMount?: boolean
22+
): {
23+
observedEntry: Ref<ResizeObserverEntry | null>
24+
isTracking: Ref<boolean>
25+
start: () => void
26+
stop: () => void
27+
}
28+
```
29+
30+
### Parameters
31+
32+
- `elRef: Ref<null | HTMLElement>` the element to observe for size changes
33+
- `options: ResizeObserverObserveOptions` the [ResizeObserver options](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/observe)
34+
- `runOnMount: boolean` whether to observe the element on mount, `true` by default
35+
36+
### Returns
37+
38+
- `observedEntry: Ref<ResizeObserverEntry | null>` the [observed entry](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)
39+
- `isTracking: Ref<boolean>` whether this function observer is running or not
40+
- `start: Function` the function used for start observing
41+
- `stop: Function` the function used for stop observing
42+
43+
## Usage
44+
45+
```html
46+
<template>
47+
<div class="box" ref="elRef">
48+
<div class="box__msg">Resize me!</div>
49+
<div class="box__info">{{ width }} {{ height }}</div>
50+
</div>
51+
</template>
52+
53+
<script lang="ts">
54+
import Vue from 'vue'
55+
import { useSize } from 'vue-use-kit'
56+
import { ref, watch } from '@src/api'
57+
58+
export default Vue.extend({
59+
name: 'UseSizeDemo',
60+
setup() {
61+
const elRef = ref(null)
62+
const width = ref(0)
63+
const height = ref(0)
64+
const { observedEntry } = useSize(elRef)
65+
66+
watch(observedEntry, () => {
67+
if (!observedEntry.value) return
68+
const { width, height } = observedEntry.value.contentRect
69+
width.value = width
70+
height.value = height
71+
})
72+
return { elRef, width, height }
73+
}
74+
})
75+
</script>
76+
77+
<style scoped>
78+
.box {
79+
resize: both;
80+
overflow: auto;
81+
}
82+
</style>
83+
```

Diff for: src/functions/useSize/stories/useSize.story.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { storiesOf } from '@storybook/vue'
2+
import path from 'path'
3+
import StoryTitle from '@src/helpers/StoryTitle.vue'
4+
import UseSizeDemo from './UseSizeDemo.vue'
5+
6+
const functionName = 'useSize'
7+
const functionPath = path.resolve(__dirname, '..')
8+
const notes = require(`./${functionName}.md`).default
9+
10+
const basicDemo = () => ({
11+
components: { StoryTitle, demo: UseSizeDemo },
12+
template: `
13+
<div class="container">
14+
<story-title
15+
function-path="${functionPath}"
16+
source-name="${functionName}"
17+
demo-name="UseSizeDemo.vue"
18+
>
19+
<template v-slot:title></template>
20+
<template v-slot:intro>
21+
<p>
22+
<strong>Try to resize the box below by dragging the handle</strong> in the bottom right hand corner.
23+
</p>
24+
</template>
25+
</story-title>
26+
<demo />
27+
</div>`
28+
})
29+
30+
storiesOf('sensors|useSize', module)
31+
.addParameters({ notes })
32+
.add('Demo', basicDemo)

Diff for: src/functions/useSize/useSize.spec.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// import { mount } from '@src/helpers/test'
2+
// import { useSize } from '@src/vue-use-kit'
3+
4+
afterEach(() => {
5+
jest.clearAllMocks()
6+
})
7+
8+
describe('useSize', () => {
9+
it('should do something', () => {
10+
// Add test here
11+
})
12+
})

Diff for: src/functions/useSize/useSize.ts

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { ref, onMounted, onUnmounted, Ref } from '@src/api'
2+
import {
3+
ResizeObserver as ResizeObserverInterface,
4+
ResizeObserverEntry,
5+
ResizeObserverObserveOptions
6+
} from '@src/types/ResizeObserver'
7+
8+
const errorMsg = 'ResizeObserver is not supported, please install a polyfill'
9+
10+
export function useSize(
11+
elRef: Ref<null | HTMLElement>,
12+
options: ResizeObserverObserveOptions = {},
13+
runOnMount = true
14+
) {
15+
const isTracking = ref(false)
16+
const observedEntry: Ref<ResizeObserverEntry | null> = ref(null)
17+
18+
const handleObserver = (entries: ResizeObserverEntry[]) => {
19+
observedEntry.value = entries[0]
20+
}
21+
22+
let observer: ResizeObserverInterface | null = null
23+
24+
const start = () => {
25+
if (isTracking.value) return
26+
if (!('ResizeObserver' in window)) throw new Error(errorMsg)
27+
28+
// Do not start if the observer is already initialized
29+
// or the elRef does not exist
30+
if (!elRef.value) return
31+
observer = new (window as any).ResizeObserver(
32+
handleObserver
33+
) as ResizeObserverInterface
34+
observer.observe(elRef.value, options)
35+
isTracking.value = true
36+
}
37+
38+
const stop = () => {
39+
if (!isTracking.value) return
40+
if (!observer) return
41+
observer.disconnect()
42+
isTracking.value = false
43+
}
44+
45+
onMounted(() => runOnMount && start())
46+
onUnmounted(stop)
47+
48+
return { observedEntry, isTracking, start, stop }
49+
}

Diff for: src/types/ResizeObserver.ts

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export declare class ResizeObserver {
2+
constructor(callback: ResizeObserverCallback)
3+
disconnect: () => void
4+
observe: (target: Element, options?: ResizeObserverObserveOptions) => void
5+
unobserve: (target: Element) => void
6+
}
7+
8+
export interface ResizeObserverEntry {
9+
readonly borderBoxSize: ResizeObserverEntryBoxSize
10+
readonly contentBoxSize: ResizeObserverEntryBoxSize
11+
readonly contentRect: DOMRectReadOnly
12+
readonly target: Element
13+
}
14+
15+
export interface ResizeObserverObserveOptions {
16+
box?: 'content-box' | 'border-box'
17+
}
18+
19+
export type ResizeObserverCallback = (
20+
entries: ResizeObserverEntry[],
21+
observer: ResizeObserver
22+
) => void
23+
24+
export interface ResizeObserverEntryBoxSize {
25+
blockSize: number
26+
inlineSize: number
27+
}

Diff for: src/vue-use-kit.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export * from './functions/useMouse'
1515
export * from './functions/useMouseElement'
1616
export * from './functions/useMouseLeavePage'
1717
export * from './functions/useOrientation'
18+
export * from './functions/useSize'
1819
export * from './functions/useSearchParams'
1920
export * from './functions/useScroll'
2021
// Animations

0 commit comments

Comments
 (0)