Skip to content

Commit

Permalink
fix(VTextField): use intersect to recalculate elements width (#9341)
Browse files Browse the repository at this point in the history
* feat: add new mixin to work with IntersectionObserver

* fix(VTextField): use intersect to recalculate elements width

fixes #9299
  • Loading branch information
Djaler authored and johnleider committed Dec 4, 2019
1 parent 39bec78 commit c34f35c
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 1 deletion.
10 changes: 9 additions & 1 deletion packages/vuetify/src/components/VTextField/VTextField.ts
Expand Up @@ -9,6 +9,7 @@ import VCounter from '../VCounter'
import VLabel from '../VLabel'

// Mixins
import Intersectable from '../../mixins/intersectable'
import Loadable from '../../mixins/loadable'

// Directives
Expand All @@ -24,7 +25,14 @@ import { VNode } from 'vue/types'

const baseMixins = mixins(
VInput,
Loadable
Intersectable({
onVisible: [
'setLabelWidth',
'setPrefixWidth',
'setPrependWidth',
],
}),
Loadable,
)
interface options extends InstanceType<typeof baseMixins> {
$refs: {
Expand Down
@@ -0,0 +1,39 @@
import intersectable from '../index'

import {
mount,
Wrapper,
} from '@vue/test-utils'
import { ComponentOptions } from 'vue'

describe('intersectable.ts', () => {
let mountFunction: (options?: ComponentOptions<any>) => Wrapper<any>

beforeEach(() => {
mountFunction = (options?: ComponentOptions<any>) => {
return mount({
render: h => h('div'),
...options,
})
}
})

it('should call callbacks when element is intersected', () => {
const callback = jest.fn()

const wrapper = mountFunction({
mixins: [intersectable({ onVisible: ['callback'] })],
methods: { callback },
})

expect(callback).not.toHaveBeenCalled()

wrapper.vm.onObserve([] as IntersectionObserverEntry[], null as any as IntersectionObserver, false)

expect(callback).not.toHaveBeenCalled()

wrapper.vm.onObserve([] as IntersectionObserverEntry[], null as any as IntersectionObserver, true)

expect(callback).toHaveBeenCalledTimes(1)
})
})
49 changes: 49 additions & 0 deletions packages/vuetify/src/mixins/intersectable/index.ts
@@ -0,0 +1,49 @@
// Directives
import Intersect from '../../directives/intersect'

// Utilities
import { consoleWarn } from '../../util/console'

// Types
import Vue from 'vue'

export default function intersectable (options: { onVisible: string[] }) {
if (typeof window === 'undefined' || !('IntersectionObserver' in window)) {
// do nothing because intersection observer is not available
return Vue.extend({ name: 'intersectable' })
}

return Vue.extend({
name: 'intersectable',

mounted () {
Intersect.inserted(this.$el as HTMLElement, {
name: 'intersect',
value: {
handler: this.onObserve,
},
})
},

destroyed () {
Intersect.unbind(this.$el as HTMLElement)
},

methods: {
onObserve (entries: IntersectionObserverEntry[], observer: IntersectionObserver, isIntersecting: boolean) {
if (!isIntersecting) return

for (let i = 0, length = options.onVisible.length; i < length; i++) {
const callback = (this as any)[options.onVisible[i]]

if (typeof callback === 'function') {
callback()
continue
}

consoleWarn(options.onVisible[i] + ' method is not available on the instance but referenced in intersectable mixin options')
}
},
},
})
}

0 comments on commit c34f35c

Please sign in to comment.