diff --git a/.gitignore b/.gitignore
index b6682fa..3f235ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,6 @@ build/
dist/
lib/
es/
+esm/
+es2017/
+.docusaurus/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 357d3f8..8449b63 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## 0.2.0
+
+- [refactor] Using ICE PKG to build the package.
+- [feature] Support minimum version of appear-polyfill.
+- [refactor] Support passive event listener.
## 0.1.3
- [feat] Support custom option `endReachedThreshold`
\ No newline at end of file
diff --git a/README.md b/README.md
index 9f20638..5b6836a 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-[![npm](https://img.shields.io/npm/v/rax-appear.svg)](https://www.npmjs.com/package/rax-appear)
+[![npm](https://img.shields.io/npm/v/rax-appear.svg)](https://www.npmjs.com/package/appear-polyfill)
**描述:**
-封装了组件 Appear 和 Disappear 的监听。
+封装了 appear 和 disappear 事件监听的 Polyfill。
## 安装
@@ -11,50 +11,59 @@ $ npm install appear-polyfill --save
## 示例
-
```jsx
-import { createElement, render } from 'rax';
-import * as DriverDOM from 'driver-dom';
-import { isWeb } from 'universal-env';
+// app.js
+import { useEffect } from 'react';
import { setupAppear } from 'appear-polyfill';
-
-if (isWeb) {
- setupAppear(window);
+setupAppear(window);
+
+function App() {
+ useEffect(() => {
+ const item50 = document.getElementById('item50');
+
+ item50.addEventListener('appear', (event) => {
+ console.log('appear at', event.target, event);
+ });
+
+ item50.addEventListener('disappear', (event) => {
+ console.log('disappear at', event.target, event);
+ });
+ }, []);
+ return Array.from({ length: 100 })
+ .map((_, index) => (
+
Item {index}
+ ))
}
+render();
+```
+## 配置项
+
+**intersectionObserverLoader**
-const list = [];
-for (let index = 1; index <= 100; index++) {
- list.push(index);
+- 类型:`function`
+
+> Tip: 从 0.2.0 版本开始, appear-polyfill 移除了内置的 IntersectionObserver Polyfill,如有必要可以自行引入。
+
+用于在浏览器不支持 IntersectionObserver 的情况下,动态加载 IntersectionObserver Polyfill。
+
+```js
+import { setupAppear } from 'appear-polyfill';
+
+const INTERSECTION_OBSERVER_POLYFILL = 'https://cdn.jsdelivr.net/npm/intersection-observer@0.12.2/intersection-observer.js';
+function intersectionObserverLoader() {
+ return new Promise((resolve, reject) => {
+ const script = document.createElement('script');
+ // Polyfill 加载完成后,会在 window 上挂载 IntersectionObserver 对象
+ script.onload = () => resolve(window.IntersectionObserver);
+ script.onerror = () => reject();
+ script.src = INTERSECTION_OBSERVER_POLYFILL;
+ document.head.appendChild(script);
+ });
}
-render((
-
- {list.map((item) => {
- return (
-
{
- console.log('appear: ', item, event.detail.direction);
- }}
- onDisappear={() => {
- console.log('disappear: ', item, event.detail.direction);
- }}
- >
- 第 {item} 个
-
- );
- })}
-
-), document.body, { driver: DriverDOM });
+// 启动监听
+setupAppear(window, { intersectionObserverLoader });
```
-## 配置项
**preAppear**
@@ -64,7 +73,6 @@ render((
```jsx
import { createElement, render } from 'rax';
-import DriverUniversal from 'driver-universal';
import Image from 'rax-image';
import { setupAppear } from 'appear-polyfill';
@@ -97,5 +105,5 @@ const App = () => {
);
};
-render(, document.body, { driver: DriverUniversal });
+render(, document.body);
```
\ No newline at end of file
diff --git a/build.config.mts b/build.config.mts
new file mode 100644
index 0000000..64f7fea
--- /dev/null
+++ b/build.config.mts
@@ -0,0 +1,14 @@
+import { defineConfig } from '@ice/pkg';
+
+export default defineConfig({
+ transform: {
+ formats: ['esm'],
+ },
+ bundle: {
+ formats: ['umd', 'es2017'],
+ minify: true,
+ },
+ plugins: [
+ '@ice/pkg-plugin-docusaurus',
+ ],
+});
\ No newline at end of file
diff --git a/build.json b/build.json
deleted file mode 100644
index fbb1418..0000000
--- a/build.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "type": "rax",
- "plugins": [
- "build-plugin-component"
- ],
- "targets": [
- "web",
- "weex"
- ]
-}
diff --git a/demo/index.js b/demo/index.js
deleted file mode 100644
index 7a177a6..0000000
--- a/demo/index.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { createElement, render } from 'rax';
-import * as DriverDOM from 'driver-dom';
-import { isWeb } from 'universal-env';
-import { setupAppear } from '../src/index';
-
-setupAppear();
-
-const list = [];
-for (let index = 1; index <= 100; index++) {
- list.push(index);
-}
-
-render((
-
- {list.map((item) => {
- return (
-
{
- console.log('appear: ', item, event.detail.direction);
- }}
- onDisappear={() => {
- console.log('disappear: ', item, event.detail.direction);
- }}
- isonce
- >
- 第 {item} 个
-
- );
- })}
-
-), document.body, { driver: DriverDOM });
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..7bdf803
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,41 @@
+# Example
+
+展开代码块以查看使用的例子
+
+```jsx preview
+import { useEffect } from 'react';
+import { setupAppear } from '../src/index';
+
+// https://caniuse.com/?search=IntersectionObserver
+function intersectionObserverLoader() {
+ return new Promise((resolve, reject) => {
+ const script = document.createElement('script');
+ script.onload = () => resolve(window.IntersectionObserver);
+ script.onerror = () => reject();
+ script.src = 'https://g.alicdn.com/ice/intersection-observer/0.12.2/intersection-observer.min.js';
+ document.head.appendChild(script);
+ });
+}
+setupAppear(window, { intersectionObserverLoader });
+
+const styles = {
+ item: {
+ padding: '10px 0',
+ borderBottom: '1px solid #eee',
+ },
+};
+// Ignore following line.
+export default function List() {
+ useEffect(() => {
+ document.getElementById('item50').addEventListener('appear', (event) => {
+ console.log('appear at', event.target, event);
+ });
+
+ document.getElementById('item50').addEventListener('disappear', (event) => {
+ console.log('disappear at', event.target, event);
+ });
+ }, []);
+ return Array.from({ length: 100 })
+ .map((_, index) => (Item {index}
));
+}
+```
\ No newline at end of file
diff --git a/jest.config.js b/jest.config.js
deleted file mode 100644
index 234b9b7..0000000
--- a/jest.config.js
+++ /dev/null
@@ -1,5 +0,0 @@
-const getJestConfig = require('rax-jest-config');
-
-module.exports = {
- ...getJestConfig(),
-};
diff --git a/package.json b/package.json
index b42e37d..6dc0a5b 100644
--- a/package.json
+++ b/package.json
@@ -1,14 +1,15 @@
{
"name": "appear-polyfill",
- "version": "0.1.3",
- "description": "",
- "author": "rax",
+ "version": "0.2.0",
+ "description": "Simulate appear & disappear events.",
+ "author": "Rax Team & ICE Team",
"license": "BSD-3-Clause",
- "main": "lib/index.js",
+ "main": "esm/index.js",
+ "module": "esm/index.js",
+ "types": "esm/index.d.ts",
"scripts": {
- "start": "build-scripts start",
- "build": "build-scripts build",
- "test": "build-scripts test",
+ "start": "ice-pkg start",
+ "build": "ice-pkg build",
"prepublishOnly": "npm run build"
},
"keywords": [
@@ -18,18 +19,14 @@
"engines": {
"npm": ">=3.0.0"
},
- "peerDependencies": {
- "rax": "^1.0.0"
- },
"devDependencies": {
- "@alib/build-scripts": "^0.1.28",
- "build-plugin-component": "^1.0.0",
- "driver-dom": "^1.0.0",
- "rax": "^1.0.0",
- "rax-jest-config": "^1.0.0",
- "rax-test-renderer": "^1.0.0",
- "rax-view": "^1.0.2",
- "universal-env": "^1.0.1"
+ "@ice/pkg": "^1.5.0",
+ "@ice/pkg-plugin-docusaurus": "^1.4.3",
+ "react-dom": "^18.2.0"
+ },
+ "homepage": "https://unpkg.com/appear-polyfill@0.2.0/build/index.html",
+ "dependencies": {
+ "@swc/helpers": "^0.4.14"
},
- "homepage": "https://unpkg.com/appear-polyfill@0.1.3/build/index.html"
+ "repository": "git@github.com:raxjs/appear-polyfill.git"
}
diff --git a/public/index.html b/public/index.html
deleted file mode 100644
index 6de1a78..0000000
--- a/public/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
- Rax Component Demo
-
-
-
-
-
diff --git a/src/IntersectionObserver.js b/src/IntersectionObserver.js
deleted file mode 100644
index f5dca15..0000000
--- a/src/IntersectionObserver.js
+++ /dev/null
@@ -1,652 +0,0 @@
-/**
- * An IntersectionObserver registry. This registry exists to hold a strong
- * reference to IntersectionObserver instances currently observing a target
- * element. Without this registry, instances without another reference may be
- * garbage collected.
- */
-const registry = [];
-
-
-/**
- * Creates the global IntersectionObserverEntry constructor.
- * https://w3c.github.io/IntersectionObserver/#intersection-observer-entry
- * @param {Object} entry A dictionary of instance properties.
- * @constructor
- */
-export function IntersectionObserverEntry(entry) {
- this.time = entry.time;
- this.target = entry.target;
- this.rootBounds = entry.rootBounds;
- this.boundingClientRect = entry.boundingClientRect;
- this.intersectionRect = entry.intersectionRect || getEmptyRect();
- this.isIntersecting = !!entry.intersectionRect;
-
- // Calculates the intersection ratio.
- const targetRect = this.boundingClientRect;
- const targetArea = targetRect.width * targetRect.height;
- const intersectionRect = this.intersectionRect;
- const intersectionArea = intersectionRect.width * intersectionRect.height;
-
- // Sets intersection ratio.
- if (targetArea) {
- // Round the intersection ratio to avoid floating point math issues:
- // https://github.com/w3c/IntersectionObserver/issues/324
- this.intersectionRatio = Number((intersectionArea / targetArea).toFixed(4));
- } else {
- // If area is zero and is intersecting, sets to 1, otherwise to 0
- this.intersectionRatio = this.isIntersecting ? 1 : 0;
- }
-}
-
-export default class IntersectionObserver {
- /**
- * The minimum interval within which the document will be checked for
- * intersection changes.
- */
- THROTTLE_TIMEOUT = 100;
-
- /**
- * The frequency in which the polyfill polls for intersection changes.
- * this can be updated on a per instance basis and must be set prior to
- * calling `observe` on the first target.
- */
- POLL_INTERVAL = null;
-
- /**
- * Use a mutation observer on the root element
- * to detect intersection changes.
- */
- USE_MUTATION_OBSERVER = true;
-
- /**
- * Creates the global IntersectionObserver constructor.
- * https://w3c.github.io/IntersectionObserver/#intersection-observer-interface
- * @param {Function} callback The function to be invoked after intersection
- * changes have queued. The function is not invoked if the queue has
- * been emptied by calling the `takeRecords` method.
- * @param {Object=} optOptions Optional configuration options.
- * @constructor
- */
- constructor(callback, optOptions) {
- const options = optOptions || {};
-
- if (typeof callback != 'function') {
- throw new Error('callback must be a function');
- }
-
- if (options.root && options.root.nodeType != 1) {
- throw new Error('root must be an Element');
- }
-
- // Throttles `this._checkForIntersections`.
- this._checkForIntersections = throttle(this._checkForIntersections, this.THROTTLE_TIMEOUT);
-
- // Private properties.
- this._callback = callback;
- this._observationTargets = [];
- this._queuedEntries = [];
- this._rootMarginValues = this._parseRootMargin(options.rootMargin);
-
- // Public properties.
- this.thresholds = this._initThresholds(options.threshold);
- this.root = options.root || null;
- this.rootMargin = this._rootMarginValues.map((margin) => margin.value + margin.unit).join(' ');
- }
-
- /**
- * Starts observing a target element for intersection changes based on
- * the thresholds values.
- * @param {Element} target The DOM element to observe.
- */
- observe(target) {
- const isTargetAlreadyObserved = this._observationTargets.some((item) => item.element === target);
-
- if (isTargetAlreadyObserved) {
- return;
- }
-
- if (!(target && target.nodeType == 1)) {
- throw new Error('target must be an Element');
- }
-
- this._registerInstance();
- this._observationTargets.push({element: target, entry: null});
- this._monitorIntersections();
- this._checkForIntersections();
- }
-
- /**
- * Stops observing a target element for intersection changes.
- * @param {Element} target The DOM element to observe.
- */
- unobserve(target) {
- this._observationTargets =
- this._observationTargets.filter(function(item) {
- return item.element !== target;
- });
- if (!this._observationTargets.length) {
- this._unmonitorIntersections();
- this._unregisterInstance();
- }
- }
-
- /**
- * Stops observing all target elements for intersection changes.
- */
- disconnect() {
- this._observationTargets = [];
- this._unmonitorIntersections();
- this._unregisterInstance();
- }
-
- /**
- * Returns any queue entries that have not yet been reported to the
- * callback and clears the queue. This can be used in conjunction with the
- * callback to obtain the absolute most up-to-date intersection information.
- * @return {Array} The currently queued entries.
- */
- takeRecords() {
- const records = this._queuedEntries.slice();
- this._queuedEntries = [];
- return records;
- }
-
- /**
- * Accepts the threshold value from the user configuration object and
- * returns a sorted array of unique threshold values. If a value is not
- * between 0 and 1 and error is thrown.
- * @private
- * @param {Array|number=} optThreshold An optional threshold value or
- * a list of threshold values, defaulting to [0].
- * @return {Array} A sorted list of unique and valid threshold values.
- */
- _initThresholds(optThreshold) {
- let threshold = optThreshold || [0];
- if (!Array.isArray(threshold)) threshold = [threshold];
-
- return threshold.sort().filter(function(t, i, a) {
- if (typeof t != 'number' || isNaN(t) || t < 0 || t > 1) {
- throw new Error('threshold must be a number between 0 and 1 inclusively');
- }
- return t !== a[i - 1];
- });
- }
-
- /**
- * Accepts the rootMargin value from the user configuration object
- * and returns an array of the four margin values as an object containing
- * the value and unit properties. If any of the values are not properly
- * formatted or use a unit other than px or %, and error is thrown.
- * @private
- * @param {string=} optRootMargin An optional rootMargin value,
- * defaulting to '0px'.
- * @return {Array