Full Code of heavyy/vue-intersect for AI

master 0a8123f30748 cached
12 files
17.7 KB
5.0k tokens
8 symbols
1 requests
Download .txt
Repository: heavyy/vue-intersect
Branch: master
Commit: 0a8123f30748
Files: 12
Total size: 17.7 KB

Directory structure:
gitextract_ucdwe_b3/

├── .babelrc
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── __mocks__/
│   └── intersection-observer.js
├── __tests__/
│   └── index.js
├── dist/
│   └── index.js
├── package.json
└── src/
    └── index.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .babelrc
================================================
{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }]
  ],
  "plugins": ["transform-runtime"],
  "env": {
    "test": {
      "presets": ["env"]
    }
  }
}


================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

================================================
FILE: .eslintrc.js
================================================
module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module'
  },
  env: {
    browser: true,
  },
  extends: 'standard',
  'rules': {
    'arrow-parens': 0
  }
}


================================================
FILE: .gitignore
================================================
.DS_Store
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
coverage/


================================================
FILE: .travis.yml
================================================
language: node_js

node_js:
  - "6"
  - "7"
  - "8"

after_script: "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js"


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2017 Heavyy IvS

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Vue Intersect
**A Vue component to add intersection-observer to a Vue component or HTML element.**

[![npm version](https://badge.fury.io/js/vue-intersect.svg)](https://badge.fury.io/js/vue-intersect) [![Coverage Status](https://coveralls.io/repos/github/heavyy/vue-intersect/badge.svg)](https://coveralls.io/github/heavyy/vue-intersect) [![Build status](https://img.shields.io/travis/heavyy/vue-intersect.svg)](https://travis-ci.org/heavyy/vue-intersect)



## Table of content

* [Introduction](#introduction)
* [Demo](#demo)
* [Installation](#installation)
* [Usage](#usage)
* [Properties](#properties)
* [Events](#events)
* [Polyfill](#polyfill)

## Introduction

The [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) is an amazing API which allows you to observe one or more HTMLElement for when it has entered or left the viewport.

This API has many use cases like, infinite-scroll, lazy-loading or animations when an element enters the viewport.



## Demo

We've made a basic demo of how you might want to use **vue-intersect**. The code is available in the [gh-pages branch](https://github.com/heavyy/vue-intersect/tree/gh-pages) and the part where **vue-intersect** is used [can be found here](https://github.com/heavyy/vue-intersect/blob/gh-pages/src/components/InfiniteScrollItem.vue#L33).

[Hackernews infinite scroll demo](https://heavyy.github.io/vue-intersect/)

> Please keep in mind that the demo is not production code. Use it as an inspiration.



## Installation

Simply install using your favorite package manager 🔥

> ⚠️ If you're using Vue 3 then install `vue-intersect@next`

#### NPM

```bash
npm install vue-intersect --save
```

#### Yarn
```bash
yarn add vue-intersect
```



## Usage

The package acts as an abstract component, much like what you may know from [keep-alive](https://vuejs.org/v2/api/#keep-alive) or [transition](https://vuejs.org/v2/api/#transition).

This means that it's basically a "decorator". A component which does not output any markup to the DOM, but adds the functionality under the hood 😱.

#### .vue

```html
<template>
  <intersect @enter="msg = 'Intersected'" @leave="msg = 'Not intersected'">
    <div>{{ msg }}</div>
  </intersect>
</template>

<script>
  import Intersect from 'vue-intersect'

  export default {
    components: { Intersect },
    data () {
      return {
        msg: 'I will change'
      }
    }
  }
</script>
```



## Properties

| Property   | Type        | Default           | Required | Description                              |
| ---------- | ----------- | ----------------- | -------- | ---------------------------------------- |
| threshold  | Array       | [0, 0.2]          | *no*     | [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options) |
| root       | HTMLElement | null              | *no*     | [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options) |
| rootMargin | String      | *0px 0px 0px 0px* | *no*     | [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options) |



## Events

| Name       | Arguments                                | Description                              |
| ---------- | ---------------------------------------- | ---------------------------------------- |
| **change** | [*IntersectionObserverEntry*](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) | Event fired on any inte.                 |
| **enter**  | [*IntersectionObserverEntry*](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) | Event fired when the element is intersected (visible on the screen) |
| **leave**  | [*IntersectionObserverEntry*](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) | Event fired when the element is *not* intersected (not visible on the screen) |
| **destroyed** | None | Fired when the underlying element is destroyed |



> The **enter** and **leave** event is sugar, for an often performed operation. You still have to set the threshold to e.g. [0, 0.2] (default). If you leave out "0", it will never call the **leave** event.



The events is compliant with Vue's [event modifiers](https://vuejs.org/v2/guide/events.html#Event-Modifiers). This means that you could add `.once` to the events to make sure you only trigger your event handler once.



## Polyfill

The IntersectionObserver API is not currently available in all browsers ([IE11, Safari and iOS Safari](http://caniuse.com/#feat=intersectionobserver)). If you intend to support these browsers, you'll need to add a poylfill to your bundle.

[WICG IntersectionObserver Polyfill](https://github.com/w3c/IntersectionObserver/tree/master/polyfill) is highly recommended.


================================================
FILE: __mocks__/intersection-observer.js
================================================
export default class IntersectionObserver {
  constructor (cb, options) {
    this.cb = cb
    this.options = options
    this.observables = []
  }

  observe (el) {
    this.observables.push(el)
  }

  disconnect () {
    return true
  }
}


================================================
FILE: __tests__/index.js
================================================
import Vue from 'vue/dist/vue.js'
import IntersectionObserver from '../__mocks__/intersection-observer.js'
import Intersect from '../src'

// Mock
global.IntersectionObserver = IntersectionObserver

test('It should be a function', () => {
  expect(typeof Intersect.mounted).toBe('function')
})

test('It should create a instance of IntersectionObserver', async () => {
  global.console.warn = jest.fn()
  const vm = new Vue(Intersect).$mount()
  expect(vm.observer).toBeInstanceOf(IntersectionObserver)

  await vm.$nextTick

  expect(global.console.warn).toHaveBeenCalledTimes(1)
})

test('It should mount correctly and add the item to the observers list', async () => {
  const mockedIntersect = Object.assign({}, Intersect)

  const spy = {
    mounted: jest.spyOn(mockedIntersect, 'mounted')
  }

  const vm = new Vue({
    template: `<intersect><div ref="intersect">this is my component</div></intersect>`,
    components: {Intersect: mockedIntersect}
  }).$mount()

  await Vue.nextTick()

  expect(vm._vnode.componentInstance.observer.observables.length).toBe(1)

  expect(spy.mounted).toHaveBeenCalledTimes(1)

  expect(vm.$el.outerHTML).toBe(`<div>this is my component</div>`)
  expect(vm.$el.textContent).toBe('this is my component')
})

test('It should emit "enter" event when the component is intersected', async () => {
  const mockedIntersect = Object.assign({}, Intersect)
  const spy = jest.fn()

  const vm = new Vue({
    template: `<intersect @enter="onEnter"><div></div></intersect>`,
    components: {Intersect: mockedIntersect},
    methods: {
      onEnter: spy
    }
  }).$mount()

  await vm.$nextTick()

  vm._vnode.componentInstance.observer.cb([{
    isIntersecting: true
  }])

  expect(spy).toHaveBeenCalledTimes(1)
})

test('It should emit "leave" event when the component is not intersected', async () => {
  const mockedIntersect = Object.assign({}, Intersect)
  const spy = jest.fn()

  const vm = new Vue({
    template: `<intersect @leave="onLeave"><div></div></intersect>`,
    components: {Intersect: mockedIntersect},
    methods: {
      onLeave: spy
    }
  }).$mount()

  await vm.$nextTick()

  vm._vnode.componentInstance.observer.cb([{
    isIntersecting: false
  }])

  expect(spy).toHaveBeenCalledTimes(1)
})

test('It should emit "change" on any intersection change', async () => {
  const mockedIntersect = Object.assign({}, Intersect)
  const spy = jest.fn()

  const vm = new Vue({
    template: `<intersect @change="onChange"><div></div></intersect>`,
    components: {Intersect: mockedIntersect},
    methods: {
      onChange: spy
    }
  }).$mount()

  await vm.$nextTick()

  vm._vnode.componentInstance.observer.cb([{
    isIntersecting: false
  }])

  vm._vnode.componentInstance.observer.cb([{
    isIntersecting: true
  }])

  expect(spy).toHaveBeenCalledTimes(2)
})

test('It should be possible to set the threshold property', async () => {
  const mockedIntersect = Object.assign({}, Intersect)
  const vm = new Vue({
    template: `<intersect :threshold="[0, 0.5]"><div></div></intersect>`,
    components: {Intersect: mockedIntersect}
  }).$mount()

  await vm.$nextTick()

  expect(vm._vnode.componentInstance.$options.propsData.threshold).toEqual([0, 0.5])
})

test('It should be possible to set the root property', async () => {
  const mockedIntersect = Object.assign({}, Intersect)
  const vm = new Vue({
    template: `<intersect :root="viewPort"><div></div></intersect>`,
    components: {Intersect: mockedIntersect},
    data () {
      return {
        viewPort: document.body
      }
    }
  }).$mount()

  await vm.$nextTick()
  expect(vm._vnode.componentInstance.$options.propsData.root).toBeInstanceOf(HTMLElement)
})

test('It should be possible to set the rootMargin property', async () => {
  const mockedIntersect = Object.assign({}, Intersect)
  const vm = new Vue({
    template: `<intersect root-margin="1px 1px 1px 1px"><div></div></intersect>`,
    components: {Intersect: mockedIntersect}
  }).$mount()

  await vm.$nextTick()
  expect(vm._vnode.componentInstance.$options.propsData.rootMargin).toBe('1px 1px 1px 1px')
})

test('It should disconnect the IntersectionObserver when the component is destroyed', async () => {
  const mockedIntersect = Object.assign({}, Intersect)

  const spy = {
    destroyed: jest.spyOn(mockedIntersect, 'destroyed'),
    disconnect: jest.spyOn(global.IntersectionObserver.prototype, 'disconnect')
  }

  const vm = new Vue({
    template: `<intersect><div></div></intersect>`,
    components: {Intersect: mockedIntersect}
  }).$mount()

  await vm.$nextTick()

  vm.$destroy()
  expect(spy.destroyed).toHaveBeenCalledTimes(1)
  expect(spy.disconnect).toHaveBeenCalledTimes(1)
  spy.disconnect.mockClear()
})

test('It should emit event when component is destroyed', async () => {
  const mockedIntersect = Object.assign({}, Intersect)
  const onDestroy = jest.fn()

  const spy = {
    destroyed: jest.spyOn(mockedIntersect, 'destroyed'),
    disconnect: jest.spyOn(global.IntersectionObserver.prototype, 'disconnect')
  }

  const vm = new Vue({
    template: `<intersect @destroyed="onDestroy"><div></div></intersect>`,
    components: {Intersect: mockedIntersect},
    methods: {
      onDestroy
    }
  }).$mount()

  await vm.$nextTick()

  vm.$destroy()

  expect(spy.destroyed).toHaveBeenCalledTimes(1)
  expect(spy.disconnect).toHaveBeenCalledTimes(1)
  expect(onDestroy).toHaveBeenCalledTimes(1)
})

test('It should warn when no child component is defined', async () => {
  global.console.warn = jest.fn()

  const vm = new Vue({
    template: `<intersect></intersect>`,
    components: {Intersect}
  }).$mount()

  await vm.$nextTick()

  expect(global.console.warn).toHaveBeenCalledTimes(1)
  expect(vm._vnode.componentInstance.observer.observables.length).toBe(0)

  global.console.warn.mockReset()
})

test('It should warn if more than one child component is defined', async () => {
  global.console.warn = jest.fn()
  const vm = new Vue({
    template: `<intersect><div></div><div></div></intersect>`,
    components: {Intersect}
  }).$mount()

  await vm.$nextTick()

  expect(global.console.warn).toHaveBeenCalledTimes(1)
  expect(vm._vnode.componentInstance.observer.observables.length).toBe(1)

  global.console.warn.mockReset()
})

test('It should not warn if Vue.config.silent is set to false', async () => {
  require('vue').config.silent = true

  global.console.warn = jest.fn()

  const vm = new Vue({
    template: `<intersect><div></div><div></div></intersect>`,
    components: {Intersect}
  }).$mount()

  await vm.$nextTick()

  expect(global.console.warn).toHaveBeenCalledTimes(0)
  expect(vm._vnode.componentInstance.observer.observables.length).toBe(1)

  global.console.warn.mockReset()
})


================================================
FILE: dist/index.js
================================================
import Vue from 'vue';

var warn = function warn(msg) {
  if (!Vue.config.silent) {
    console.warn(msg);
  }
};

export default {
  name: 'intersect',
  abstract: true,
  props: {
    threshold: {
      type: Array,
      required: false,
      default: function _default() {
        return [0.2];
      }
    },
    root: {
      type: HTMLElement,
      required: false,
      default: function _default() {
        return null;
      }
    },
    rootMargin: {
      type: String,
      required: false,
      default: function _default() {
        return '0px 0px 0px 0px';
      }
    }
  },
  created: function created() {
    var _this = this;

    this.observer = new IntersectionObserver(function (entries) {
      if (!entries[0].isIntersecting) {
        _this.$emit('leave', [entries[0]]);
      } else {
        _this.$emit('enter', [entries[0]]);
      }

      _this.$emit('change', [entries[0]]);
    }, {
      threshold: this.threshold,
      root: this.root,
      rootMargin: this.rootMargin
    });
  },
  mounted: function mounted() {
    var _this2 = this;

    this.$nextTick(function () {
      if (_this2.$slots.default && _this2.$slots.default.length > 1) {
        warn('[VueIntersect] You may only wrap one element in a <intersect> component.');
      } else if (!_this2.$slots.default || _this2.$slots.default.length < 1) {
        warn('[VueIntersect] You must have one child inside a <intersect> component.');
        return;
      }

      _this2.observer.observe(_this2.$slots.default[0].elm);
    });
  },
  destroyed: function destroyed() {
    this.observer.disconnect();
  },
  render: function render() {
    return this.$slots.default ? this.$slots.default[0] : null;
  }
};

================================================
FILE: package.json
================================================
{
  "name": "vue-intersect",
  "version": "1.1.5",
  "description": "A Vue component to add intersection-observer to a Vue component or HTML element.",
  "main": "dist/index.js",
  "repository": "git@github.com:heavyy/vue-intersect.git",
  "author": "Heavyy <hello@heavyy.io>",
  "license": "MIT",
  "scripts": {
    "test": "./node_modules/.bin/jest --coverage --coverageDirectory coverage",
    "lint": "./node_modules/.bin/eslint -c ./.eslintrc.js src/**/*.js",
    "lint:fix": "./node_modules/.bin/eslint -c ./.eslintrc.js src/**/*.js --fix",
    "build": "./node_modules/.bin/babel ./src -d ./dist/"
  },
  "peerDependencies": {
    "vue": "^2.4.2"
  },
  "devDependencies": {
    "vue": "^2.4.2",
    "babel-cli": "^6.24.1",
    "babel-core": "^6.25.0",
    "babel-eslint": "^7.2.3",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.6.0",
    "coveralls": "^2.13.1",
    "eslint": "^4.4.1",
    "eslint-config-standard": "^10.2.1",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^5.1.1",
    "eslint-plugin-promise": "^3.5.0",
    "eslint-plugin-standard": "^3.0.1",
    "jest": "^20.0.4"
  }
}


================================================
FILE: src/index.js
================================================
import Vue from 'vue'

const warn = (msg) => {
  if (!Vue.config.silent) {
    console.warn(msg)
  }
}

export default {
  name: 'intersect',
  abstract: true,
  props: {
    threshold: {
      type: Array,
      required: false,
      default: () => [0, 0.2]
    },
    root: {
      type: typeof HTMLElement !== 'undefined' ? HTMLElement : Object,
      required: false,
      default: () => null
    },
    rootMargin: {
      type: String,
      required: false,
      default: () => '0px 0px 0px 0px'
    }
  },
  mounted () {
    this.observer = new IntersectionObserver((entries) => {
      if (!entries[0].isIntersecting) {
        this.$emit('leave', [entries[0]])
      } else {
        this.$emit('enter', [entries[0]])
      }

      this.$emit('change', [entries[0]])
    }, {
      threshold: this.threshold,
      root: this.root,
      rootMargin: this.rootMargin
    })

    this.$nextTick(() => {
      if (this.$slots.default && this.$slots.default.length > 1) {
        warn('[VueIntersect] You may only wrap one element in a <intersect> component.')
      } else if (!this.$slots.default || this.$slots.default.length < 1) {
        warn('[VueIntersect] You must have one child inside a <intersect> component.')
        return
      }

      this.observer.observe(this.$slots.default[0].elm)
    })
  },
  destroyed () {
    this.$emit('destroyed')
    this.observer.disconnect()
  },
  render () {
    return this.$slots.default ? this.$slots.default[0] : null
  }
}
Download .txt
gitextract_ucdwe_b3/

├── .babelrc
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── __mocks__/
│   └── intersection-observer.js
├── __tests__/
│   └── index.js
├── dist/
│   └── index.js
├── package.json
└── src/
    └── index.js
Download .txt
SYMBOL INDEX (8 symbols across 3 files)

FILE: __mocks__/intersection-observer.js
  class IntersectionObserver (line 1) | class IntersectionObserver {
    method constructor (line 2) | constructor (cb, options) {
    method observe (line 8) | observe (el) {
    method disconnect (line 12) | disconnect () {

FILE: __tests__/index.js
  method data (line 128) | data () {

FILE: src/index.js
  method mounted (line 29) | mounted () {
  method destroyed (line 55) | destroyed () {
  method render (line 59) | render () {
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (19K chars).
[
  {
    "path": ".babelrc",
    "chars": 255,
    "preview": "{\n  \"presets\": [\n    [\"env\", {\n      \"modules\": false,\n      \"targets\": {\n        \"browsers\": [\"> 1%\", \"last 2 versions\""
  },
  {
    "path": ".editorconfig",
    "chars": 146,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_"
  },
  {
    "path": ".eslintrc.js",
    "chars": 205,
    "preview": "module.exports = {\n  root: true,\n  parser: 'babel-eslint',\n  parserOptions: {\n    sourceType: 'module'\n  },\n  env: {\n   "
  },
  {
    "path": ".gitignore",
    "chars": 81,
    "preview": ".DS_Store\nnode_modules/\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\ncoverage/\n"
  },
  {
    "path": ".travis.yml",
    "chars": 138,
    "preview": "language: node_js\n\nnode_js:\n  - \"6\"\n  - \"7\"\n  - \"8\"\n\nafter_script: \"cat ./coverage/lcov.info | ./node_modules/coveralls/"
  },
  {
    "path": "LICENSE",
    "chars": 1077,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Heavyy IvS\n\nPermission is hereby granted, free of charge, to any person obtain"
  },
  {
    "path": "README.md",
    "chars": 4872,
    "preview": "# Vue Intersect\n**A Vue component to add intersection-observer to a Vue component or HTML element.**\n\n[![npm version](ht"
  },
  {
    "path": "__mocks__/intersection-observer.js",
    "chars": 241,
    "preview": "export default class IntersectionObserver {\n  constructor (cb, options) {\n    this.cb = cb\n    this.options = options\n  "
  },
  {
    "path": "__tests__/index.js",
    "chars": 6745,
    "preview": "import Vue from 'vue/dist/vue.js'\nimport IntersectionObserver from '../__mocks__/intersection-observer.js'\nimport Inters"
  },
  {
    "path": "dist/index.js",
    "chars": 1716,
    "preview": "import Vue from 'vue';\n\nvar warn = function warn(msg) {\n  if (!Vue.config.silent) {\n    console.warn(msg);\n  }\n};\n\nexpor"
  },
  {
    "path": "package.json",
    "chars": 1147,
    "preview": "{\n  \"name\": \"vue-intersect\",\n  \"version\": \"1.1.5\",\n  \"description\": \"A Vue component to add intersection-observer to a V"
  },
  {
    "path": "src/index.js",
    "chars": 1489,
    "preview": "import Vue from 'vue'\n\nconst warn = (msg) => {\n  if (!Vue.config.silent) {\n    console.warn(msg)\n  }\n}\n\nexport default {"
  }
]

About this extraction

This page contains the full source code of the heavyy/vue-intersect GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (17.7 KB), approximately 5.0k tokens, and a symbol index with 8 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!