diff --git a/.gitignore b/.gitignore
index 2978361..9af12e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,9 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
/es
/dist
+/temp
.rpt2_cache
+tsdoc-metadata.json
# dependencies
/node_modules
/.pnp
diff --git a/.npmignore b/.npmignore
index 4a09b64..3f3bcc8 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,7 +1,27 @@
+.DS_Store
+*.log*
+*.tsbuildinfo
+/temp
.rpt2_cache
-node_modules
+tsdoc-metadata.json
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
npm-debug.log*
yarn-debug.log*
yarn-error.log*
-*.tsbuildinfo
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 00ad71f..e997ffc 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,6 @@
{
- "typescript.tsdk": "node_modules\\typescript\\lib"
+ "typescript.tsdk": "node_modules\\typescript\\lib",
+ "search.exclude": {
+ "**/api-document": true
+ }
}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..7decbeb
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,15 @@
+{
+// 有关 tasks.json 格式的文档,请参见
+ // https://go.microsoft.com/fwlink/?LinkId=733558
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "type": "npm",
+ "script": "start-tsc",
+ "problemMatcher": [
+ "$tsc-watch"
+ ],
+ "isBackground": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index a9d2af5..67c0aee 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,14 @@
-# @holoflows/kit · ![GitHub license](https://img.shields.io/badge/license-AGPL-blue.svg?style=flat-square) [![npm version](https://img.shields.io/npm/v/@holoflows/kit.svg?style=flat-square)](https://www.npmjs.com/package/@holoflows/kit) ![Ciecle CI](https://img.shields.io/circleci/project/github/DimensionFoundation/holoflows-kit.svg?style=flat-square&logo=circleci)
+# @holoflows/kit · ![GitHub license](https://img.shields.io/badge/license-AGPL-blue.svg?style=flat-square) [![npm version](https://img.shields.io/npm/v/@holoflows/kit.svg?style=flat-square)](https://www.npmjs.com/package/@holoflows/kit) ![Ciecle CI](https://img.shields.io/circleci/project/github/DimensionDev/Holoflows-Kit.svg?style=flat-square&logo=circleci)
Toolkit for modern web browser extension developing.
## Documentation
-[English documentation](./doc/en/index.md)
+[Get Started](./doc/en/index.md)
-[简体中文文档](./doc/zh-CN/index.md)
+[初次使用](./doc/zh-CN/index.md)
+
+[API Documentation](./api-documents/kit.md)
## License
diff --git a/api-documents/kit.asynccall.md b/api-documents/kit.asynccall.md
new file mode 100644
index 0000000..4989426
--- /dev/null
+++ b/api-documents/kit.asynccall.md
@@ -0,0 +1,84 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AsyncCall](./kit.asynccall.md)
+
+## AsyncCall() function
+
+Async call between different context.
+
+Signature:
+
+```typescript
+export declare function AsyncCall(implementation: Default, options?: Partial): OtherSideImplementedFunctions;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| implementation | Default
| Implementation of this side. |
+| options | Partial<AsyncCallOptions>
| Define your own serializer, MessageCenter or other options. |
+
+Returns:
+
+`OtherSideImplementedFunctions`
+
+## Remarks
+
+Async call is a high level abstraction of MessageCenter.
+
+\# Shared code
+
+- How to stringify/parse parameters/returns should be shared, defaults to NoSerialization.
+
+- `key` should be shared.
+
+\# One side
+
+- Should provide some functions then export its type (for example, `BackgroundCalls`)
+
+- `const call = AsyncCall(backgroundCalls)`
+
+- Then you can `call` any method on `ForegroundCalls`
+
+\# Other side
+
+- Should provide some functions then export its type (for example, `ForegroundCalls`)
+
+- `const call = AsyncCall(foregroundCalls)`
+
+- Then you can `call` any method on `BackgroundCalls`
+
+Note: Two sides can implement the same function
+
+## Example
+
+For example, here is a mono repo.
+
+Code for UI part:
+
+```ts
+const UI = {
+ async dialog(text: string) {
+ alert(text)
+ },
+}
+export type UI = typeof UI
+const callsClient = AsyncCall(UI)
+callsClient.sendMail('hello world', 'what')
+
+```
+Code for server part
+
+```ts
+const Server = {
+ async sendMail(text: string, to: string) {
+ return true
+ }
+}
+export type Server = typeof Server
+const calls = AsyncCall(Server)
+calls.dialog('hello')
+
+```
+
diff --git a/api-documents/kit.asynccalloptions.dontthrowonnotimplemented.md b/api-documents/kit.asynccalloptions.dontthrowonnotimplemented.md
new file mode 100644
index 0000000..01f491b
--- /dev/null
+++ b/api-documents/kit.asynccalloptions.dontthrowonnotimplemented.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AsyncCallOptions](./kit.asynccalloptions.md) > [dontThrowOnNotImplemented](./kit.asynccalloptions.dontthrowonnotimplemented.md)
+
+## AsyncCallOptions.dontThrowOnNotImplemented property
+
+Signature:
+
+```typescript
+dontThrowOnNotImplemented: boolean;
+```
diff --git a/api-documents/kit.asynccalloptions.key.md b/api-documents/kit.asynccalloptions.key.md
new file mode 100644
index 0000000..1a69c5e
--- /dev/null
+++ b/api-documents/kit.asynccalloptions.key.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AsyncCallOptions](./kit.asynccalloptions.md) > [key](./kit.asynccalloptions.key.md)
+
+## AsyncCallOptions.key property
+
+Signature:
+
+```typescript
+key: string;
+```
diff --git a/api-documents/kit.asynccalloptions.md b/api-documents/kit.asynccalloptions.md
new file mode 100644
index 0000000..ddbc1fe
--- /dev/null
+++ b/api-documents/kit.asynccalloptions.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AsyncCallOptions](./kit.asynccalloptions.md)
+
+## AsyncCallOptions interface
+
+Options for [AsyncCall()](./kit.asynccall.md)
+
+Signature:
+
+```typescript
+export interface AsyncCallOptions
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [dontThrowOnNotImplemented](./kit.asynccalloptions.dontthrowonnotimplemented.md) | boolean
| |
+| [key](./kit.asynccalloptions.key.md) | string
| |
+| [MessageCenter](./kit.asynccalloptions.messagecenter.md) | {
new (): {
on(event: string, cb: (data: any) => void): void;
send(event: string, data: any): void;
};
}
| |
+| [serializer](./kit.asynccalloptions.serializer.md) | Serialization
| |
+| [writeToConsole](./kit.asynccalloptions.writetoconsole.md) | boolean
| |
+
diff --git a/api-documents/kit.asynccalloptions.messagecenter.md b/api-documents/kit.asynccalloptions.messagecenter.md
new file mode 100644
index 0000000..75a2c4d
--- /dev/null
+++ b/api-documents/kit.asynccalloptions.messagecenter.md
@@ -0,0 +1,16 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AsyncCallOptions](./kit.asynccalloptions.md) > [MessageCenter](./kit.asynccalloptions.messagecenter.md)
+
+## AsyncCallOptions.MessageCenter property
+
+Signature:
+
+```typescript
+MessageCenter: {
+ new (): {
+ on(event: string, cb: (data: any) => void): void;
+ send(event: string, data: any): void;
+ };
+ };
+```
diff --git a/api-documents/kit.asynccalloptions.serializer.md b/api-documents/kit.asynccalloptions.serializer.md
new file mode 100644
index 0000000..e447818
--- /dev/null
+++ b/api-documents/kit.asynccalloptions.serializer.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AsyncCallOptions](./kit.asynccalloptions.md) > [serializer](./kit.asynccalloptions.serializer.md)
+
+## AsyncCallOptions.serializer property
+
+Signature:
+
+```typescript
+serializer: Serialization;
+```
diff --git a/api-documents/kit.asynccalloptions.writetoconsole.md b/api-documents/kit.asynccalloptions.writetoconsole.md
new file mode 100644
index 0000000..9576b79
--- /dev/null
+++ b/api-documents/kit.asynccalloptions.writetoconsole.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AsyncCallOptions](./kit.asynccalloptions.md) > [writeToConsole](./kit.asynccalloptions.writetoconsole.md)
+
+## AsyncCallOptions.writeToConsole property
+
+Signature:
+
+```typescript
+writeToConsole: boolean;
+```
diff --git a/api-documents/kit.automatedtabtask.md b/api-documents/kit.automatedtabtask.md
new file mode 100644
index 0000000..85387d9
--- /dev/null
+++ b/api-documents/kit.automatedtabtask.md
@@ -0,0 +1,47 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AutomatedTabTask](./kit.automatedtabtask.md)
+
+## AutomatedTabTask() function
+
+Open a new page in the background, execute some task, then close it automatically.
+
+Signature:
+
+```typescript
+export declare function AutomatedTabTask Promise>>(taskImplements: T, options?: Partial): ((url: string, options?: Partial) => T) | null;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| taskImplements | T
| All tasks that background page can call. |
+| options | Partial<AutomatedTabTaskDefineTimeOptions>
| Options |
+
+Returns:
+
+`((url: string, options?: Partial) => T) | null`
+
+## Example
+
+In content script: (You must run this in the page you wanted to run task in!)
+
+```ts
+export const task = AutomatedTabTask({
+ async taskA() {
+ return 'Done!'
+ },
+})
+
+```
+In background script:
+
+Open https://example.com/ then run taskA() on that page, which will return 'Done!'
+
+```ts
+import { task } from '...'
+task('https://example.com/').taskA()
+
+```
+
diff --git a/api-documents/kit.automatedtabtaskdefinetimeoptions.concurrent.md b/api-documents/kit.automatedtabtaskdefinetimeoptions.concurrent.md
new file mode 100644
index 0000000..3b83014
--- /dev/null
+++ b/api-documents/kit.automatedtabtaskdefinetimeoptions.concurrent.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AutomatedTabTaskDefineTimeOptions](./kit.automatedtabtaskdefinetimeoptions.md) > [concurrent](./kit.automatedtabtaskdefinetimeoptions.concurrent.md)
+
+## AutomatedTabTaskDefineTimeOptions.concurrent property
+
+At most run `concurrent` tasks. Prevents open too many tabs at the same time.
+
+Signature:
+
+```typescript
+concurrent: number;
+```
diff --git a/api-documents/kit.automatedtabtaskdefinetimeoptions.key.md b/api-documents/kit.automatedtabtaskdefinetimeoptions.key.md
new file mode 100644
index 0000000..971a143
--- /dev/null
+++ b/api-documents/kit.automatedtabtaskdefinetimeoptions.key.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AutomatedTabTaskDefineTimeOptions](./kit.automatedtabtaskdefinetimeoptions.md) > [key](./kit.automatedtabtaskdefinetimeoptions.key.md)
+
+## AutomatedTabTaskDefineTimeOptions.key property
+
+A unique key
+
+Signature:
+
+```typescript
+key: string;
+```
diff --git a/api-documents/kit.automatedtabtaskdefinetimeoptions.md b/api-documents/kit.automatedtabtaskdefinetimeoptions.md
new file mode 100644
index 0000000..5536faa
--- /dev/null
+++ b/api-documents/kit.automatedtabtaskdefinetimeoptions.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AutomatedTabTaskDefineTimeOptions](./kit.automatedtabtaskdefinetimeoptions.md)
+
+## AutomatedTabTaskDefineTimeOptions interface
+
+Define-time options for [AutomatedTabTask()](./kit.automatedtabtask.md)
+
+Signature:
+
+```typescript
+export interface AutomatedTabTaskDefineTimeOptions extends AutomatedTabTaskSharedOptions
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [concurrent](./kit.automatedtabtaskdefinetimeoptions.concurrent.md) | number
| At most run concurrent
tasks. Prevents open too many tabs at the same time. |
+| [key](./kit.automatedtabtaskdefinetimeoptions.key.md) | string
| A unique key |
+| [memorizeTTL](./kit.automatedtabtaskdefinetimeoptions.memorizettl.md) | number
| TTL for memorize |
+
diff --git a/api-documents/kit.automatedtabtaskdefinetimeoptions.memorizettl.md b/api-documents/kit.automatedtabtaskdefinetimeoptions.memorizettl.md
new file mode 100644
index 0000000..42344b8
--- /dev/null
+++ b/api-documents/kit.automatedtabtaskdefinetimeoptions.memorizettl.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AutomatedTabTaskDefineTimeOptions](./kit.automatedtabtaskdefinetimeoptions.md) > [memorizeTTL](./kit.automatedtabtaskdefinetimeoptions.memorizettl.md)
+
+## AutomatedTabTaskDefineTimeOptions.memorizeTTL property
+
+TTL for memorize
+
+Signature:
+
+```typescript
+memorizeTTL: number;
+```
diff --git a/api-documents/kit.automatedtabtaskruntimeoptions.important.md b/api-documents/kit.automatedtabtaskruntimeoptions.important.md
new file mode 100644
index 0000000..476f541
--- /dev/null
+++ b/api-documents/kit.automatedtabtaskruntimeoptions.important.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AutomatedTabTaskRuntimeOptions](./kit.automatedtabtaskruntimeoptions.md) > [important](./kit.automatedtabtaskruntimeoptions.important.md)
+
+## AutomatedTabTaskRuntimeOptions.important property
+
+This task is important, need to start now without queue.
+
+Signature:
+
+```typescript
+important: boolean;
+```
diff --git a/api-documents/kit.automatedtabtaskruntimeoptions.md b/api-documents/kit.automatedtabtaskruntimeoptions.md
new file mode 100644
index 0000000..1d7d7af
--- /dev/null
+++ b/api-documents/kit.automatedtabtaskruntimeoptions.md
@@ -0,0 +1,20 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [AutomatedTabTaskRuntimeOptions](./kit.automatedtabtaskruntimeoptions.md)
+
+## AutomatedTabTaskRuntimeOptions interface
+
+Runtime options for [AutomatedTabTask()](./kit.automatedtabtask.md)
+
+Signature:
+
+```typescript
+export interface AutomatedTabTaskRuntimeOptions extends AutomatedTabTaskSharedOptions
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [important](./kit.automatedtabtaskruntimeoptions.important.md) | boolean
| This task is important, need to start now without queue. |
+
diff --git a/api-documents/kit.contexts.md b/api-documents/kit.contexts.md
new file mode 100644
index 0000000..45c3a99
--- /dev/null
+++ b/api-documents/kit.contexts.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Contexts](./kit.contexts.md)
+
+## Contexts type
+
+All context that possible in when developing a WebExtension
+
+Signature:
+
+```typescript
+export declare type Contexts = 'background' | 'content' | 'webpage' | 'unknown' | 'options' | 'debugging';
+```
diff --git a/api-documents/kit.domproxy.after.md b/api-documents/kit.domproxy.after.md
new file mode 100644
index 0000000..102bf13
--- /dev/null
+++ b/api-documents/kit.domproxy.after.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md) > [after](./kit.domproxy.after.md)
+
+## DomProxy.after property
+
+Returns the `after` element, if it doesn't exist, create it implicitly.
+
+Signature:
+
+```typescript
+readonly after: After;
+```
diff --git a/api-documents/kit.domproxy.aftershadow.md b/api-documents/kit.domproxy.aftershadow.md
new file mode 100644
index 0000000..95271d7
--- /dev/null
+++ b/api-documents/kit.domproxy.aftershadow.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md) > [afterShadow](./kit.domproxy.aftershadow.md)
+
+## DomProxy.afterShadow property
+
+Returns the `ShadowRoot` of the `after` element.
+
+Signature:
+
+```typescript
+readonly afterShadow: ShadowRoot;
+```
diff --git a/api-documents/kit.domproxy.before.md b/api-documents/kit.domproxy.before.md
new file mode 100644
index 0000000..a4146cf
--- /dev/null
+++ b/api-documents/kit.domproxy.before.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md) > [before](./kit.domproxy.before.md)
+
+## DomProxy.before property
+
+Returns the `before` element, if it doesn't exist, create it implicitly.
+
+Signature:
+
+```typescript
+readonly before: Before;
+```
diff --git a/api-documents/kit.domproxy.beforeshadow.md b/api-documents/kit.domproxy.beforeshadow.md
new file mode 100644
index 0000000..680541a
--- /dev/null
+++ b/api-documents/kit.domproxy.beforeshadow.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md) > [beforeShadow](./kit.domproxy.beforeshadow.md)
+
+## DomProxy.beforeShadow property
+
+Returns the `ShadowRoot` of the `before` element.
+
+Signature:
+
+```typescript
+readonly beforeShadow: ShadowRoot;
+```
diff --git a/api-documents/kit.domproxy.current.md b/api-documents/kit.domproxy.current.md
new file mode 100644
index 0000000..0c62f40
--- /dev/null
+++ b/api-documents/kit.domproxy.current.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md) > [current](./kit.domproxy.current.md)
+
+## DomProxy.current property
+
+A proxy that always point to `realCurrent`, and if `realCurrent` changes, all action will be forwarded to new `realCurrent`
+
+Signature:
+
+```typescript
+readonly current: ProxiedElement;
+```
diff --git a/api-documents/kit.domproxy.destroy.md b/api-documents/kit.domproxy.destroy.md
new file mode 100644
index 0000000..9b1f505
--- /dev/null
+++ b/api-documents/kit.domproxy.destroy.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md) > [destroy](./kit.domproxy.destroy.md)
+
+## DomProxy.destroy() method
+
+Destroy the DomProxy
+
+Signature:
+
+```typescript
+destroy(): void;
+```
+Returns:
+
+`void`
+
diff --git a/api-documents/kit.domproxy.md b/api-documents/kit.domproxy.md
new file mode 100644
index 0000000..f4c233b
--- /dev/null
+++ b/api-documents/kit.domproxy.md
@@ -0,0 +1,34 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md)
+
+## DomProxy interface
+
+A DomProxy object
+
+Signature:
+
+```typescript
+export interface DomProxy
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [after](./kit.domproxy.after.md) | After
| Returns the after
element, if it doesn't exist, create it implicitly. |
+| [afterShadow](./kit.domproxy.aftershadow.md) | ShadowRoot
| Returns the ShadowRoot
of the after
element. |
+| [before](./kit.domproxy.before.md) | Before
| Returns the before
element, if it doesn't exist, create it implicitly. |
+| [beforeShadow](./kit.domproxy.beforeshadow.md) | ShadowRoot
| Returns the ShadowRoot
of the before
element. |
+| [current](./kit.domproxy.current.md) | ProxiedElement
| A proxy that always point to realCurrent
, and if realCurrent
changes, all action will be forwarded to new realCurrent
|
+| [observer](./kit.domproxy.observer.md) | {
readonly observer: MutationObserver | null;
callback: MutationCallback | undefined;
init: MutationObserverInit | undefined;
}
| Observer for the current node. You need to set callback and init to activate it. |
+| [realCurrent](./kit.domproxy.realcurrent.md) | ProxiedElement | null
| The real current of the current
|
+| [weakAfter](./kit.domproxy.weakafter.md) | After | null
| Returns the after
element without implicitly create it. |
+| [weakBefore](./kit.domproxy.weakbefore.md) | Before | null
| Returns the before
element without implicitly create it. |
+
+## Methods
+
+| Method | Description |
+| --- | --- |
+| [destroy()](./kit.domproxy.destroy.md) | Destroy the DomProxy |
+
diff --git a/api-documents/kit.domproxy.observer.md b/api-documents/kit.domproxy.observer.md
new file mode 100644
index 0000000..2d98401
--- /dev/null
+++ b/api-documents/kit.domproxy.observer.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md) > [observer](./kit.domproxy.observer.md)
+
+## DomProxy.observer property
+
+Observer for the current node. You need to set callback and init to activate it.
+
+Signature:
+
+```typescript
+readonly observer: {
+ readonly observer: MutationObserver | null;
+ callback: MutationCallback | undefined;
+ init: MutationObserverInit | undefined;
+ };
+```
diff --git a/api-documents/kit.domproxy.realcurrent.md b/api-documents/kit.domproxy.realcurrent.md
new file mode 100644
index 0000000..148ddf5
--- /dev/null
+++ b/api-documents/kit.domproxy.realcurrent.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md) > [realCurrent](./kit.domproxy.realcurrent.md)
+
+## DomProxy.realCurrent property
+
+The real current of the `current`
+
+Signature:
+
+```typescript
+realCurrent: ProxiedElement | null;
+```
diff --git a/api-documents/kit.domproxy.weakafter.md b/api-documents/kit.domproxy.weakafter.md
new file mode 100644
index 0000000..70341dc
--- /dev/null
+++ b/api-documents/kit.domproxy.weakafter.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md) > [weakAfter](./kit.domproxy.weakafter.md)
+
+## DomProxy.weakAfter property
+
+Returns the `after` element without implicitly create it.
+
+Signature:
+
+```typescript
+readonly weakAfter: After | null;
+```
diff --git a/api-documents/kit.domproxy.weakbefore.md b/api-documents/kit.domproxy.weakbefore.md
new file mode 100644
index 0000000..a72a14f
--- /dev/null
+++ b/api-documents/kit.domproxy.weakbefore.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxy](./kit.domproxy.md) > [weakBefore](./kit.domproxy.weakbefore.md)
+
+## DomProxy.weakBefore property
+
+Returns the `before` element without implicitly create it.
+
+Signature:
+
+```typescript
+readonly weakBefore: Before | null;
+```
diff --git a/api-documents/kit.domproxyoptions.aftershadowrootinit.md b/api-documents/kit.domproxyoptions.aftershadowrootinit.md
new file mode 100644
index 0000000..6ed1276
--- /dev/null
+++ b/api-documents/kit.domproxyoptions.aftershadowrootinit.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxyOptions](./kit.domproxyoptions.md) > [afterShadowRootInit](./kit.domproxyoptions.aftershadowrootinit.md)
+
+## DomProxyOptions.afterShadowRootInit property
+
+ShadowRootInit for creating the shadow of `after`
+
+Signature:
+
+```typescript
+afterShadowRootInit: ShadowRootInit;
+```
diff --git a/api-documents/kit.domproxyoptions.beforeshadowrootinit.md b/api-documents/kit.domproxyoptions.beforeshadowrootinit.md
new file mode 100644
index 0000000..43096a9
--- /dev/null
+++ b/api-documents/kit.domproxyoptions.beforeshadowrootinit.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxyOptions](./kit.domproxyoptions.md) > [beforeShadowRootInit](./kit.domproxyoptions.beforeshadowrootinit.md)
+
+## DomProxyOptions.beforeShadowRootInit property
+
+ShadowRootInit for creating the shadow of `before`
+
+Signature:
+
+```typescript
+beforeShadowRootInit: ShadowRootInit;
+```
diff --git a/api-documents/kit.domproxyoptions.createafter.md b/api-documents/kit.domproxyoptions.createafter.md
new file mode 100644
index 0000000..99379a5
--- /dev/null
+++ b/api-documents/kit.domproxyoptions.createafter.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxyOptions](./kit.domproxyoptions.md) > [createAfter](./kit.domproxyoptions.createafter.md)
+
+## DomProxyOptions.createAfter() method
+
+Create the `after` node of the DomProxy
+
+Signature:
+
+```typescript
+createAfter(): After;
+```
+Returns:
+
+`After`
+
diff --git a/api-documents/kit.domproxyoptions.createbefore.md b/api-documents/kit.domproxyoptions.createbefore.md
new file mode 100644
index 0000000..62ccdbe
--- /dev/null
+++ b/api-documents/kit.domproxyoptions.createbefore.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxyOptions](./kit.domproxyoptions.md) > [createBefore](./kit.domproxyoptions.createbefore.md)
+
+## DomProxyOptions.createBefore() method
+
+Create the `before` node of the DomProxy
+
+Signature:
+
+```typescript
+createBefore(): Before;
+```
+Returns:
+
+`Before`
+
diff --git a/api-documents/kit.domproxyoptions.md b/api-documents/kit.domproxyoptions.md
new file mode 100644
index 0000000..f7a1693
--- /dev/null
+++ b/api-documents/kit.domproxyoptions.md
@@ -0,0 +1,28 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [DomProxyOptions](./kit.domproxyoptions.md)
+
+## DomProxyOptions interface
+
+Options for DomProxy
+
+Signature:
+
+```typescript
+export interface DomProxyOptions
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [afterShadowRootInit](./kit.domproxyoptions.aftershadowrootinit.md) | ShadowRootInit
| ShadowRootInit for creating the shadow of after
|
+| [beforeShadowRootInit](./kit.domproxyoptions.beforeshadowrootinit.md) | ShadowRootInit
| ShadowRootInit for creating the shadow of before
|
+
+## Methods
+
+| Method | Description |
+| --- | --- |
+| [createAfter()](./kit.domproxyoptions.createafter.md) | Create the after
node of the DomProxy |
+| [createBefore()](./kit.domproxyoptions.createbefore.md) | Create the before
node of the DomProxy |
+
diff --git a/api-documents/kit.eventwatcher.eventlistener.md b/api-documents/kit.eventwatcher.eventlistener.md
new file mode 100644
index 0000000..287babc
--- /dev/null
+++ b/api-documents/kit.eventwatcher.eventlistener.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [EventWatcher](./kit.eventwatcher.md) > [eventListener](./kit.eventwatcher.eventlistener.md)
+
+## EventWatcher.eventListener property
+
+Use this function as event listener to invoke watcher.
+
+Signature:
+
+```typescript
+eventListener: () => void;
+```
diff --git a/api-documents/kit.eventwatcher.md b/api-documents/kit.eventwatcher.md
new file mode 100644
index 0000000..cbc5e17
--- /dev/null
+++ b/api-documents/kit.eventwatcher.md
@@ -0,0 +1,36 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [EventWatcher](./kit.eventwatcher.md)
+
+## EventWatcher class
+
+A Watcher based on event handlers.
+
+Signature:
+
+```typescript
+export declare class EventWatcher extends Watcher
+```
+
+## Properties
+
+| Property | Modifiers | Type | Description |
+| --- | --- | --- | --- |
+| [eventListener](./kit.eventwatcher.eventlistener.md) | | () => void
| Use this function as event listener to invoke watcher. |
+| [watching](./kit.eventwatcher.watching.md) | | boolean
| |
+
+## Methods
+
+| Method | Modifiers | Description |
+| --- | --- | --- |
+| [startWatch()](./kit.eventwatcher.startwatch.md) | | |
+
+## Example
+
+
+```ts
+const e = new EventWatcher(ls)
+document.addEventListener('event', e.eventListener)
+
+```
+
diff --git a/api-documents/kit.eventwatcher.startwatch.md b/api-documents/kit.eventwatcher.startwatch.md
new file mode 100644
index 0000000..c29481c
--- /dev/null
+++ b/api-documents/kit.eventwatcher.startwatch.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [EventWatcher](./kit.eventwatcher.md) > [startWatch](./kit.eventwatcher.startwatch.md)
+
+## EventWatcher.startWatch() method
+
+Signature:
+
+```typescript
+startWatch(): this;
+```
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.eventwatcher.watching.md b/api-documents/kit.eventwatcher.watching.md
new file mode 100644
index 0000000..9f271b3
--- /dev/null
+++ b/api-documents/kit.eventwatcher.watching.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [EventWatcher](./kit.eventwatcher.md) > [watching](./kit.eventwatcher.watching.md)
+
+## EventWatcher.watching property
+
+Signature:
+
+```typescript
+protected watching: boolean;
+```
diff --git a/api-documents/kit.getcontext.md b/api-documents/kit.getcontext.md
new file mode 100644
index 0000000..ae394ea
--- /dev/null
+++ b/api-documents/kit.getcontext.md
@@ -0,0 +1,21 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [GetContext](./kit.getcontext.md)
+
+## GetContext() function
+
+Get current running context.
+
+Signature:
+
+```typescript
+export declare function GetContext(): Contexts;
+```
+Returns:
+
+`Contexts`
+
+## Remarks
+
+- background: background script - content: content script - webpage: a normal webpage - unknown: unknown context
+
diff --git a/api-documents/kit.intervalwatcher.md b/api-documents/kit.intervalwatcher.md
new file mode 100644
index 0000000..9f07963
--- /dev/null
+++ b/api-documents/kit.intervalwatcher.md
@@ -0,0 +1,21 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [IntervalWatcher](./kit.intervalwatcher.md)
+
+## IntervalWatcher class
+
+A watcher based on time interval.
+
+Signature:
+
+```typescript
+export declare class IntervalWatcher extends Watcher
+```
+
+## Methods
+
+| Method | Modifiers | Description |
+| --- | --- | --- |
+| [startWatch(interval)](./kit.intervalwatcher.startwatch.md) | | Start to watch the LiveSelector at a interval(ms). |
+| [stopWatch()](./kit.intervalwatcher.stopwatch.md) | | |
+
diff --git a/api-documents/kit.intervalwatcher.startwatch.md b/api-documents/kit.intervalwatcher.startwatch.md
new file mode 100644
index 0000000..4e28b36
--- /dev/null
+++ b/api-documents/kit.intervalwatcher.startwatch.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [IntervalWatcher](./kit.intervalwatcher.md) > [startWatch](./kit.intervalwatcher.startwatch.md)
+
+## IntervalWatcher.startWatch() method
+
+Start to watch the LiveSelector at a interval(ms).
+
+Signature:
+
+```typescript
+startWatch(interval: number): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| interval | number
| |
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.intervalwatcher.stopwatch.md b/api-documents/kit.intervalwatcher.stopwatch.md
new file mode 100644
index 0000000..50eba35
--- /dev/null
+++ b/api-documents/kit.intervalwatcher.stopwatch.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [IntervalWatcher](./kit.intervalwatcher.md) > [stopWatch](./kit.intervalwatcher.stopwatch.md)
+
+## IntervalWatcher.stopWatch() method
+
+Signature:
+
+```typescript
+stopWatch(): void;
+```
+Returns:
+
+`void`
+
diff --git a/api-documents/kit.jsonserialization.md b/api-documents/kit.jsonserialization.md
new file mode 100644
index 0000000..521e47e
--- /dev/null
+++ b/api-documents/kit.jsonserialization.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [JSONSerialization](./kit.jsonserialization.md)
+
+## JSONSerialization variable
+
+Serialization implementation by JSON.parse/stringify
+
+Signature:
+
+```typescript
+JSONSerialization: (replacer?: ((this: any, key: string, value: any) => any) | undefined) => Serialization
+```
diff --git a/api-documents/kit.liveselector.clone.md b/api-documents/kit.liveselector.clone.md
new file mode 100644
index 0000000..7104164
--- /dev/null
+++ b/api-documents/kit.liveselector.clone.md
@@ -0,0 +1,27 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [clone](./kit.liveselector.clone.md)
+
+## LiveSelector.clone() method
+
+Clone this LiveSelector and return a new LiveSelector.
+
+Signature:
+
+```typescript
+clone(): LiveSelector;
+```
+Returns:
+
+`LiveSelector`
+
+a new LiveSelector with same action
+
+## Example
+
+
+```ts
+ls.clone()
+
+```
+
diff --git a/api-documents/kit.liveselector.closest.md b/api-documents/kit.liveselector.closest.md
new file mode 100644
index 0000000..b012bfd
--- /dev/null
+++ b/api-documents/kit.liveselector.closest.md
@@ -0,0 +1,33 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [closest](./kit.liveselector.closest.md)
+
+## LiveSelector.closest() method
+
+Reversely select element in the parent
+
+Signature:
+
+```typescript
+closest(parentOfNth: number): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| parentOfNth | number
| |
+
+Returns:
+
+`LiveSelector`
+
+## Example
+
+
+```ts
+ls.closest('div')
+ls.closest(2) // parentElement.parentElement
+
+```
+
diff --git a/api-documents/kit.liveselector.closest_1.md b/api-documents/kit.liveselector.closest_1.md
new file mode 100644
index 0000000..eeae54a
--- /dev/null
+++ b/api-documents/kit.liveselector.closest_1.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [closest](./kit.liveselector.closest_1.md)
+
+## LiveSelector.closest() method
+
+Signature:
+
+```typescript
+closest(selectors: K): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| selectors | K
| |
+
+Returns:
+
+`LiveSelector`
+
diff --git a/api-documents/kit.liveselector.closest_2.md b/api-documents/kit.liveselector.closest_2.md
new file mode 100644
index 0000000..56be45e
--- /dev/null
+++ b/api-documents/kit.liveselector.closest_2.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [closest](./kit.liveselector.closest_2.md)
+
+## LiveSelector.closest() method
+
+Signature:
+
+```typescript
+closest(selectors: K): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| selectors | K
| |
+
+Returns:
+
+`LiveSelector`
+
diff --git a/api-documents/kit.liveselector.closest_3.md b/api-documents/kit.liveselector.closest_3.md
new file mode 100644
index 0000000..64f1d64
--- /dev/null
+++ b/api-documents/kit.liveselector.closest_3.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [closest](./kit.liveselector.closest_3.md)
+
+## LiveSelector.closest() method
+
+Signature:
+
+```typescript
+closest(selectors: string): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| selectors | string
| |
+
+Returns:
+
+`LiveSelector`
+
diff --git a/api-documents/kit.liveselector.concat.md b/api-documents/kit.liveselector.concat.md
new file mode 100644
index 0000000..4bde930
--- /dev/null
+++ b/api-documents/kit.liveselector.concat.md
@@ -0,0 +1,32 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [concat](./kit.liveselector.concat.md)
+
+## LiveSelector.concat() method
+
+Combines two LiveSelector.
+
+Signature:
+
+```typescript
+concat(newEle: LiveSelector): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| newEle | LiveSelector<NextType>
| Additional LiveSelector to combine. |
+
+Returns:
+
+`LiveSelector`
+
+## Example
+
+
+```ts
+ls.concat(new LiveSelector().querySelector('#root'))
+
+```
+
diff --git a/api-documents/kit.liveselector.evaluateonce.md b/api-documents/kit.liveselector.evaluateonce.md
new file mode 100644
index 0000000..c5b2584
--- /dev/null
+++ b/api-documents/kit.liveselector.evaluateonce.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [evaluateOnce](./kit.liveselector.evaluateonce.md)
+
+## LiveSelector.evaluateOnce() method
+
+Evaluate selector expression
+
+Signature:
+
+```typescript
+evaluateOnce(): T[];
+```
+Returns:
+
+`T[]`
+
diff --git a/api-documents/kit.liveselector.filter.md b/api-documents/kit.liveselector.filter.md
new file mode 100644
index 0000000..f933011
--- /dev/null
+++ b/api-documents/kit.liveselector.filter.md
@@ -0,0 +1,32 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [filter](./kit.liveselector.filter.md)
+
+## LiveSelector.filter() method
+
+Select the elements of a LiveSelector that meet the condition specified in a callback function.
+
+Signature:
+
+```typescript
+filter(f: (value: T, index: number, array: T[]) => any): LiveSelector>;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| f | (value: T, index: number, array: T[]) => any
| The filter method |
+
+Returns:
+
+`LiveSelector>`
+
+## Example
+
+
+```ts
+ls.filter(x => x.innerText.match('hello'))
+
+```
+
diff --git a/api-documents/kit.liveselector.flat.md b/api-documents/kit.liveselector.flat.md
new file mode 100644
index 0000000..7d3396a
--- /dev/null
+++ b/api-documents/kit.liveselector.flat.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [flat](./kit.liveselector.flat.md)
+
+## LiveSelector.flat() method
+
+Flat T\[\]\[\] to T\[\]
+
+Signature:
+
+```typescript
+flat(): LiveSelector ? U : never>;
+```
+Returns:
+
+`LiveSelector ? U : never>`
+
+## Example
+
+
+```ts
+ls.flat()
+
+```
+
diff --git a/api-documents/kit.liveselector.getelementsbyclassname.md b/api-documents/kit.liveselector.getelementsbyclassname.md
new file mode 100644
index 0000000..767c342
--- /dev/null
+++ b/api-documents/kit.liveselector.getelementsbyclassname.md
@@ -0,0 +1,33 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [getElementsByClassName](./kit.liveselector.getelementsbyclassname.md)
+
+## LiveSelector.getElementsByClassName() method
+
+Select all element base on the current result.
+
+Signature:
+
+```typescript
+getElementsByClassName(className: string): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| className | string
| Class name |
+
+Returns:
+
+`LiveSelector`
+
+## Example
+
+Equal to ls.querySelectorAll('.a .b')
+
+```ts
+ls.getElementsByClassName('a').getElementsByClassName('b')
+
+```
+
diff --git a/api-documents/kit.liveselector.getelementsbytagname.md b/api-documents/kit.liveselector.getelementsbytagname.md
new file mode 100644
index 0000000..d06716e
--- /dev/null
+++ b/api-documents/kit.liveselector.getelementsbytagname.md
@@ -0,0 +1,33 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [getElementsByTagName](./kit.liveselector.getelementsbytagname.md)
+
+## LiveSelector.getElementsByTagName() method
+
+Select all element base on the current result.
+
+Signature:
+
+```typescript
+getElementsByTagName(tag: K): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| tag | K
| Tag name |
+
+Returns:
+
+`LiveSelector`
+
+## Example
+
+Equal to ls.querySelectorAll('a b')
+
+```ts
+ls.getElementsByTagName('a').getElementsByTagName('b')
+
+```
+
diff --git a/api-documents/kit.liveselector.getelementsbytagname_1.md b/api-documents/kit.liveselector.getelementsbytagname_1.md
new file mode 100644
index 0000000..9c8e049
--- /dev/null
+++ b/api-documents/kit.liveselector.getelementsbytagname_1.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [getElementsByTagName](./kit.liveselector.getelementsbytagname_1.md)
+
+## LiveSelector.getElementsByTagName() method
+
+Signature:
+
+```typescript
+getElementsByTagName(tag: K): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| tag | K
| |
+
+Returns:
+
+`LiveSelector`
+
diff --git a/api-documents/kit.liveselector.getelementsbytagname_2.md b/api-documents/kit.liveselector.getelementsbytagname_2.md
new file mode 100644
index 0000000..c17bbf3
--- /dev/null
+++ b/api-documents/kit.liveselector.getelementsbytagname_2.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [getElementsByTagName](./kit.liveselector.getelementsbytagname_2.md)
+
+## LiveSelector.getElementsByTagName() method
+
+Signature:
+
+```typescript
+getElementsByTagName(tag: string): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| tag | string
| |
+
+Returns:
+
+`LiveSelector`
+
diff --git a/api-documents/kit.liveselector.map.md b/api-documents/kit.liveselector.map.md
new file mode 100644
index 0000000..265a773
--- /dev/null
+++ b/api-documents/kit.liveselector.map.md
@@ -0,0 +1,32 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [map](./kit.liveselector.map.md)
+
+## LiveSelector.map() method
+
+Calls a defined callback function on each element of a LiveSelector, and continues with the results.
+
+Signature:
+
+```typescript
+map(callbackfn: (element: T) => NextType): LiveSelector>;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| callbackfn | (element: T) => NextType
| Map function |
+
+Returns:
+
+`LiveSelector>`
+
+## Example
+
+
+```ts
+ls.map(x => x.parentElement)
+
+```
+
diff --git a/api-documents/kit.liveselector.md b/api-documents/kit.liveselector.md
new file mode 100644
index 0000000..6e810e0
--- /dev/null
+++ b/api-documents/kit.liveselector.md
@@ -0,0 +1,48 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md)
+
+## LiveSelector class
+
+Create a live selector that can continuously select the element you want.
+
+Signature:
+
+```typescript
+export declare class LiveSelector
+```
+
+## Methods
+
+| Method | Modifiers | Description |
+| --- | --- | --- |
+| [clone()](./kit.liveselector.clone.md) | | Clone this LiveSelector and return a new LiveSelector. |
+| [closest(parentOfNth)](./kit.liveselector.closest.md) | | Reversely select element in the parent |
+| [closest(selectors)](./kit.liveselector.closest_1.md) | | |
+| [closest(selectors)](./kit.liveselector.closest_2.md) | | |
+| [closest(selectors)](./kit.liveselector.closest_3.md) | | |
+| [concat(newEle)](./kit.liveselector.concat.md) | | Combines two LiveSelector. |
+| [evaluateOnce()](./kit.liveselector.evaluateonce.md) | | Evaluate selector expression |
+| [filter(f)](./kit.liveselector.filter.md) | | Select the elements of a LiveSelector that meet the condition specified in a callback function. |
+| [flat()](./kit.liveselector.flat.md) | | Flat T\[\]\[\] to T\[\] |
+| [getElementsByClassName(className)](./kit.liveselector.getelementsbyclassname.md) | | Select all element base on the current result. |
+| [getElementsByTagName(tag)](./kit.liveselector.getelementsbytagname.md) | | Select all element base on the current result. |
+| [getElementsByTagName(tag)](./kit.liveselector.getelementsbytagname_1.md) | | |
+| [getElementsByTagName(tag)](./kit.liveselector.getelementsbytagname_2.md) | | |
+| [map(callbackfn)](./kit.liveselector.map.md) | | Calls a defined callback function on each element of a LiveSelector, and continues with the results. |
+| [nth(n)](./kit.liveselector.nth.md) | | Select only nth element |
+| [querySelector(selector)](./kit.liveselector.queryselector.md) | | Select the first element that is a descendant of node that matches selectors. |
+| [querySelector(selector)](./kit.liveselector.queryselector_1.md) | | |
+| [querySelector(selector)](./kit.liveselector.queryselector_2.md) | | |
+| [querySelectorAll(selector)](./kit.liveselector.queryselectorall.md) | | Select all element descendants of node that match selectors. |
+| [querySelectorAll(selector)](./kit.liveselector.queryselectorall_1.md) | | |
+| [querySelectorAll(selector)](./kit.liveselector.queryselectorall_2.md) | | |
+| [replace(f)](./kit.liveselector.replace.md) | | Replace the whole array. |
+| [reverse()](./kit.liveselector.reverse.md) | | Reverses the elements in an Array. |
+| [slice(start, end)](./kit.liveselector.slice.md) | | Returns a section of an array. |
+| [sort(compareFn)](./kit.liveselector.sort.md) | | Sorts an array. |
+
+## Remarks
+
+Call [\#evaluateOnce](./kit.liveselector.evaluateonce.md) to evaluate the element. Falsy value will be ignored.
+
diff --git a/api-documents/kit.liveselector.nth.md b/api-documents/kit.liveselector.nth.md
new file mode 100644
index 0000000..a5205bf
--- /dev/null
+++ b/api-documents/kit.liveselector.nth.md
@@ -0,0 +1,32 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [nth](./kit.liveselector.nth.md)
+
+## LiveSelector.nth() method
+
+Select only nth element
+
+Signature:
+
+```typescript
+nth(n: number): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| n | number
| Select only nth element, allow negative number. |
+
+Returns:
+
+`LiveSelector`
+
+## Example
+
+
+```ts
+ls.nth(-1)
+
+```
+
diff --git a/api-documents/kit.liveselector.queryselector.md b/api-documents/kit.liveselector.queryselector.md
new file mode 100644
index 0000000..1cdb51e
--- /dev/null
+++ b/api-documents/kit.liveselector.queryselector.md
@@ -0,0 +1,32 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [querySelector](./kit.liveselector.queryselector.md)
+
+## LiveSelector.querySelector() method
+
+Select the first element that is a descendant of node that matches selectors.
+
+Signature:
+
+```typescript
+querySelector(selector: K): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| selector | K
| Selector |
+
+Returns:
+
+`LiveSelector`
+
+## Example
+
+
+```ts
+ls.querySelector('div#root')
+
+```
+
diff --git a/api-documents/kit.liveselector.queryselector_1.md b/api-documents/kit.liveselector.queryselector_1.md
new file mode 100644
index 0000000..94314bc
--- /dev/null
+++ b/api-documents/kit.liveselector.queryselector_1.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [querySelector](./kit.liveselector.queryselector_1.md)
+
+## LiveSelector.querySelector() method
+
+Signature:
+
+```typescript
+querySelector(selector: K): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| selector | K
| |
+
+Returns:
+
+`LiveSelector`
+
diff --git a/api-documents/kit.liveselector.queryselector_2.md b/api-documents/kit.liveselector.queryselector_2.md
new file mode 100644
index 0000000..866fd5b
--- /dev/null
+++ b/api-documents/kit.liveselector.queryselector_2.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [querySelector](./kit.liveselector.queryselector_2.md)
+
+## LiveSelector.querySelector() method
+
+Signature:
+
+```typescript
+querySelector(selector: string): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| selector | string
| |
+
+Returns:
+
+`LiveSelector`
+
diff --git a/api-documents/kit.liveselector.queryselectorall.md b/api-documents/kit.liveselector.queryselectorall.md
new file mode 100644
index 0000000..57b68ac
--- /dev/null
+++ b/api-documents/kit.liveselector.queryselectorall.md
@@ -0,0 +1,32 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [querySelectorAll](./kit.liveselector.queryselectorall.md)
+
+## LiveSelector.querySelectorAll() method
+
+Select all element descendants of node that match selectors.
+
+Signature:
+
+```typescript
+querySelectorAll(selector: K): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| selector | K
| Selector |
+
+Returns:
+
+`LiveSelector`
+
+## Example
+
+
+```ts
+ls.querySelector('div > div')
+
+```
+
diff --git a/api-documents/kit.liveselector.queryselectorall_1.md b/api-documents/kit.liveselector.queryselectorall_1.md
new file mode 100644
index 0000000..8fefa5b
--- /dev/null
+++ b/api-documents/kit.liveselector.queryselectorall_1.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [querySelectorAll](./kit.liveselector.queryselectorall_1.md)
+
+## LiveSelector.querySelectorAll() method
+
+Signature:
+
+```typescript
+querySelectorAll(selector: K): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| selector | K
| |
+
+Returns:
+
+`LiveSelector`
+
diff --git a/api-documents/kit.liveselector.queryselectorall_2.md b/api-documents/kit.liveselector.queryselectorall_2.md
new file mode 100644
index 0000000..5ec1f07
--- /dev/null
+++ b/api-documents/kit.liveselector.queryselectorall_2.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [querySelectorAll](./kit.liveselector.queryselectorall_2.md)
+
+## LiveSelector.querySelectorAll() method
+
+Signature:
+
+```typescript
+querySelectorAll(selector: string): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| selector | string
| |
+
+Returns:
+
+`LiveSelector`
+
diff --git a/api-documents/kit.liveselector.replace.md b/api-documents/kit.liveselector.replace.md
new file mode 100644
index 0000000..b586b90
--- /dev/null
+++ b/api-documents/kit.liveselector.replace.md
@@ -0,0 +1,32 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [replace](./kit.liveselector.replace.md)
+
+## LiveSelector.replace() method
+
+Replace the whole array.
+
+Signature:
+
+```typescript
+replace(f: (arr: T[]) => NextType[]): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| f | (arr: T[]) => NextType[]
| returns new array. |
+
+Returns:
+
+`LiveSelector`
+
+## Example
+
+
+```ts
+ls.replace(x => lodash.dropRight(x, 2))
+
+```
+
diff --git a/api-documents/kit.liveselector.reverse.md b/api-documents/kit.liveselector.reverse.md
new file mode 100644
index 0000000..0048b86
--- /dev/null
+++ b/api-documents/kit.liveselector.reverse.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [reverse](./kit.liveselector.reverse.md)
+
+## LiveSelector.reverse() method
+
+Reverses the elements in an Array.
+
+Signature:
+
+```typescript
+reverse(): LiveSelector;
+```
+Returns:
+
+`LiveSelector`
+
+## Example
+
+
+```ts
+ls.reverse()
+
+```
+
diff --git a/api-documents/kit.liveselector.slice.md b/api-documents/kit.liveselector.slice.md
new file mode 100644
index 0000000..a8e8980
--- /dev/null
+++ b/api-documents/kit.liveselector.slice.md
@@ -0,0 +1,33 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [slice](./kit.liveselector.slice.md)
+
+## LiveSelector.slice() method
+
+Returns a section of an array.
+
+Signature:
+
+```typescript
+slice(start?: number, end?: number): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| start | number
| The beginning of the specified portion of the array. |
+| end | number
| The end of the specified portion of the array. |
+
+Returns:
+
+`LiveSelector`
+
+## Example
+
+
+```ts
+ls.slice(2, 4)
+
+```
+
diff --git a/api-documents/kit.liveselector.sort.md b/api-documents/kit.liveselector.sort.md
new file mode 100644
index 0000000..2f4c338
--- /dev/null
+++ b/api-documents/kit.liveselector.sort.md
@@ -0,0 +1,32 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [LiveSelector](./kit.liveselector.md) > [sort](./kit.liveselector.sort.md)
+
+## LiveSelector.sort() method
+
+Sorts an array.
+
+Signature:
+
+```typescript
+sort(compareFn?: (a: T, b: T) => number): LiveSelector;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| compareFn | (a: T, b: T) => number
| The name of the function used to determine the order of the elements. If omitted, the elements are sorted in ascending, ASCII character order. |
+
+Returns:
+
+`LiveSelector`
+
+## Example
+
+
+```ts
+ls.sort((a, b) => a.innerText.length - b.innerText.length)
+
+```
+
diff --git a/api-documents/kit.md b/api-documents/kit.md
new file mode 100644
index 0000000..28e62a8
--- /dev/null
+++ b/api-documents/kit.md
@@ -0,0 +1,55 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md)
+
+## kit package
+
+A toolkit for browser extension developing.
+
+## Classes
+
+| Class | Description |
+| --- | --- |
+| [EventWatcher](./kit.eventwatcher.md) | A Watcher based on event handlers. |
+| [IntervalWatcher](./kit.intervalwatcher.md) | A watcher based on time interval. |
+| [LiveSelector](./kit.liveselector.md) | Create a live selector that can continuously select the element you want. |
+| [MessageCenter](./kit.messagecenter.md) | Send and receive messages in different contexts. |
+| [MutationObserverWatcher](./kit.mutationobserverwatcher.md) | A watcher based on MutationObserver |
+| [ValueRef](./kit.valueref.md) | A ref
object with addListener
|
+| [Watcher](./kit.watcher.md) | Use LiveSelector to watch dom changeYou need to implement startWatch
|
+
+## Functions
+
+| Function | Description |
+| --- | --- |
+| [AsyncCall(implementation, options)](./kit.asynccall.md) | Async call between different context. |
+| [AutomatedTabTask(taskImplements, options)](./kit.automatedtabtask.md) | Open a new page in the background, execute some task, then close it automatically. |
+| [DomProxy(options)](./kit.domproxy.md) | DomProxy provide an interface that be stable even dom is changed. |
+| [GetContext()](./kit.getcontext.md) | Get current running context. |
+| [OnlyRunInContext(context, name)](./kit.onlyrunincontext.md) | Make sure this file only run in wanted context |
+| [OnlyRunInContext(context, throws)](./kit.onlyrunincontext_1.md) | |
+
+## Interfaces
+
+| Interface | Description |
+| --- | --- |
+| [AsyncCallOptions](./kit.asynccalloptions.md) | Options for [AsyncCall()](./kit.asynccall.md) |
+| [AutomatedTabTaskDefineTimeOptions](./kit.automatedtabtaskdefinetimeoptions.md) | Define-time options for [AutomatedTabTask()](./kit.automatedtabtask.md) |
+| [AutomatedTabTaskRuntimeOptions](./kit.automatedtabtaskruntimeoptions.md) | Runtime options for [AutomatedTabTask()](./kit.automatedtabtask.md) |
+| [DomProxy](./kit.domproxy.md) | A DomProxy object |
+| [DomProxyOptions](./kit.domproxyoptions.md) | Options for DomProxy |
+| [Serialization](./kit.serialization.md) | Define how to do serialization and deserialization of remote procedure call |
+
+## Variables
+
+| Variable | Description |
+| --- | --- |
+| [JSONSerialization](./kit.jsonserialization.md) | Serialization implementation by JSON.parse/stringify |
+| [NoSerialization](./kit.noserialization.md) | Serialization implementation that do nothing |
+
+## Type Aliases
+
+| Type Alias | Description |
+| --- | --- |
+| [Contexts](./kit.contexts.md) | All context that possible in when developing a WebExtension |
+
diff --git a/api-documents/kit.messagecenter.md b/api-documents/kit.messagecenter.md
new file mode 100644
index 0000000..0901dbe
--- /dev/null
+++ b/api-documents/kit.messagecenter.md
@@ -0,0 +1,27 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [MessageCenter](./kit.messagecenter.md)
+
+## MessageCenter class
+
+Send and receive messages in different contexts.
+
+Signature:
+
+```typescript
+export declare class MessageCenter
+```
+
+## Properties
+
+| Property | Modifiers | Type | Description |
+| --- | --- | --- | --- |
+| [writeToConsole](./kit.messagecenter.writetoconsole.md) | | boolean
| |
+
+## Methods
+
+| Method | Modifiers | Description |
+| --- | --- | --- |
+| [on(event, handler)](./kit.messagecenter.on.md) | | Listen to an event |
+| [send(key, data, alsoSendToDocument)](./kit.messagecenter.send.md) | | Send message to local or other instance of extension |
+
diff --git a/api-documents/kit.messagecenter.on.md b/api-documents/kit.messagecenter.on.md
new file mode 100644
index 0000000..82056e8
--- /dev/null
+++ b/api-documents/kit.messagecenter.on.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [MessageCenter](./kit.messagecenter.md) > [on](./kit.messagecenter.on.md)
+
+## MessageCenter.on() method
+
+Listen to an event
+
+Signature:
+
+```typescript
+on(event: Key, handler: (data: ITypedMessages[Key]) => void): void;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| event | Key
| Name of the event |
+| handler | (data: ITypedMessages[Key]) => void
| Handler of the event |
+
+Returns:
+
+`void`
+
diff --git a/api-documents/kit.messagecenter.send.md b/api-documents/kit.messagecenter.send.md
new file mode 100644
index 0000000..10c6d1b
--- /dev/null
+++ b/api-documents/kit.messagecenter.send.md
@@ -0,0 +1,26 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [MessageCenter](./kit.messagecenter.md) > [send](./kit.messagecenter.send.md)
+
+## MessageCenter.send() method
+
+Send message to local or other instance of extension
+
+Signature:
+
+```typescript
+send(key: Key, data: ITypedMessages[Key], alsoSendToDocument?: boolean): void;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| key | Key
| Key of the message |
+| data | ITypedMessages[Key]
| Data of the message |
+| alsoSendToDocument | boolean
| ! Send message to document. This may leaks secret! Only open in localhost! |
+
+Returns:
+
+`void`
+
diff --git a/api-documents/kit.messagecenter.writetoconsole.md b/api-documents/kit.messagecenter.writetoconsole.md
new file mode 100644
index 0000000..081cdc0
--- /dev/null
+++ b/api-documents/kit.messagecenter.writetoconsole.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [MessageCenter](./kit.messagecenter.md) > [writeToConsole](./kit.messagecenter.writetoconsole.md)
+
+## MessageCenter.writeToConsole property
+
+Signature:
+
+```typescript
+writeToConsole: boolean;
+```
diff --git a/api-documents/kit.mutationobserverwatcher.liveselector.md b/api-documents/kit.mutationobserverwatcher.liveselector.md
new file mode 100644
index 0000000..7c37a54
--- /dev/null
+++ b/api-documents/kit.mutationobserverwatcher.liveselector.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [MutationObserverWatcher](./kit.mutationobserverwatcher.md) > [liveSelector](./kit.mutationobserverwatcher.liveselector.md)
+
+## MutationObserverWatcher.liveSelector property
+
+Signature:
+
+```typescript
+protected liveSelector: LiveSelector;
+```
diff --git a/api-documents/kit.mutationobserverwatcher.md b/api-documents/kit.mutationobserverwatcher.md
new file mode 100644
index 0000000..65a4bae
--- /dev/null
+++ b/api-documents/kit.mutationobserverwatcher.md
@@ -0,0 +1,27 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [MutationObserverWatcher](./kit.mutationobserverwatcher.md)
+
+## MutationObserverWatcher class
+
+A watcher based on MutationObserver
+
+Signature:
+
+```typescript
+export declare class MutationObserverWatcher extends Watcher
+```
+
+## Properties
+
+| Property | Modifiers | Type | Description |
+| --- | --- | --- | --- |
+| [liveSelector](./kit.mutationobserverwatcher.liveselector.md) | | LiveSelector<T>
| |
+
+## Methods
+
+| Method | Modifiers | Description |
+| --- | --- | --- |
+| [startWatch(options)](./kit.mutationobserverwatcher.startwatch.md) | | |
+| [stopWatch()](./kit.mutationobserverwatcher.stopwatch.md) | | |
+
diff --git a/api-documents/kit.mutationobserverwatcher.startwatch.md b/api-documents/kit.mutationobserverwatcher.startwatch.md
new file mode 100644
index 0000000..7fc575c
--- /dev/null
+++ b/api-documents/kit.mutationobserverwatcher.startwatch.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [MutationObserverWatcher](./kit.mutationobserverwatcher.md) > [startWatch](./kit.mutationobserverwatcher.startwatch.md)
+
+## MutationObserverWatcher.startWatch() method
+
+Signature:
+
+```typescript
+startWatch(options?: MutationObserverInit): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| options | MutationObserverInit
| |
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.mutationobserverwatcher.stopwatch.md b/api-documents/kit.mutationobserverwatcher.stopwatch.md
new file mode 100644
index 0000000..7c789b4
--- /dev/null
+++ b/api-documents/kit.mutationobserverwatcher.stopwatch.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [MutationObserverWatcher](./kit.mutationobserverwatcher.md) > [stopWatch](./kit.mutationobserverwatcher.stopwatch.md)
+
+## MutationObserverWatcher.stopWatch() method
+
+Signature:
+
+```typescript
+stopWatch(): void;
+```
+Returns:
+
+`void`
+
diff --git a/api-documents/kit.noserialization.md b/api-documents/kit.noserialization.md
new file mode 100644
index 0000000..2419b28
--- /dev/null
+++ b/api-documents/kit.noserialization.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [NoSerialization](./kit.noserialization.md)
+
+## NoSerialization variable
+
+Serialization implementation that do nothing
+
+Signature:
+
+```typescript
+NoSerialization: Serialization
+```
diff --git a/api-documents/kit.onlyrunincontext.md b/api-documents/kit.onlyrunincontext.md
new file mode 100644
index 0000000..04e1a4c
--- /dev/null
+++ b/api-documents/kit.onlyrunincontext.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [OnlyRunInContext](./kit.onlyrunincontext.md)
+
+## OnlyRunInContext() function
+
+Make sure this file only run in wanted context
+
+Signature:
+
+```typescript
+export declare function OnlyRunInContext(context: Contexts | Contexts[], name: string): void;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| context | Contexts | Contexts[]
| Wanted context or contexts |
+| name | string
| name to throw |
+
+Returns:
+
+`void`
+
diff --git a/api-documents/kit.onlyrunincontext_1.md b/api-documents/kit.onlyrunincontext_1.md
new file mode 100644
index 0000000..04c6b54
--- /dev/null
+++ b/api-documents/kit.onlyrunincontext_1.md
@@ -0,0 +1,23 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [OnlyRunInContext](./kit.onlyrunincontext_1.md)
+
+## OnlyRunInContext() function
+
+Signature:
+
+```typescript
+export declare function OnlyRunInContext(context: Contexts | Contexts[], throws: false): boolean;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| context | Contexts | Contexts[]
| |
+| throws | false
| |
+
+Returns:
+
+`boolean`
+
diff --git a/api-documents/kit.serialization.deserialization.md b/api-documents/kit.serialization.deserialization.md
new file mode 100644
index 0000000..3220edb
--- /dev/null
+++ b/api-documents/kit.serialization.deserialization.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Serialization](./kit.serialization.md) > [deserialization](./kit.serialization.deserialization.md)
+
+## Serialization.deserialization() method
+
+Signature:
+
+```typescript
+deserialization(serialized: unknown): Promise;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| serialized | unknown
| |
+
+Returns:
+
+`Promise`
+
diff --git a/api-documents/kit.serialization.md b/api-documents/kit.serialization.md
new file mode 100644
index 0000000..1418ed5
--- /dev/null
+++ b/api-documents/kit.serialization.md
@@ -0,0 +1,21 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Serialization](./kit.serialization.md)
+
+## Serialization interface
+
+Define how to do serialization and deserialization of remote procedure call
+
+Signature:
+
+```typescript
+export interface Serialization
+```
+
+## Methods
+
+| Method | Description |
+| --- | --- |
+| [deserialization(serialized)](./kit.serialization.deserialization.md) | |
+| [serialization(from)](./kit.serialization.serialization.md) | |
+
diff --git a/api-documents/kit.serialization.serialization.md b/api-documents/kit.serialization.serialization.md
new file mode 100644
index 0000000..70c5c8a
--- /dev/null
+++ b/api-documents/kit.serialization.serialization.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Serialization](./kit.serialization.md) > [serialization](./kit.serialization.serialization.md)
+
+## Serialization.serialization() method
+
+Signature:
+
+```typescript
+serialization(from: any): Promise;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| from | any
| |
+
+Returns:
+
+`Promise`
+
diff --git a/api-documents/kit.valueref.addlistener.md b/api-documents/kit.valueref.addlistener.md
new file mode 100644
index 0000000..b759682
--- /dev/null
+++ b/api-documents/kit.valueref.addlistener.md
@@ -0,0 +1,32 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [ValueRef](./kit.valueref.md) > [addListener](./kit.valueref.addlistener.md)
+
+## ValueRef.addListener() method
+
+Add a listener. This will return a remover.
+
+Signature:
+
+```typescript
+addListener(fn: Fn): () => void;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| fn | Fn<T>
| |
+
+Returns:
+
+`() => void`
+
+## Example
+
+
+```ts
+React.useEffect(() => ref.addListener(() => {...}))
+
+```
+
diff --git a/api-documents/kit.valueref.md b/api-documents/kit.valueref.md
new file mode 100644
index 0000000..797cd7c
--- /dev/null
+++ b/api-documents/kit.valueref.md
@@ -0,0 +1,28 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [ValueRef](./kit.valueref.md)
+
+## ValueRef class
+
+A `ref` object with `addListener`
+
+Signature:
+
+```typescript
+export declare class ValueRef
+```
+
+## Properties
+
+| Property | Modifiers | Type | Description |
+| --- | --- | --- | --- |
+| [value](./kit.valueref.value.md) | | T
| Set current value of a ValueRef |
+
+## Methods
+
+| Method | Modifiers | Description |
+| --- | --- | --- |
+| [addListener(fn)](./kit.valueref.addlistener.md) | | Add a listener. This will return a remover. |
+| [removeAllListener()](./kit.valueref.removealllistener.md) | | Remove all listeners |
+| [removeListener(fn)](./kit.valueref.removelistener.md) | | Remove a listener |
+
diff --git a/api-documents/kit.valueref.removealllistener.md b/api-documents/kit.valueref.removealllistener.md
new file mode 100644
index 0000000..a54c66a
--- /dev/null
+++ b/api-documents/kit.valueref.removealllistener.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [ValueRef](./kit.valueref.md) > [removeAllListener](./kit.valueref.removealllistener.md)
+
+## ValueRef.removeAllListener() method
+
+Remove all listeners
+
+Signature:
+
+```typescript
+removeAllListener(): void;
+```
+Returns:
+
+`void`
+
diff --git a/api-documents/kit.valueref.removelistener.md b/api-documents/kit.valueref.removelistener.md
new file mode 100644
index 0000000..963abcf
--- /dev/null
+++ b/api-documents/kit.valueref.removelistener.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [ValueRef](./kit.valueref.md) > [removeListener](./kit.valueref.removelistener.md)
+
+## ValueRef.removeListener() method
+
+Remove a listener
+
+Signature:
+
+```typescript
+removeListener(fn: Fn): void;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| fn | Fn<T>
| |
+
+Returns:
+
+`void`
+
diff --git a/api-documents/kit.valueref.value.md b/api-documents/kit.valueref.value.md
new file mode 100644
index 0000000..081b0d9
--- /dev/null
+++ b/api-documents/kit.valueref.value.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [ValueRef](./kit.valueref.md) > [value](./kit.valueref.value.md)
+
+## ValueRef.value property
+
+Set current value of a ValueRef
+
+Signature:
+
+```typescript
+value: T;
+```
diff --git a/api-documents/kit.watcher._omitwarningforrepeatedkeys.md b/api-documents/kit.watcher._omitwarningforrepeatedkeys.md
new file mode 100644
index 0000000..5cdc527
--- /dev/null
+++ b/api-documents/kit.watcher._omitwarningforrepeatedkeys.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [\_omitWarningForRepeatedKeys](./kit.watcher._omitwarningforrepeatedkeys.md)
+
+## Watcher.\_omitWarningForRepeatedKeys property
+
+Signature:
+
+```typescript
+protected _omitWarningForRepeatedKeys: boolean;
+```
diff --git a/api-documents/kit.watcher.addlistener.md b/api-documents/kit.watcher.addlistener.md
new file mode 100644
index 0000000..15a123f
--- /dev/null
+++ b/api-documents/kit.watcher.addlistener.md
@@ -0,0 +1,28 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [addListener](./kit.watcher.addlistener.md)
+
+## Watcher.addListener() method
+
+Signature:
+
+```typescript
+addListener(event: 'onChange', fn: EventCallback<{
+ oldNode: T;
+ newNode: T;
+ oldKey: unknown;
+ newKey: unknown;
+ }[]>): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| event | 'onChange'
| |
+| fn | EventCallback<{
oldNode: T;
newNode: T;
oldKey: unknown;
newKey: unknown;
}[]>
| |
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.watcher.addlistener_1.md b/api-documents/kit.watcher.addlistener_1.md
new file mode 100644
index 0000000..f5bff2f
--- /dev/null
+++ b/api-documents/kit.watcher.addlistener_1.md
@@ -0,0 +1,23 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [addListener](./kit.watcher.addlistener_1.md)
+
+## Watcher.addListener() method
+
+Signature:
+
+```typescript
+addListener(event: 'onChangeFull', fn: EventCallback): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| event | 'onChangeFull'
| |
+| fn | EventCallback<T[]>
| |
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.watcher.addlistener_2.md b/api-documents/kit.watcher.addlistener_2.md
new file mode 100644
index 0000000..e32d86a
--- /dev/null
+++ b/api-documents/kit.watcher.addlistener_2.md
@@ -0,0 +1,26 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [addListener](./kit.watcher.addlistener_2.md)
+
+## Watcher.addListener() method
+
+Signature:
+
+```typescript
+addListener(event: 'onRemove' | 'onAdd', fn: EventCallback<{
+ node: T;
+ key: unknown;
+ }[]>): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| event | 'onRemove' | 'onAdd'
| |
+| fn | EventCallback<{
node: T;
key: unknown;
}[]>
| |
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.watcher.assignkeys.md b/api-documents/kit.watcher.assignkeys.md
new file mode 100644
index 0000000..08109a5
--- /dev/null
+++ b/api-documents/kit.watcher.assignkeys.md
@@ -0,0 +1,27 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [assignKeys](./kit.watcher.assignkeys.md)
+
+## Watcher.assignKeys() method
+
+To help identify same nodes in different iteration, you need to implement a map function that map `node` to `key`
+
+If the key is changed, the same node will call through `forEachRemove` then `forEach`
+
+Signature:
+
+```typescript
+assignKeys(assigner: (node: T, index: number, arr: T[]) => Q, comparer?: (a: Q, b: Q) => boolean): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| assigner | (node: T, index: number, arr: T[]) => Q
| map node
to key
, defaults to node => node
|
+| comparer | (a: Q, b: Q) => boolean
| compare between two keys, defaults to ===
|
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.watcher.domproxyoption.md b/api-documents/kit.watcher.domproxyoption.md
new file mode 100644
index 0000000..944b72e
--- /dev/null
+++ b/api-documents/kit.watcher.domproxyoption.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [domProxyOption](./kit.watcher.domproxyoption.md)
+
+## Watcher.domProxyOption property
+
+Signature:
+
+```typescript
+protected domProxyOption: Partial>;
+```
diff --git a/api-documents/kit.watcher.emit.md b/api-documents/kit.watcher.emit.md
new file mode 100644
index 0000000..93050e8
--- /dev/null
+++ b/api-documents/kit.watcher.emit.md
@@ -0,0 +1,28 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [emit](./kit.watcher.emit.md)
+
+## Watcher.emit() method
+
+Signature:
+
+```typescript
+protected emit(event: 'onChange', data: {
+ oldNode: T;
+ newNode: T;
+ oldKey: unknown;
+ newKey: unknown;
+ }[]): boolean;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| event | 'onChange'
| |
+| data | {
oldNode: T;
newNode: T;
oldKey: unknown;
newKey: unknown;
}[]
| |
+
+Returns:
+
+`boolean`
+
diff --git a/api-documents/kit.watcher.emit_1.md b/api-documents/kit.watcher.emit_1.md
new file mode 100644
index 0000000..0ca9049
--- /dev/null
+++ b/api-documents/kit.watcher.emit_1.md
@@ -0,0 +1,23 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [emit](./kit.watcher.emit_1.md)
+
+## Watcher.emit() method
+
+Signature:
+
+```typescript
+protected emit(event: 'onChangeFull', data: T[]): boolean;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| event | 'onChangeFull'
| |
+| data | T[]
| |
+
+Returns:
+
+`boolean`
+
diff --git a/api-documents/kit.watcher.emit_2.md b/api-documents/kit.watcher.emit_2.md
new file mode 100644
index 0000000..7f8fe06
--- /dev/null
+++ b/api-documents/kit.watcher.emit_2.md
@@ -0,0 +1,26 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [emit](./kit.watcher.emit_2.md)
+
+## Watcher.emit() method
+
+Signature:
+
+```typescript
+protected emit(event: 'onRemove' | 'onAdd', data: {
+ node: T;
+ key: unknown;
+ }[]): boolean;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| event | 'onRemove' | 'onAdd'
| |
+| data | {
node: T;
key: unknown;
}[]
| |
+
+Returns:
+
+`boolean`
+
diff --git a/api-documents/kit.watcher.eventemitter.md b/api-documents/kit.watcher.eventemitter.md
new file mode 100644
index 0000000..43c40ad
--- /dev/null
+++ b/api-documents/kit.watcher.eventemitter.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [eventEmitter](./kit.watcher.eventemitter.md)
+
+## Watcher.eventEmitter property
+
+Event emitter
+
+Signature:
+
+```typescript
+protected readonly eventEmitter: EventEmitter;
+```
diff --git a/api-documents/kit.watcher.findnodefromlistbykey.md b/api-documents/kit.watcher.findnodefromlistbykey.md
new file mode 100644
index 0000000..ba83aeb
--- /dev/null
+++ b/api-documents/kit.watcher.findnodefromlistbykey.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [findNodeFromListByKey](./kit.watcher.findnodefromlistbykey.md)
+
+## Watcher.findNodeFromListByKey property
+
+Find node from the given list by key
+
+Signature:
+
+```typescript
+protected findNodeFromListByKey: (list: T[], keys: unknown[]) => (key: unknown) => T | null;
+```
diff --git a/api-documents/kit.watcher.firstvirtualnode.md b/api-documents/kit.watcher.firstvirtualnode.md
new file mode 100644
index 0000000..4e14792
--- /dev/null
+++ b/api-documents/kit.watcher.firstvirtualnode.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [firstVirtualNode](./kit.watcher.firstvirtualnode.md)
+
+## Watcher.firstVirtualNode property
+
+This virtualNode always point to the first node in the LiveSelector
+
+Signature:
+
+```typescript
+readonly firstVirtualNode: RequireElement, DomProxyBefore, DomProxyAfter>>;
+```
diff --git a/api-documents/kit.watcher.getvirtualnodebykey.md b/api-documents/kit.watcher.getvirtualnodebykey.md
new file mode 100644
index 0000000..6fb0ce7
--- /dev/null
+++ b/api-documents/kit.watcher.getvirtualnodebykey.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [getVirtualNodeByKey](./kit.watcher.getvirtualnodebykey.md)
+
+## Watcher.getVirtualNodeByKey() method
+
+Get virtual node by key. Virtual node will be unavailable if it is deleted
+
+Signature:
+
+```typescript
+getVirtualNodeByKey(key: unknown): DomProxy, DomProxyBefore, DomProxyAfter> | null;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| key | unknown
| Key used to find DomProxy |
+
+Returns:
+
+`DomProxy, DomProxyBefore, DomProxyAfter> | null`
+
diff --git a/api-documents/kit.watcher.keycomparer.md b/api-documents/kit.watcher.keycomparer.md
new file mode 100644
index 0000000..de7a4e1
--- /dev/null
+++ b/api-documents/kit.watcher.keycomparer.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [keyComparer](./kit.watcher.keycomparer.md)
+
+## Watcher.keyComparer() method
+
+Compare between `key` and `key`, in case of you don't want the default behavior
+
+Signature:
+
+```typescript
+protected keyComparer(a: unknown, b: unknown): boolean;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| a | unknown
| |
+| b | unknown
| |
+
+Returns:
+
+`boolean`
+
diff --git a/api-documents/kit.watcher.lastcallbackmap.md b/api-documents/kit.watcher.lastcallbackmap.md
new file mode 100644
index 0000000..c08afda
--- /dev/null
+++ b/api-documents/kit.watcher.lastcallbackmap.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [lastCallbackMap](./kit.watcher.lastcallbackmap.md)
+
+## Watcher.lastCallbackMap property
+
+Saved callback map of last watch
+
+Signature:
+
+```typescript
+protected lastCallbackMap: Map>;
+```
diff --git a/api-documents/kit.watcher.lastkeylist.md b/api-documents/kit.watcher.lastkeylist.md
new file mode 100644
index 0000000..69ef0fe
--- /dev/null
+++ b/api-documents/kit.watcher.lastkeylist.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [lastKeyList](./kit.watcher.lastkeylist.md)
+
+## Watcher.lastKeyList property
+
+Found key list of last watch
+
+Signature:
+
+```typescript
+protected lastKeyList: unknown[];
+```
diff --git a/api-documents/kit.watcher.lastnodelist.md b/api-documents/kit.watcher.lastnodelist.md
new file mode 100644
index 0000000..81f322f
--- /dev/null
+++ b/api-documents/kit.watcher.lastnodelist.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [lastNodeList](./kit.watcher.lastnodelist.md)
+
+## Watcher.lastNodeList property
+
+Found Node list of last watch
+
+Signature:
+
+```typescript
+protected lastNodeList: T[];
+```
diff --git a/api-documents/kit.watcher.lastvirtualnodesmap.md b/api-documents/kit.watcher.lastvirtualnodesmap.md
new file mode 100644
index 0000000..f31059f
--- /dev/null
+++ b/api-documents/kit.watcher.lastvirtualnodesmap.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [lastVirtualNodesMap](./kit.watcher.lastvirtualnodesmap.md)
+
+## Watcher.lastVirtualNodesMap property
+
+Saved virtual node of last watch
+
+Signature:
+
+```typescript
+protected lastVirtualNodesMap: Map, DomProxyBefore, DomProxyAfter>>;
+```
diff --git a/api-documents/kit.watcher.liveselector.md b/api-documents/kit.watcher.liveselector.md
new file mode 100644
index 0000000..7f9554e
--- /dev/null
+++ b/api-documents/kit.watcher.liveselector.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [liveSelector](./kit.watcher.liveselector.md)
+
+## Watcher.liveSelector property
+
+Signature:
+
+```typescript
+protected liveSelector: LiveSelector;
+```
diff --git a/api-documents/kit.watcher.mapnodetokey.md b/api-documents/kit.watcher.mapnodetokey.md
new file mode 100644
index 0000000..8f9ddfd
--- /dev/null
+++ b/api-documents/kit.watcher.mapnodetokey.md
@@ -0,0 +1,26 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [mapNodeToKey](./kit.watcher.mapnodetokey.md)
+
+## Watcher.mapNodeToKey() method
+
+Map `Node -> Key`, in case of you don't want the default behavior
+
+Signature:
+
+```typescript
+protected mapNodeToKey(node: T, index: number, arr: T[]): unknown;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| node | T
| |
+| index | number
| |
+| arr | T[]
| |
+
+Returns:
+
+`unknown`
+
diff --git a/api-documents/kit.watcher.md b/api-documents/kit.watcher.md
new file mode 100644
index 0000000..6ced2ff
--- /dev/null
+++ b/api-documents/kit.watcher.md
@@ -0,0 +1,60 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md)
+
+## Watcher class
+
+Use LiveSelector to watch dom change
+
+You need to implement `startWatch`
+
+Signature:
+
+```typescript
+export declare abstract class Watcher
+```
+
+## Properties
+
+| Property | Modifiers | Type | Description |
+| --- | --- | --- | --- |
+| [\_omitWarningForRepeatedKeys](./kit.watcher._omitwarningforrepeatedkeys.md) | | boolean
| |
+| [domProxyOption](./kit.watcher.domproxyoption.md) | | Partial<DomProxyOptions<DomProxyBefore, DomProxyAfter>>
| |
+| [eventEmitter](./kit.watcher.eventemitter.md) | | EventEmitter
| Event emitter |
+| [findNodeFromListByKey](./kit.watcher.findnodefromlistbykey.md) | | (list: T[], keys: unknown[]) => (key: unknown) => T | null
| Find node from the given list by key |
+| [firstVirtualNode](./kit.watcher.firstvirtualnode.md) | | RequireElement<T, DomProxy<ElementLikeT<T>, DomProxyBefore, DomProxyAfter>>
| This virtualNode always point to the first node in the LiveSelector |
+| [lastCallbackMap](./kit.watcher.lastcallbackmap.md) | | Map<unknown, useNodeForeachReturns<T>>
| Saved callback map of last watch |
+| [lastKeyList](./kit.watcher.lastkeylist.md) | | unknown[]
| Found key list of last watch |
+| [lastNodeList](./kit.watcher.lastnodelist.md) | | T[]
| Found Node list of last watch |
+| [lastVirtualNodesMap](./kit.watcher.lastvirtualnodesmap.md) | | Map<unknown, DomProxy<ElementLikeT<T>, DomProxyBefore, DomProxyAfter>>
| Saved virtual node of last watch |
+| [liveSelector](./kit.watcher.liveselector.md) | | LiveSelector<T>
| |
+| [useNodeForeachFn](./kit.watcher.usenodeforeachfn.md) | | Parameters<Watcher<T, DomProxyBefore, DomProxyAfter>['useNodeForeach']>[0] | null
| Saved useNodeForeach |
+| [watcherCallback](./kit.watcher.watchercallback.md) | | (deadline?: Deadline | undefined) => void
| Should be called every watch |
+| [watching](./kit.watcher.watching.md) | | boolean
| |
+
+## Methods
+
+| Method | Modifiers | Description |
+| --- | --- | --- |
+| [addListener(event, fn)](./kit.watcher.addlistener.md) | | |
+| [addListener(event, fn)](./kit.watcher.addlistener_1.md) | | |
+| [addListener(event, fn)](./kit.watcher.addlistener_2.md) | | |
+| [assignKeys(assigner, comparer)](./kit.watcher.assignkeys.md) | | To help identify same nodes in different iteration, you need to implement a map function that map node
to key
If the key is changed, the same node will call through forEachRemove
then forEach
|
+| [emit(event, data)](./kit.watcher.emit.md) | | |
+| [emit(event, data)](./kit.watcher.emit_1.md) | | |
+| [emit(event, data)](./kit.watcher.emit_2.md) | | |
+| [getVirtualNodeByKey(key)](./kit.watcher.getvirtualnodebykey.md) | | Get virtual node by key. Virtual node will be unavailable if it is deleted |
+| [keyComparer(a, b)](./kit.watcher.keycomparer.md) | | Compare between key
and key
, in case of you don't want the default behavior |
+| [mapNodeToKey(node, index, arr)](./kit.watcher.mapnodetokey.md) | | Map Node -> Key
, in case of you don't want the default behavior |
+| [omitWarningForRepeatedKeys()](./kit.watcher.omitwarningforrepeatedkeys.md) | | If you're expecting repeating keys, call this function, this will omit the warning. |
+| [once()](./kit.watcher.once.md) | | Run the Watcher once. Once it emit data, stop watching. |
+| [once(fn)](./kit.watcher.once_1.md) | | |
+| [removeListener(event, fn)](./kit.watcher.removelistener.md) | | |
+| [removeListener(event, fn)](./kit.watcher.removelistener_1.md) | | |
+| [removeListener(event, fn)](./kit.watcher.removelistener_2.md) | | |
+| [requestIdleCallback(fn, timeout)](./kit.watcher.requestidlecallback.md) | | Is the watcher running |
+| [setDomProxyOption(option)](./kit.watcher.setdomproxyoption.md) | | Set option for DomProxy |
+| [startWatch(args)](./kit.watcher.startwatch.md) | | |
+| [stopWatch(args)](./kit.watcher.stopwatch.md) | | |
+| [useNodeForeach(fn)](./kit.watcher.usenodeforeach.md) | | Just like React hooks. Provide callbacks for each node changes. |
+
diff --git a/api-documents/kit.watcher.omitwarningforrepeatedkeys.md b/api-documents/kit.watcher.omitwarningforrepeatedkeys.md
new file mode 100644
index 0000000..c7e3c6b
--- /dev/null
+++ b/api-documents/kit.watcher.omitwarningforrepeatedkeys.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [omitWarningForRepeatedKeys](./kit.watcher.omitwarningforrepeatedkeys.md)
+
+## Watcher.omitWarningForRepeatedKeys() method
+
+If you're expecting repeating keys, call this function, this will omit the warning.
+
+Signature:
+
+```typescript
+omitWarningForRepeatedKeys(): this;
+```
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.watcher.once.md b/api-documents/kit.watcher.once.md
new file mode 100644
index 0000000..1ec941d
--- /dev/null
+++ b/api-documents/kit.watcher.once.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [once](./kit.watcher.once.md)
+
+## Watcher.once() method
+
+Run the Watcher once. Once it emit data, stop watching.
+
+Signature:
+
+```typescript
+once(): Promise;
+```
+Returns:
+
+`Promise`
+
diff --git a/api-documents/kit.watcher.once_1.md b/api-documents/kit.watcher.once_1.md
new file mode 100644
index 0000000..32be6d8
--- /dev/null
+++ b/api-documents/kit.watcher.once_1.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [once](./kit.watcher.once_1.md)
+
+## Watcher.once() method
+
+Signature:
+
+```typescript
+once(fn: (data: T) => PromiseLike | Result): Promise;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| fn | (data: T) => PromiseLike<Result> | Result
| |
+
+Returns:
+
+`Promise`
+
diff --git a/api-documents/kit.watcher.removelistener.md b/api-documents/kit.watcher.removelistener.md
new file mode 100644
index 0000000..608e492
--- /dev/null
+++ b/api-documents/kit.watcher.removelistener.md
@@ -0,0 +1,28 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [removeListener](./kit.watcher.removelistener.md)
+
+## Watcher.removeListener() method
+
+Signature:
+
+```typescript
+removeListener(event: 'onChange', fn: EventCallback<{
+ oldNode: T;
+ newNode: T;
+ oldKey: unknown;
+ newKey: unknown;
+ }[]>): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| event | 'onChange'
| |
+| fn | EventCallback<{
oldNode: T;
newNode: T;
oldKey: unknown;
newKey: unknown;
}[]>
| |
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.watcher.removelistener_1.md b/api-documents/kit.watcher.removelistener_1.md
new file mode 100644
index 0000000..b78a81c
--- /dev/null
+++ b/api-documents/kit.watcher.removelistener_1.md
@@ -0,0 +1,23 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [removeListener](./kit.watcher.removelistener_1.md)
+
+## Watcher.removeListener() method
+
+Signature:
+
+```typescript
+removeListener(event: 'onChangeFull', fn: EventCallback): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| event | 'onChangeFull'
| |
+| fn | EventCallback<T[]>
| |
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.watcher.removelistener_2.md b/api-documents/kit.watcher.removelistener_2.md
new file mode 100644
index 0000000..e800f4c
--- /dev/null
+++ b/api-documents/kit.watcher.removelistener_2.md
@@ -0,0 +1,26 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [removeListener](./kit.watcher.removelistener_2.md)
+
+## Watcher.removeListener() method
+
+Signature:
+
+```typescript
+removeListener(event: 'onRemove' | 'onAdd', fn: EventCallback<{
+ node: T;
+ key: unknown;
+ }[]>): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| event | 'onRemove' | 'onAdd'
| |
+| fn | EventCallback<{
node: T;
key: unknown;
}[]>
| |
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.watcher.requestidlecallback.md b/api-documents/kit.watcher.requestidlecallback.md
new file mode 100644
index 0000000..35b0c2f
--- /dev/null
+++ b/api-documents/kit.watcher.requestidlecallback.md
@@ -0,0 +1,27 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [requestIdleCallback](./kit.watcher.requestidlecallback.md)
+
+## Watcher.requestIdleCallback() method
+
+Is the watcher running
+
+Signature:
+
+```typescript
+protected requestIdleCallback(fn: (t: Deadline) => void, timeout?: {
+ timeout: number;
+ }): NodeJS.Timeout;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| fn | (t: Deadline) => void
| |
+| timeout | {
timeout: number;
}
| |
+
+Returns:
+
+`NodeJS.Timeout`
+
diff --git a/api-documents/kit.watcher.setdomproxyoption.md b/api-documents/kit.watcher.setdomproxyoption.md
new file mode 100644
index 0000000..942de16
--- /dev/null
+++ b/api-documents/kit.watcher.setdomproxyoption.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [setDomProxyOption](./kit.watcher.setdomproxyoption.md)
+
+## Watcher.setDomProxyOption() method
+
+Set option for DomProxy
+
+Signature:
+
+```typescript
+setDomProxyOption(option: Partial>): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| option | Partial<DomProxyOptions<DomProxyBefore, DomProxyAfter>>
| DomProxy options |
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.watcher.startwatch.md b/api-documents/kit.watcher.startwatch.md
new file mode 100644
index 0000000..bd84399
--- /dev/null
+++ b/api-documents/kit.watcher.startwatch.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [startWatch](./kit.watcher.startwatch.md)
+
+## Watcher.startWatch() method
+
+Signature:
+
+```typescript
+abstract startWatch(...args: any[]): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| args | any[]
| |
+
+Returns:
+
+`this`
+
diff --git a/api-documents/kit.watcher.stopwatch.md b/api-documents/kit.watcher.stopwatch.md
new file mode 100644
index 0000000..eec5f6d
--- /dev/null
+++ b/api-documents/kit.watcher.stopwatch.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [stopWatch](./kit.watcher.stopwatch.md)
+
+## Watcher.stopWatch() method
+
+Signature:
+
+```typescript
+stopWatch(...args: any[]): void;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| args | any[]
| |
+
+Returns:
+
+`void`
+
diff --git a/api-documents/kit.watcher.usenodeforeach.md b/api-documents/kit.watcher.usenodeforeach.md
new file mode 100644
index 0000000..3039cf1
--- /dev/null
+++ b/api-documents/kit.watcher.usenodeforeach.md
@@ -0,0 +1,40 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [useNodeForeach](./kit.watcher.usenodeforeach.md)
+
+## Watcher.useNodeForeach() method
+
+Just like React hooks. Provide callbacks for each node changes.
+
+Signature:
+
+```typescript
+useNodeForeach(fn: RequireElement, DomProxyBefore, DomProxyAfter>, key: unknown, realNode: T) => useNodeForeachReturns>): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| fn | RequireElement<T, (virtualNode: DomProxy<ElementLikeT<T>, DomProxyBefore, DomProxyAfter>, key: unknown, realNode: T) => useNodeForeachReturns<T>>
| You can return a set of functions that will be called on changes. |
+
+Returns:
+
+`this`
+
+## Remarks
+
+Return value of `fn`
+
+- `void`: No-op
+
+- `((oldNode: T) => void)`: it will be called when the node is removed.
+
+- `{ onRemove?: (old: T) => void; onTargetChanged?: (oldNode: T, newNode: T) => void; onNodeMutation?: (node: T) => void }`,
+
+- - `onRemove` will be called when node is removed.
+
+- - `onTargetChanged` will be called when the node is still existing but target has changed.
+
+- - `onNodeMutation` will be called when the node is the same, but it inner content or attributes are modified.
+
diff --git a/api-documents/kit.watcher.usenodeforeachfn.md b/api-documents/kit.watcher.usenodeforeachfn.md
new file mode 100644
index 0000000..d9871d1
--- /dev/null
+++ b/api-documents/kit.watcher.usenodeforeachfn.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [useNodeForeachFn](./kit.watcher.usenodeforeachfn.md)
+
+## Watcher.useNodeForeachFn property
+
+Saved useNodeForeach
+
+Signature:
+
+```typescript
+protected useNodeForeachFn: Parameters['useNodeForeach']>[0] | null;
+```
diff --git a/api-documents/kit.watcher.watchercallback.md b/api-documents/kit.watcher.watchercallback.md
new file mode 100644
index 0000000..27009ea
--- /dev/null
+++ b/api-documents/kit.watcher.watchercallback.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [watcherCallback](./kit.watcher.watchercallback.md)
+
+## Watcher.watcherCallback property
+
+Should be called every watch
+
+Signature:
+
+```typescript
+protected watcherCallback: (deadline?: Deadline | undefined) => void;
+```
diff --git a/api-documents/kit.watcher.watching.md b/api-documents/kit.watcher.watching.md
new file mode 100644
index 0000000..414ad8f
--- /dev/null
+++ b/api-documents/kit.watcher.watching.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [Watcher](./kit.watcher.md) > [watching](./kit.watcher.watching.md)
+
+## Watcher.watching property
+
+Signature:
+
+```typescript
+protected watching: boolean;
+```
diff --git a/api-extractor.json b/api-extractor.json
new file mode 100644
index 0000000..b2d5de1
--- /dev/null
+++ b/api-extractor.json
@@ -0,0 +1,349 @@
+/**
+ * Config file for API Extractor. For more info, please visit: https://api-extractor.com
+ */
+{
+ "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
+
+ /**
+ * Optionally specifies another JSON config file that this file extends from. This provides a way for
+ * standard settings to be shared across multiple projects.
+ *
+ * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains
+ * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be
+ * resolved using NodeJS require().
+ *
+ * SUPPORTED TOKENS: none
+ * DEFAULT VALUE: ""
+ */
+ // "extends": "./shared/api-extractor-base.json"
+ // "extends": "my-package/include/api-extractor-base.json"
+
+ /**
+ * Determines the "" token that can be used with other config file settings. The project folder
+ * typically contains the tsconfig.json and package.json config files, but the path is user-defined.
+ *
+ * The path is resolved relative to the folder of the config file that contains the setting.
+ *
+ * The default value for "projectFolder" is the token "", which means the folder is determined by traversing
+ * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder
+ * that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error
+ * will be reported.
+ *
+ * SUPPORTED TOKENS:
+ * DEFAULT VALUE: ""
+ */
+ // "projectFolder": "..",
+
+ /**
+ * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor
+ * analyzes the symbols exported by this module.
+ *
+ * The file extension must be ".d.ts" and not ".ts".
+ *
+ * The path is resolved relative to the folder of the config file that contains the setting; to change this,
+ * prepend a folder token such as "".
+ *
+ * SUPPORTED TOKENS: , ,
+ */
+ "mainEntryPointFilePath": "/es/index.d.ts",
+
+ /**
+ * Determines how the TypeScript compiler engine will be invoked by API Extractor.
+ */
+ "compiler": {
+ /**
+ * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.
+ *
+ * The path is resolved relative to the folder of the config file that contains the setting; to change this,
+ * prepend a folder token such as "".
+ *
+ * Note: This setting will be ignored if "overrideTsconfig" is used.
+ *
+ * SUPPORTED TOKENS: , ,
+ * DEFAULT VALUE: "/tsconfig.json"
+ */
+ // "tsconfigFilePath": "/tsconfig.json",
+ /**
+ * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.
+ * The object must conform to the TypeScript tsconfig schema:
+ *
+ * http://json.schemastore.org/tsconfig
+ *
+ * If omitted, then the tsconfig.json file will be read from the "projectFolder".
+ *
+ * DEFAULT VALUE: no overrideTsconfig section
+ */
+ // "overrideTsconfig": {
+ // . . .
+ // }
+ /**
+ * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended
+ * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when
+ * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses
+ * for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.
+ *
+ * DEFAULT VALUE: false
+ */
+ // "skipLibCheck": true,
+ },
+
+ /**
+ * Configures how the API report file (*.api.md) will be generated.
+ */
+ "apiReport": {
+ /**
+ * (REQUIRED) Whether to generate an API report.
+ */
+ "enabled": false
+
+ /**
+ * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce
+ * a full file path.
+ *
+ * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/".
+ *
+ * SUPPORTED TOKENS: ,
+ * DEFAULT VALUE: ".api.md"
+ */
+ // "reportFileName": ".api.md",
+
+ /**
+ * Specifies the folder where the API report file is written. The file name portion is determined by
+ * the "reportFileName" setting.
+ *
+ * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy,
+ * e.g. for an API review.
+ *
+ * The path is resolved relative to the folder of the config file that contains the setting; to change this,
+ * prepend a folder token such as "".
+ *
+ * SUPPORTED TOKENS: , ,
+ * DEFAULT VALUE: "/etc/"
+ */
+ // "reportFolder": "/etc/",
+
+ /**
+ * Specifies the folder where the temporary report file is written. The file name portion is determined by
+ * the "reportFileName" setting.
+ *
+ * After the temporary file is written to disk, it is compared with the file in the "reportFolder".
+ * If they are different, a production build will fail.
+ *
+ * The path is resolved relative to the folder of the config file that contains the setting; to change this,
+ * prepend a folder token such as "".
+ *
+ * SUPPORTED TOKENS: , ,
+ * DEFAULT VALUE: "/temp/"
+ */
+ // "reportTempFolder": "/temp/"
+ },
+
+ /**
+ * Configures how the doc model file (*.api.json) will be generated.
+ */
+ "docModel": {
+ /**
+ * (REQUIRED) Whether to generate a doc model file.
+ */
+ "enabled": true
+
+ /**
+ * The output path for the doc model file. The file extension should be ".api.json".
+ *
+ * The path is resolved relative to the folder of the config file that contains the setting; to change this,
+ * prepend a folder token such as "".
+ *
+ * SUPPORTED TOKENS: , ,
+ * DEFAULT VALUE: "/temp/.api.json"
+ */
+ // "apiJsonFilePath": "/temp/.api.json"
+ },
+
+ /**
+ * Configures how the .d.ts rollup file will be generated.
+ */
+ "dtsRollup": {
+ /**
+ * (REQUIRED) Whether to generate the .d.ts rollup file.
+ */
+ "enabled": false
+
+ /**
+ * Specifies the output path for a .d.ts rollup file to be generated without any trimming.
+ * This file will include all declarations that are exported by the main entry point.
+ *
+ * If the path is an empty string, then this file will not be written.
+ *
+ * The path is resolved relative to the folder of the config file that contains the setting; to change this,
+ * prepend a folder token such as "".
+ *
+ * SUPPORTED TOKENS: , ,
+ * DEFAULT VALUE: "/dist/.d.ts"
+ */
+ // "untrimmedFilePath": "/dist/.d.ts",
+
+ /**
+ * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release.
+ * This file will include only declarations that are marked as "@public" or "@beta".
+ *
+ * The path is resolved relative to the folder of the config file that contains the setting; to change this,
+ * prepend a folder token such as "".
+ *
+ * SUPPORTED TOKENS: , ,
+ * DEFAULT VALUE: ""
+ */
+ // "betaTrimmedFilePath": "/dist/-beta.d.ts",
+
+ /**
+ * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release.
+ * This file will include only declarations that are marked as "@public".
+ *
+ * If the path is an empty string, then this file will not be written.
+ *
+ * The path is resolved relative to the folder of the config file that contains the setting; to change this,
+ * prepend a folder token such as "".
+ *
+ * SUPPORTED TOKENS: , ,
+ * DEFAULT VALUE: ""
+ */
+ // "publicTrimmedFilePath": "/dist/-public.d.ts",
+
+ /**
+ * When a declaration is trimmed, by default it will be replaced by a code comment such as
+ * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the
+ * declaration completely.
+ *
+ * DEFAULT VALUE: false
+ */
+ // "omitTrimmingComments": true
+ },
+
+ /**
+ * Configures how the tsdoc-metadata.json file will be generated.
+ */
+ "tsdocMetadata": {
+ /**
+ * Whether to generate the tsdoc-metadata.json file.
+ *
+ * DEFAULT VALUE: true
+ */
+ // "enabled": true,
+ /**
+ * Specifies where the TSDoc metadata file should be written.
+ *
+ * The path is resolved relative to the folder of the config file that contains the setting; to change this,
+ * prepend a folder token such as "".
+ *
+ * The default value is "", which causes the path to be automatically inferred from the "tsdocMetadata",
+ * "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup
+ * falls back to "tsdoc-metadata.json" in the package folder.
+ *
+ * SUPPORTED TOKENS: , ,
+ * DEFAULT VALUE: ""
+ */
+ // "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json"
+ },
+
+ /**
+ * Configures how API Extractor reports error and warning messages produced during analysis.
+ *
+ * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages.
+ */
+ "messages": {
+ /**
+ * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing
+ * the input .d.ts files.
+ *
+ * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551"
+ *
+ * DEFAULT VALUE: A single "default" entry with logLevel=warning.
+ */
+ "compilerMessageReporting": {
+ /**
+ * Configures the default routing for messages that don't match an explicit rule in this table.
+ */
+ "default": {
+ /**
+ * Specifies whether the message should be written to the the tool's output log. Note that
+ * the "addToApiReportFile" property may supersede this option.
+ *
+ * Possible values: "error", "warning", "none"
+ *
+ * Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail
+ * and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes
+ * the "--local" option), the warning is displayed but the build will not fail.
+ *
+ * DEFAULT VALUE: "warning"
+ */
+ "logLevel": "warning"
+
+ /**
+ * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md),
+ * then the message will be written inside that file; otherwise, the message is instead logged according to
+ * the "logLevel" option.
+ *
+ * DEFAULT VALUE: false
+ */
+ // "addToApiReportFile": false
+ }
+
+ // "TS2551": {
+ // "logLevel": "warning",
+ // "addToApiReportFile": true
+ // },
+ //
+ // . . .
+ },
+
+ /**
+ * Configures handling of messages reported by API Extractor during its analysis.
+ *
+ * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag"
+ *
+ * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings
+ */
+ "extractorMessageReporting": {
+ "default": {
+ "logLevel": "warning"
+ // "addToApiReportFile": false
+ },
+ "ae-forgotten-export": {
+ "logLevel": "none"
+ },
+ "ae-incompatible-release-tags": {
+ "logLevel": "none"
+ },
+ "ae-missing-release-tag": {
+ "logLevel": "none"
+ }
+
+ // "ae-extra-release-tag": {
+ // "logLevel": "warning",
+ // "addToApiReportFile": true
+ // },
+ //
+ // . . .
+ },
+
+ /**
+ * Configures handling of messages reported by the TSDoc parser when analyzing code comments.
+ *
+ * TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text"
+ *
+ * DEFAULT VALUE: A single "default" entry with logLevel=warning.
+ */
+ "tsdocMessageReporting": {
+ "default": {
+ "logLevel": "warning"
+ // "addToApiReportFile": false
+ }
+
+ // "tsdoc-link-tag-unescaped-text": {
+ // "logLevel": "warning",
+ // "addToApiReportFile": true
+ // },
+ //
+ // . . .
+ }
+ }
+}
diff --git a/doc/en/DOM.md b/doc/en/DOM.md
index f91a419..fb62570 100644
--- a/doc/en/DOM.md
+++ b/doc/en/DOM.md
@@ -15,7 +15,7 @@ It will automatically refresh, just like today's PWAs.
You want to add price in USD after every ticket.
-```typescript
+```ts
import { LiveSelector, MutationObserverWatcher } from '@holoflows/kit/DOM'
const price = new LiveSelector()
@@ -139,418 +139,3 @@ A complete `useNodeForeach` call is like this:
Tutorial is over.
-
-# Documentation
-
-## class LiveSelector
-
-All methods except `evaluateOnce()` can be chained.
-
-```ts
-const ls = new LiveSelector()
-```
-
-> Typescript: `LiveSelector` have a generic `` to tell you the current type.
-
-### `.querySelector(selector)`
-
-Same as [document.querySelector](https://mdn.io/document.querySelector), add element to the list when evaluating.
-
-```typescript
-ls.querySelector('div#root').querySelector('.nav')
-```
-
-**Warn: Example above is union of `div#root` and `.nav`, is NOT `div#root .nav`**
-
-> Typescript: Generic is the same as `document.querySelector`
-
-> Typescript: For complex CSS selector, you need to specify it manually. Or you will get type `Element`. `.querySelector('div > div')`
-
-### `.querySelectorAll(selector)`
-
-Same as [document.querySelectorAll](https://mdn.io/document.querySelectorAll), add elements to the list when evaluating.
-
-```typescript
-ls.querySelectorAll('div').querySelectorAll('h1')
-```
-
-**Warn: Example above is union of `div` and `h1`, is NOT `div h1`**
-
-> Typescript: Generic is the same as `document.querySelectorAll`
-
-> Typescript: For complex CSS selector, you need to specify it manually. Or you will get type `Element`. `.querySelectorAll('div > div')`
-
-### `.filter(callbackfn)`
-
-Like [Array#filter](https://mdn.io/Array.filter). Remove items you don't want.
-
-```ts
-ls.filter(x => x.innerText.match('hello'))
-```
-
-### `.map(callbackfn)`
-
-Like [Array#map](https://mdn.io/Array.map). Map an item to another.
-
-```ts
-ls.map(x => x.parentElement)
-```
-
-**Tips: You can map to anything you want!**
-
-### `.concat(newLS: LiveSelector)`
-
-Like [Array#concat](https://mdn.io/Array.concat). Concat the result of another `LiveSelector.evaluateOnce()` into the current list.
-
-```ts
-ls.concat(new LiveSelector().querySelector('#root'))
-```
-
-### `.reverse()`
-
-Like [Array#reverse](https://mdn.io/Array.reverse). Reverse the list.
-
-```ts
-ls.reverse()
-```
-
-### `.slice(start?, end?)`
-
-Like [Array#slice](https://mdn.io/Array.slice). Cut the list.
-
-```ts
-ls.slice(2, 4)
-```
-
-### `.sort(compareFn)`
-
-Like [Array#sort](https://mdn.io/Array.sort). Sort the list.
-
-```ts
-ls.sort((a, b) => a.innerText.length - b.innerText.length)
-```
-
-### `.flat()`
-
-Like [Array#flat](https://mdn.io/Array.flat). Flatten the list.
-
-**Notice: Not recursively flating the list**
-
-```ts
-ls.flat()
-```
-
-### `.nth(n: number)`
-
-Remove anything except nth element.
-
-```ts
-ls.nth(-1)
-```
-
-### `.replace(f: (list: T[]) => NextT[])`
-
-If you think methods above is not enought, you can replace the list directly when evaluating.
-
-```ts
-ls.replace(x => lodash.dropRight(x, 2))
-```
-
-### `.evaluateOnce()`
-
-Evaluate. This should be the last method to be called.
-
-```ts
-ls.evaluateOnce()
-```
-
-## Watchers
-
-Every `Watcher` extends from abstract class [Watcher](#abstract-class-Watcher-public)。
-
-### abstract class Watcher (public)
-
-Extends [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
-
-#### `constructor (liveSelector)`
-
-Create a new `Watcher`。
-
-- liveSelector: `LiveSelector`, LiveSelector to watch
-
-> Typescript: Generic `T` equals to generic of the `LiveSelector` passed in.
-
-#### abstract `.startWatch(?): this`
-
-Start watching.
-
-#### abstract `.stopWatch()`
-
-Stop watching.
-
-#### `.addListener(event, fn)`
-
-See [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter).
-Only these events are available.
-
-- onChange - When list updated, changed part
-- onChangeFull - When list updated, full list
-- onRemove - When list updated, removed part
-- onAdd - When list updated, added part
-
-#### `.firstVirtualNode`
-
-**Notice: T must be sub type of HTMLElement, or it will be type `never`.**
-
-A [DomProxy](#doc-domproxy), always points to the first result of `LiveSelector`.
-
-#### `.assignKeys(assigner, comparer?)`
-
-- assigner: assign a key for each element. Key can be anything.
- Defaults to `x => x`
-
-```ts
-assigner: (node: T, index: number, arr: T[]) => Q
-// node: node that needs a key
-// index: current index
-// arr: whole array
-```
-
-- comparer: If your key can't be compared by `===`, provide a comparer.
- Defaults to `(a, b) => a === b`
-
-```ts
-comparer: (a: Q, b: Q) => boolean
-// a: returned by assigner
-// b: returned by assigner
-```
-
-#### `.useNodeForEach(fn)`
-
-**Notice: T must be sub type of HTMLElement, or it will be type `never`.**
-
-Everytime that a new item is added to the list, it will be called.
-
-##### fn and it's return value
-
-```ts
-(fn: (node: DomProxy, key: Q, realNode: HTMLElement) => ...)
-// node: a DomProxy
-// key: returned from assigner
-// realNode: real node after DomProxy
-```
-
-- undefined: nothing will happen
-- A function: `(oldNode: T) => void`, when `key` is gone, it will be called
-- An object: `{ onRemove?: (old: T) => void; onTargetChanged?: (oldNode: T, newNode: T) => void; onNodeMutation?: (node: T) => void }`
-- - `onRemove(oldNode: T) => void`, when key is gone, it will be called
-- - `onTargetChanged(oldNode: T, newNode: T) => void`, when `key` is still exist but `realNode` has changed, it will be called.
-- - `onNodeMutation: (node: T) => void`, when `key` and `realCurrent` is not changed, but there are some mutations inside the `realCurrent`, it will be called.
-
-#### `.getVirtualNodeByKey(key)`
-
-**Notice: T must be sub type of HTMLElement, or it will be type `never`.**
-
-- key: Q. Find [DomProxy](#doc-domproxy) by `key`
-
-### MutationObserverWatcher
-
-#### `constructor (liveSelector, consistentWatchRoot = document.body)`
-
-Create a new `MutationObserverWatcher`。
-
-It will listen on `consistentWatchRoot`. If any changes happened, it will do a check.
-
-> At most 1 query every requestAnimateFrame. Don't worry
-
-- liveSelector: `LiveSelector`, LiveSelector to watch
-- consistentWatchRoot: `Element | Document`, it should be consistent (if it is deleted, watcher will not work.). Defaults to `document.body`, if you think `MutationObserverWatcher` cause some performance problem, use this.
-
-#### `startWatch(options?: MutationObserverInit)`
-
-Start watching.
-
-- options: `MutationObserverInit`, you can remove some options by yourself. See: [MutationObserver](https://mdn.io/MutationObserver)
-
-### IntervalWatcher
-
-Check when time passed.
-
-#### `.startWatch(interval)`
-
-Start watching.
-
-- options: `numebr`, check it at `options`ms
-
-### EventWatcher
-
-Check when you want.
-
-#### `.startWatch()`
-
-Start watching.
-
-#### `.eventListener()`
-
-Event listener.
-Usage:
-
-```ts
-ele.addEventListener('click', watcher.eventListener)
-```
-
-### ValueRef
-
-ValueRef is not related to `Watcher`. It listen to `.value =`. e.g.:
-
-```ts
-const ref = new ValueRef(0)
-ref.value // 0
-ref.addListener((newVal, old) => console.log(newVal, old))
-ref.value = 1
-// Log: 1, 0
-ref.value // 1
-```
-
-#### `constructor(value: T)`
-
-- value: Initial value
-
-#### `.value`
-
-Current value. If you assign it, then it will emit event.
-
-#### `.removeListener(fn: (newValue: T, oldValue: T) => void): void`
-
-Remove listener.
-
-#### abstract class Watcher (protected)
-
-Here are `protected` fields and methods in the `Watcher` class. If you are not extending it, you don't need it.
-
-#### protected readonly `.nodeWatcher: MutationWatcherHelper`
-
-Used to invoke `onNodeMutation`
-
-`MutationWatcherHelper` is an un-exported internal class. Don't use it.
-
-#### protected `.watching: boolean`
-
-Is it watching now?
-
-If false, `.watcherCallback()` will do nothing.
-
-#### protected `.lastKeyList: unknown[]`
-
-Key list of last time.
-
-#### protected `.lastNodeList: T[]`
-
-Element list of last time.
-
-#### protected `.lastCallbackMap: Map>`
-
-All living return functions(like `onRemove` `onNodeMutation`)
-
-#### protected `.lastVirtualNodesMap: Map`
-
-All living DomProxy
-
-#### protected `.findNodeFromListByKey(list: T[], keys: unknown: []): (key: unknown) => T | null`
-
-A high order function. Find key in the list.
-
-```ts
-.findNodeFromListByKey(this.lastNodeList, this.lastKeyList)(key)
-```
-
-#### protected `.watcherCallback()`
-
-Core of watcher. If you want to do a check, call it.
-
-It does:
-
-- Call `LiveSelector.evaluateOnce()`
-- Call `assignKeys` to get `key`s
-
-- For deleted nodes, call `onRemove`
-- For new nodes, call `useNodeForeachFn()`
-- For changed nodes, call `onTargetChanged()`
-- Set `lastCallbackMap` `lastVirtualNodesMap` `lastKeyList` `lastNodeList`
-- Emit `onChangeFull` `onChange` `onRemove` `onAdd`
-- Bind `.firstVirtualNode.realCurrent` to new value.
-
-#### protected `.mapNodeToKey(node: T, index: number: arr: T[]): unknown`
-
-map node to key (can be overwrited by `assignKeys`)
-
-#### protected `.keyComparer(a: unknown, b: unknown): boolean`
-
-check if `a` and `b` are equal (can be overwrited by `assignKeys`)
-
-#### protected `.useNodeForeachFn(...): ...`
-
-See [.useNodeForeach](#doc-watcher-usenodeforeach-fn)
-
-## DomProxy
-
-DomProxy provide an interface that be stable even dom is changed.
-
-Return this object
-
-### `.before`
-
-A span element, always at before of [realCurrent](#doc-domproxy-realCurrent)
-
-### `.current`
-
-A fake HTML, all operations on it will be forwarded to [realCurrent](#doc-domproxy-realCurrent). After `realCurrent` changes, some of effects will be move to the new target.
-
-### `.after`
-
-A span element, alwyas at after of [realCurrent](#doc-domproxy-realCurrent)
-
-### `.realCurrent`
-
-The real current. If you change it, [after](#doc-domproxy-after), [current](#doc-domproxy-current), [before](#doc-domproxy-before) will be affected too.
-
-### `.destroy()`
-
-Destroy the DomProxy.
-
-### DOMProxy behavior
-
-**Notice, only changes happened on current will be forwarded.**
-
-- forward: forward to the current`realCurrent`
-- undo: If `realCurrent` changed, effect will be undoed.
-- move: If `realCurrent` changed, effect will be moved.
-
-| Attributes | forward | undo | move |
-| ---------------- | ------- | ---- | ---- |
-| style | Yes | No | Yes |
-| addEventListener | Yes | Yes | Yes |
-| appendChild | Yes | Yes | Yes |
-| ...default | Yes | No | No |
-
-This means, if you change `current.style.opacity`, then change `realCurrent`, new `realCurrent` will set `current.style.opacity` automatically.
-
-**We will add more behavior later. If you need something, issues or pull requests wellcome!**
diff --git a/doc/en/Extension.md b/doc/en/Extension.md
deleted file mode 100644
index 1a9bd28..0000000
--- a/doc/en/Extension.md
+++ /dev/null
@@ -1,159 +0,0 @@
-# @holoflows/kit/Extension/
-
-Some tools that useful in extension developing
-
-# class MessageCenter
-
-A class that can help you to send messages in different context.
-
-> Typescript: Messages are typed!
-
-```ts
-interface AllEvents {
- event1: { x: number; y: number }
-}
-const mc = new MessageCenter()
-mc.on // Can only listen to keyof AllEvents
-mc.send // Can only send event of keyof AllEvents and data need to be type AllEvents[key]
-```
-
-## `constructor(key?: string)`
-
-- key?: Whatever, but need to be same in all instances.
-
-## `.on(event, handler)`
-
-Listen to event
-
-## `.on(event, data)`
-
-Send event
-
-## `.writeToConsole`
-
-Log to console when receive/send event
-
-# AsyncCall
-
-Async call between different context.
-
-A High level abstraction of MessageCenter.
-
-> Shared code
-
-- How to stringify/parse parameters/returns should be shared, defaults to NoSerialization.
-- `key` should be shared.
-
-> One side
-
-- Should provide some functions then export its type (for example, `BackgroundCalls`)
-- `const call = AsyncCall(backgroundCalls)`
-- Then you can `call` any method on `ForegroundCalls`
-
-> Other side
-
-- Should provide some functions then export its type (for example, `ForegroundCalls`)
-- `const call = AsyncCall(foregroundCalls)`
-- Then you can `call` any method on `BackgroundCalls`
-
-_Note: Two sides can implement the same function_
-
-Example:
-
-```typescript
-// Mono repo
-// On UI
-const UI = {
- async dialog(text: string) {
- alert(text)
- },
-}
-export type UI = typeof UI
-const callsClient = AsyncCall(UI)
-callsClient.sendMail('hello world', 'what')
-
-// On server
-const Server = {
- async sendMail(text: string, to: string) {
- return true
- },
-}
-export type Server = typeof Server
-const calls = AsyncCall(Server)
-calls.dialog('hello')
-```
-
-## Options
-
-- key: A key to prevent collision with other AsyncCalls. Can be anything, but need to be the same on the both side. (Defaults to `default`)
-- serializer: How to serialization and deserialization parameters and return values (Defaults to `NoSerialization`)
-- MessageCenter: A class that can let you transfer messages between two sides (Defaults to `MessageCenter` of @holoflows/kit)
-- dontThrowOnNotImplemented: If this side receive messages that we didn't implemented, throw an error (Defaults to `true`)
-- writeToConsole: Write all calls to console. (Defaults to `true`)
-
-## Serializer:
-
-We offer some built-in serializer:
-
-- `NoSerialization` (Do not do any serialization)
-- `JSONSerialization` (Use JSON.parse/stringify) (You can provide a `replacer`! See [JSON.stringify](https://mdn.io/JSON.stringify))
-
-You can also build your own serializer by implement interface `Serialization`
-
-## Return:
-
-`typeof` the type parameter. (``)
-
-# AutomatedTabTask
-
-Based on AsyncCall. Open a new page in the background, execute some task, then close it automatically.
-
-Usage:
-
-> In content script: (You must run this in the page you wanted to run task in!)
-
-```ts
-export const task = AutomatedTabTask({
- async taskA() {
- return 'Done!'
- },
-})
-```
-
-> In background script:
-
-```ts
-import { task } from '...'
-task('https://example.com/').taskA()
-// Open https://example.com/ then run taskA() on that page, which will return 'Done!'
-```
-
-## Parameters:
-
-- taskImplements: All tasks that background page can call.
-- AsyncCallKey: A unique key, defaults to a extension specific url.
-
-## Return:
-
-- `null` on content script
-- `typeof taskImplements` on background page
-
-# Contexts
-
-Identify the current running context
-
-## type `Contexts`
-
-- background: background page
-- content: content script
-- unknown: unknown
-
-## `GetContext():`Contexts
-
-Get current context
-
-## `OnlyRunInContext`(context: Contexts | Contexts[], name: string)
-
-Check if the current context is the wanted context, if not, throws.
-
-- `name` is the name while you throw
diff --git a/doc/en/index.md b/doc/en/index.md
index a122b95..3f7a300 100644
--- a/doc/en/index.md
+++ b/doc/en/index.md
@@ -4,10 +4,9 @@ A toolkit for browser extension developing.
## Components
-@holoflows/kit 由以下部分组成
+See [API documents](../../api-documents/kit.md)
-- [DOM](./DOM.md) - Help developer to track changes in the content script
-- [Extension](./Extension.md) - Some tools that useful in extension developing
+See tutorial of [DOM watcher](./DOM.md)
## Installation
@@ -15,7 +14,10 @@ Use `yarn` or `npm`. Or use UMD.
> https://unpkg.com/@holoflows/kit@latest/dist/out.js
-使用模块加载器时,使用 `@holoflows/kit` 导入;使用 umd 时,使用 `window.HoloflowsKit`。
+If you're using module bundler, use `@holoflows/kit` to import;
+using umd, use `window.HoloflowsKit`.
+
+You need to load a polyfill for WebExtension in Chrome (`webextension-polyfill`)
### ECMAScript version
diff --git a/doc/zh-CN/DOM.md b/doc/zh-CN/DOM.md
index 9529e94..ed58e1c 100644
--- a/doc/zh-CN/DOM.md
+++ b/doc/zh-CN/DOM.md
@@ -2,8 +2,6 @@
提供了一组方便追踪被注入页面中内容变化的工具。
-只是来查阅文档的?跳过教程,直接跳转到 [文档](#doc) 吧
-
## 例子
@@ -13,7 +11,7 @@
假设被注入页面是由 React 生成的机票价格页面,它会动态刷新。你想在每张机票的价格后面加上它的美元价格。
-```typescript
+```ts
import { LiveSelector, MutationObserverWatcher } from '@holoflows/kit/DOM'
const price = new LiveSelector()
@@ -66,7 +64,7 @@ setTimeout(() => {
})
```
-关于 LiveSelector 的完整用法,参见 [LiveSelector 的文档](#doc-LiveSelector)。
+关于 LiveSelector 的完整用法,参见 [LiveSelector 的文档](../../api-documents/kit.liveselector.md)。
那么 `MutationObserverWatcher` 又是什么?
@@ -138,415 +136,3 @@ Watcher 有以下几种:
教程到这里就结束了,你可以回头看看最开始的例子。
-
-# 文档
-
-## class LiveSelector
-
-LiveSelector 上的方法,除了 `evaluateOnce()` 都可以链式调用。
-
-```ts
-const ls = new LiveSelector()
-```
-
-> Typescript: `LiveSelector` 每一次都有一个类型参数 `` 告诉你计算到这一步时它的类型。
-
-### `.querySelector(selector)`
-
-同 [document.querySelector](https://mdn.io/document.querySelector),计算时,将选中的元素加入列表。
-
-```typescript
-ls.querySelector('div#root').querySelector('.nav')
-```
-
-**注意:以上的例子等于 `div#root` 和 `.nav` 的并集,并不是 `div#root .nav` 的意思!**
-
-> Typescript: 这个函数的泛型与 `document.querySelector` 相同
-
-> Typescript: 对于复杂的 CSS 选择器,无法推断它的类型,你需要手动指定。`.querySelector('div > div')`
-
-### `.querySelectorAll(selector)`
-
-同 [document.querySelectorAll](https://mdn.io/document.querySelectorAll),计算时,将选中的元素加入列表。
-
-```typescript
-ls.querySelectorAll('div').querySelectorAll('h1')
-```
-
-**注意:以上的例子等于 `div` 和 `h1` 的并集,并不是 `div h1` 的意思!**
-
-> Typescript: 这个函数的泛型与 `document.querySelectorAll` 相同
-
-> Typescript: 对于复杂的 CSS 选择器,无法推断它的类型,你需要手动指定。`.querySelectorAll('div > div')`
-
-### `.filter(callbackfn)`
-
-与 [Array#filter](https://mdn.io/Array.filter) 类似。计算时,过滤掉列表中不符合的内容。
-
-```ts
-ls.filter(x => x.innerText.match('hello'))
-```
-
-### `.map(callbackfn)`
-
-与 [Array#map](https://mdn.io/Array.map) 类似。计算时,将列表中的每个元素映射为另一个元素。
-
-```ts
-ls.map(x => x.parentElement)
-```
-
-**提示:map 不只限于 map 到 Dom 元素,你可以 map 到任何东西**
-
-### `.concat(newLS: LiveSelector)`
-
-与 [Array#concat](https://mdn.io/Array.concat) 类似。计算时,将一个新的 `LiveSelector` 的计算结果合并进当前的计算结果。
-
-```ts
-ls.concat(new LiveSelector().querySelector('#root'))
-```
-
-### `.reverse()`
-
-与 [Array#reverse](https://mdn.io/Array.reverse) 类似。计算时,将列表反转。
-
-```ts
-ls.reverse()
-```
-
-### `.slice(start?, end?)`
-
-与 [Array#slice](https://mdn.io/Array.slice) 类似。计算时,截取列表的一部分。
-
-```ts
-ls.slice(2, 4)
-```
-
-### `.sort(compareFn)`
-
-与 [Array#sort](https://mdn.io/Array.sort) 类似。计算时,对列表排序。
-
-```ts
-ls.sort((a, b) => a.innerText.length - b.innerText.length)
-```
-
-### `.flat()`
-
-与 [Array#flat](https://mdn.io/Array.flat) 类似。计算时,将列表变平。
-
-**注意:这不是递归的操作!**
-
-```ts
-ls.flat()
-```
-
-### `.nth(n: number)`
-
-计算时,只保留第 N 个元素。
-
-```ts
-ls.nth(-1)
-```
-
-### `.replace(f: (list: T[]) => NextT[])`
-
-如果认为上面这些类 Array 的方法还不足以满足你的要求,你可以直接在计算时替换列表。
-
-```ts
-ls.replace(x => lodash.dropRight(x, 2))
-```
-
-### `.evaluateOnce()`
-
-执行一次计算。这应该是最后一个被调用的方法。每一次调用,它都会重新根据你之前所执行的 `querySelector` 等方法查询一次。
-
-```ts
-ls.evaluateOnce()
-```
-
-## Watchers
-
-所有 Watcher 都继承自抽象类 [Watcher](#abstract-class-Watcher-public)。
-
-### abstract class Watcher (public)
-
-继承自 [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
-
-#### `constructor (liveSelector)`
-
-创建一个新的 `Watcher`。
-
-- liveSelector: `LiveSelector`, 要监听的 LiveSelector
-
-> Typescript: 泛型 `T` 等于 LiveSelector 的泛型
-
-#### abstract `.startWatch(?): this`
-
-开始监听。参数请参见实现的说明。
-
-#### abstract `.stopWatch()`
-
-停止监听。
-
-#### `.addListener(event, fn)`
-
-见 [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)。
-仅提供以下事件:
-
-- onChange - 每次列表更新时,发生变化的部分
-- onChangeFull - 每次列表更新时,新的完整的列表
-- onRemove - 每次列表更新时,被删除的部分
-- onAdd - 每次列表更新时,被添加的部分
-
-#### `.firstVirtualNode`
-
-**注意:如果 T 不是 HTMLElement 的子类型,那么该对象不可用。**
-
-一个 [DomProxy](#doc-domproxy),始终指向 LiveSelector 的第一个元素
-
-#### `.assignKeys(assigner, comparer?)`
-
-- assigner: 为每个元素分配一个 key,key 可以是任何内容。
- 默认为 `x => x`
-
-```ts
-assigner: (node: T, index: number, arr: T[]) => Q
-// node: 需要被分配 key 的元素
-// index: 当前位置
-// arr: 整个数组
-```
-
-- comparer: 如果你的 key 不能用 `===` 来直接比较的话,用这个参数自定义一个比较方式。默认为 `(a, b) => a === b`
-
-```ts
-comparer: (a: Q, b: Q) => boolean
-// a: 一种 assigner 返回的对象
-// b: 另一种 assigner 返回的对象
-```
-
-#### `.useNodeForEach(fn)`
-
-**注意:如果 T 不是 HTMLElement 的子类型,那么该函数不可用。**
-
-列表里每添加一个新项目,会调用一次 fn。
-
-##### fn 与它的返回值:
-
-```ts
-(fn: (node: DomProxy, key: Q, realNode: HTMLElement) => ...)
-// node: 一个 DomProxy
-// key: assigner 返回的 key
-// realNode: node 所对应的真实 node
-```
-
-- undefined: 什么也不会发生
-- 一个函数: `(oldNode: T) => void`,当 `key` 在某一次迭代中从列表中消失了,该函数会被调用
-- 一个对象: `{ onRemove?: (old: T) => void; onTargetChanged?: (oldNode: T, newNode: T) => void; onNodeMutation?: (node: T) => void }`
-- - `onRemove(oldNode: T) => void` 当 `key` 在某一次迭代中从列表中消失了,该函数会被调用
-- - `onTargetChanged(oldNode: T, newNode: T) => void` 当 `key` 在两次迭代中依然存在,但它对应的元素不同时会调用
-- - `onNodeMutation: (node: T) => void` 当 `key` 和元素都没有变化,而是元素内部发生了变化时会调用。
-
-#### `.getVirtualNodeByKey(key)`
-
-**注意:如果 T 不是 HTMLElement 的子类型,那么该函数不可用。**
-
-- key: Q. 根据 key 寻找 key 对应的 [DomProxy](#doc-domproxy)
-
-### MutationObserverWatcher
-
-#### `constructor (liveSelector, consistentWatchRoot = document.body)`
-
-创建一个新的 `MutationObserverWatcher`。
-
-它会在 `consistentWatchRoot` 上发生任何变化时计算变化。
-
-> 每 requestAnimateFrame 最多查询一次,不会导致页面卡顿。
-
-- liveSelector: `LiveSelector`, 要监听的 LiveSelector
-- consistentWatchRoot: `Element | Document`, 保证稳定(不会被删除从而导致监听失效)的元素,默认为 `document.body`,如果你怀疑 `MutationObserverWatcher` 导致了性能问题,请提供这个参数缩小监听范围。
-
-#### `startWatch(options?: MutationObserverInit)`
-
-开始监听。
-
-- options: `MutationObserverInit`,你可以自行排除掉对某些修改事件的监听。(见: [MutationObserver](https://mdn.io/MutationObserver) )
-
-### IntervalWatcher
-
-通过时间流逝触发检查。
-
-#### `.startWatch(interval)`
-
-开始监听。
-
-- options: `numebr`,每隔多少毫秒检查一次。
-
-### EventWatcher
-
-手动触发检查。
-
-#### `.startWatch()`
-
-开始监听。
-
-#### `.eventListener()`
-
-事件监听器。
-用法:
-
-```ts
-ele.addEventListener('click', watcher.eventListener)
-```
-
-### ValueRef
-
-ValueRef 与 `Watcher` 无关,它监听 `.value =`。例如:
-
-```ts
-const ref = new ValueRef(0)
-ref.value // 0
-ref.addListener((newVal, old) => console.log(newVal, old))
-ref.value = 1
-// Log: 1, 0
-ref.value // 1
-```
-
-#### `constructor(value: T)`
-
-- value: 初始值。
-
-#### `.value`
-
-当前值。写入的话会触发事件。
-
-#### `.removeListener(fn: (newValue: T, oldValue: T) => void): void`
-
-取消监听器。
-
-#### abstract class Watcher (protected)
-
-这里 Watcher 的 protected 属性与方法。如果你不是在自己继承 `Watcher`,那么你用不到这里提到的属性和方法。
-
-#### protected readonly `.nodeWatcher: MutationWatcherHelper`
-
-用于触发 onNodeMutation 的 Watcher。
-
-`MutationWatcherHelper` 是内部类,没有导出。你不应该使用它。
-
-#### protected `.watching: boolean`
-
-当前是否正在监听。如果为 `false`,那么 `.watcherCallback()` 不会有反应。
-
-#### protected `.lastKeyList: unknown[]`
-
-上一次检查的 Key 列表。
-
-#### protected `.lastNodeList: T[]`
-
-上一次检查的元素列表。
-
-#### protected `.lastCallbackMap: Map>`
-
-所有还未销毁的 `useNodeForeach()` 所返回的函数(`onRemove` `onNodeMutation` 等)
-
-#### protected `.lastVirtualNodesMap: Map`
-
-所有还未销毁的 DomProxy
-
-#### protected `.findNodeFromListByKey(list: T[], keys: unknown: []): (key: unknown) => T | null`
-
-一个高阶函数。通过 key 在 list 中寻找元素。(因为元素可能是复杂的对象,不能直接比较。)
-
-```ts
-.findNodeFromListByKey(this.lastNodeList, this.lastKeyList)(key)
-```
-
-#### protected `.watcherCallback()`
-
-检查逻辑。当你需要触发检查时,调用它。
-
-它做了以下这些事情:
-
-- 调用 `LiveSelector` 的 `EvaluateOnce`
-- 通过 `assignKeys` 为每个元素设置 `key`
-
-- 寻找被删除的元素并调用 `onRemove`
-- 寻找新增的元素并调用 `useNodeForeachFn()`
-- 寻找 `key` 相同但变化了的元素并调用 `onTargetChanged()`
-- 重新设置 `lastCallbackMap` `lastVirtualNodesMap` `lastKeyList` `lastNodeList`
-- 发出 `onChangeFull` `onChange` `onRemove` `onAdd` 事件
-- 为 `.firstVirtualNode` 绑定新的 Node
-
-#### protected `.mapNodeToKey(node: T, index: number: arr: T[]): unknown`
-
-返回 node 对应的 key(可被 `assignKeys` 覆盖)
-
-#### protected `.keyComparer(a: unknown, b: unknown): boolean`
-
-返回 `a` 和 `b` 是否相等 (可被 `assignKeys` 覆盖)
-
-#### protected `.useNodeForeachFn(...): ...`
-
-见 [.useNodeForeach](#doc-watcher-usenodeforeach-fn)
-
-## DomProxy
-
-DomProxy 提供抽象的 Dom,其引用不随 Dom 变化而变化。
-
-调用后返回以下对象
-
-### `.before`
-
-一个 span 元素,始终位于 [realCurrent](#doc-domproxy-realCurrent) 前面
-
-### `.current`
-
-一个伪装的 HTML 元素,对其的操作会转发到 [realCurrent](#doc-domproxy-realCurrent),realCurrent 改变后,曾经的部分操作会被转发。
-
-### `.after`
-
-一个 span 元素,始终位于 [realCurrent](#doc-domproxy-realCurrent) 后面
-
-### `.realCurrent`
-
-真实的 current。修改的话会触发 [after](#doc-domproxy-after), [current](#doc-domproxy-current), [before](#doc-domproxy-before) 的修改。
-
-### `.destroy()`
-
-调用后该 DomProxy 不再可用。
-
-### DOMProxy 当前的转发策略
-
-**注意:只有通过 current 进行的修改才会被转发**
-
-- forward: 转发到当前的 `realCurrent`
-- undo: `realCurrent` 修改时被撤销
-- move: `realCurrent` 修改时移动到新的 `realCurrent` 上
-
-| 属性 | forward | undo | move |
-| ---------------- | ------- | ---- | ---- |
-| style | Yes | No | Yes |
-| addEventListener | Yes | Yes | Yes |
-| appendChild | Yes | Yes | Yes |
-| ...默认 | Yes | No | No |
-
-这意味着,你修改 `current.style.opacity`,在 `realCurrent` 被修改后,新的 `realCurrent` 也会自动修改 `current.style.opacity`
-
-**将来会添加更多转发策略,如有需要,欢迎到 issue 提出,或自己实现!**
diff --git a/doc/zh-CN/Extension.md b/doc/zh-CN/Extension.md
deleted file mode 100644
index ec6e143..0000000
--- a/doc/zh-CN/Extension.md
+++ /dev/null
@@ -1,159 +0,0 @@
-# @holoflows/kit/Extension/
-
-一些扩展开发会使用到的实用工具
-
-# class MessageCenter
-
-一个在 Chrome 扩展不同上下文间传递消息的类。
-
-> Typescript: 消息是有类型的!
-
-```ts
-interface AllEvents {
- event1: { x: number; y: number }
-}
-const mc = new MessageCenter()
-mc.on // 只接受监听 keyof AllEvents
-mc.send // 只允许发送 keyof AllEvents, 且 data 需要是 AllEvents[key]
-```
-
-## `constructor(key?: string)`
-
-- key?: 可随意指定,但需要在各个实例之间保持一致。
-
-## `.on(event, handler)`
-
-接受事件。
-
-## `.on(event, data)`
-
-发送事件。
-
-## `.writeToConsole`
-
-发送、接受事件时打印到控制台。
-
-# AsyncCall
-
-在不同环境之间进行远程过程调用。
-
-一个 MessageCenter 的高阶抽象。
-
-> 两端共享的代码
-
-- 如何对参数和返回值进行序列化、反序列化的代码应该在两端共享,默认值为不进行序列化。
-- `key` should be shared.
-
-> 甲端
-
-- 应该提供一些函数供另一端调用。(例如, `BackgroundCalls`)
-- `const call = AsyncCall(backgroundCalls)`
-- 然后你就能把 `call` 当作 `ForegroundCalls` 类型的对象来调用另一端的代码了。
-
-> 乙端
-
-- 应该提供一些函数供另一端调用。(例如, `ForegroundCalls`)
-- `const call = AsyncCall(foregroundCalls)`
-- 然后你就能把 `call` 当作 `BackgroundCalls` 类型的对象来调用另一端的代码了。
-
-_提示: 两端可以定义同一个函数_
-
-例子:
-
-```typescript
-// Mono repo
-// UI 一端
-const UI = {
- async dialog(text: string) {
- alert(text)
- },
-}
-export type UI = typeof UI
-const callsClient = AsyncCall(UI)
-callsClient.sendMail('hello world', 'what')
-
-// 服务器一端
-const Server = {
- async sendMail(text: string, to: string) {
- return true
- },
-}
-export type Server = typeof Server
-const calls = AsyncCall(Server)
-calls.dialog('hello')
-```
-
-## 选项
-
-- key: 一个 Key,以防与其他同一信道上通信的 AsyncCall 冲突,可以是任何内容,但需要在两端一致。(默认为 `default`)
-- serializer: 如何序列化、反序列化参数和返回值。(默认为 `NoSerialization`)
-- MessageCenter: 一个消息中心,作为通信信道,只要实现了对应接口即可使用任何信道通信,比如 `WebSocket` `chrome.runtime` 等。(默认为 `@holoflows/kit` 自带的 `MessageCenter`)
-- dontThrowOnNotImplemented: 如果本端收到了远程调用,但本端没有实现该函数时,是否忽略错误。(默认为 `true`)
-- writeToConsole: 是否把所有调用输出到控制台以便调试。(默认为 `true`)
-
-## 序列化
-
-有一些内置的序列化办法:
-
-- `NoSerialization` (不进行任何序列化)
-- `JSONSerialization` (使用 JSON.parse/stringify 进行序列化) (你可以提供一个 `replacer`!见 [JSON.stringify](https://mdn.io/JSON.stringify))
-
-你也可以实现自己的序列化,只需要实现 `Serialization` 接口即可。
-
-## 返回值
-
-返回一个类型为 `OtherSideImplementedFunctions` 的对象。
-
-# AutomatedTabTask
-
-基于 AsyncCall。打开一个新标签页,执行一些任务,然后自动关闭标签页。
-
-例子:
-
-> 在 content script 中(一定要在你需要执行任务的页面里注入!):
-
-```ts
-export const task = AutomatedTabTask({
- async taskA() {
- return 'Done!'
- },
-})
-```
-
-> 在背景页中:
-
-```ts
-import { task } from '...'
-task('https://example.com/').taskA()
-// 打开 https://example.com/,在上面运行 taskA(),等待返回结果('Done!')然后自动关闭页面
-```
-
-## 参数
-
-- taskImplements: Content script 能执行的任务。
-- AsyncCallKey: 一个 Key,默认对每个插件不同。
-
-## 返回值
-
-- 在 content script 上为 `null`
-- 在背景页上为 `typeof taskImplements`
-
-# Contexts
-
-辨别当前运行的上下文
-
-## type `Contexts`
-
-- background: 背景页
-- content: 内容脚本
-- unknown: 未知
-
-## `GetContext():`Contexts
-
-获取当前上下文
-
-## `OnlyRunInContext`(context: Contexts | Contexts[], name: string)
-
-只允许本段代码在某个上下文中运行,否则报错。
-
-- name 是报错时提供的名字。
diff --git a/doc/zh-CN/index.md b/doc/zh-CN/index.md
index ef4d41f..5510feb 100644
--- a/doc/zh-CN/index.md
+++ b/doc/zh-CN/index.md
@@ -6,8 +6,20 @@
@holoflows/kit 由以下部分组成
-- [DOM](./DOM.md) - 帮助扩展开发者追踪被注入网页中的内容变化
-- [Extension](./Extension.md) - 一些扩展开发会使用到的实用工具
+- [DOM 相关的工具的教程](./DOM.md) - 帮助扩展开发者追踪被注入网页中的内容变化
+- - [DomProxy](../../api-documents/kit.domproxy.md) 用于持续追踪网页变化而不丢失引用和副作用
+- - [LiveSelector](../../api-documents/kit.liveselector.md) 用于持续选择网页中的元素。
+- - `abstract` [Watcher](../../api-documents/kit.watcher.md)
+- - - [MutationObserverWatcher](../../api-documents/kit.mutationobserverwatcher.md) 通过 `MutationObserver` 追踪网页中的变化
+- - - [IntervalWatcher](../../api-documents/kit.intervalwatcher.md) 通过 `setInterval` 追踪网页中的变化
+- - - [EventWatcher](../../api-documents/kit.eventwatcher.md) 通过事件回调追踪网页中的变化
+- - [ValueRef](../../api-documents/kit.valueref.md) 通过 `setter` 订阅值的变化
+
+- Extension - 一些扩展开发会使用到的实用工具
+- - [AsyncCall](../../api-documents/kit.asynccall.md) 跨上下文的远程过程调用工具
+- - [Context](../../api-documents/kit.context.md) 在扩展开发中检测当前的上下文
+- - [MessageCenter](../../api-documents/kit.messagecenter.md) 在插件开发的不同上下文中通信
+- - [AutomatedTabTask](../../api-documents/kit.automatedtabtask.md) 打开一个新的标签页,自动执行某些任务,然后回传结果
## 安装
@@ -17,6 +29,8 @@
使用模块加载器时,使用 `@holoflows/kit` 导入;使用 umd 时,使用 `window.HoloflowsKit`。
+如果在 Chrome 中使用,需要加载 WebExtension 的 Polyfill (`webextension-polyfill`)。
+
### ECMAScript 版本
因为本库重度依赖 [Proxy](https://mdn.io/Proxy),所以支持 ES5 没有意义。
diff --git a/package.json b/package.json
index d7954e1..152834b 100644
--- a/package.json
+++ b/package.json
@@ -1,18 +1,26 @@
{
"name": "@holoflows/kit",
- "version": "0.2.0",
+ "version": "0.3.0",
"module": "./es/index.js",
"main": "./dist/out.js",
"typings": "./es/",
+ "homepage": "https://github.com/project-holoflows/holoflows-kit",
+ "bugs": {
+ "url": "https://github.com/project-holoflows/holoflows-kit/issues"
+ },
+ "readme": "https://github.com/project-holoflows/holoflows-kit/blob/master/README.md",
"dependencies": {
- "@types/chrome": "^0.0.81",
"@types/lodash-es": "^4.1.4",
"@types/node": "10.12.23",
+ "concurrent-lock": "^1.0.7",
"events": "^3.0.0",
"immer": "^2.1.3",
"lodash-es": "^4.1.2",
- "reflect-metadata": "^0.1.13"
+ "memorize-decorator": "^0.2.2",
+ "reflect-metadata": "^0.1.13",
+ "web-ext-types": "^3.1.0"
},
+ "sideEffects": false,
"scripts": {
"start": "npm-run-all --parallel start-tsc start-rollup",
"start-tsc": "tsc --watch",
@@ -21,9 +29,14 @@
"build-tsc": "tsc",
"build-rollup": "rollup -c",
"clean": "rimraf ./es ./dist",
- "prepublishOnly": "npm run build"
+ "prepublishOnly": "npm run build",
+ "apigen": "api-extractor run --local --verbose",
+ "mdgen": "api-documenter markdown -i temp -o api-documents",
+ "gendoc": "npm-run-all --serial build-tsc apigen mdgen"
},
"devDependencies": {
+ "@microsoft/api-documenter": "^7.1.6",
+ "@microsoft/api-extractor": "^7.1.4",
"npm-run-all": "^4.1.5",
"rimraf": "^2.6.3",
"rollup": "^1.1.2",
@@ -33,5 +46,8 @@
"rollup-plugin-typescript2": "^0.19.2",
"typescript": "^3.4.1"
},
+ "peerDependencies": {
+ "webextension-polyfill": "^0.4.0"
+ },
"license": "AGPL-3.0-or-later"
}
diff --git a/src/DOM/LiveSelector.ts b/src/DOM/LiveSelector.ts
index 0984ad5..c6cfd20 100644
--- a/src/DOM/LiveSelector.ts
+++ b/src/DOM/LiveSelector.ts
@@ -1,57 +1,143 @@
-type RecordType = { type: T; param: F }
/**
* Define all possible recordable operations.
*/
interface SelectorChainType {
- querySelector: RecordType<'querySelector', string>
- querySelectorAll: RecordType<'querySelectorAll', string>
- filter: RecordType<'filter', (element: any, index: number, array: any[]) => boolean>
- map: RecordType<'map', (element: any) => any>
- concat: RecordType<'concat', LiveSelector>
- reverse: RecordType<'reverse', undefined>
- slice: RecordType<'slice', [number | undefined, number | undefined]>
- sort: RecordType<'sort', (a: any, b: any) => number>
- flat: RecordType<'flat', undefined>
- nth: RecordType<'nth', number>
- replace: RecordType<'replace', (array: any[]) => any[]>
+ getElementsByClassName: string
+ getElementsByTagName: string
+ querySelector: string
+ closest: string | number
+ querySelectorAll: string
+ filter: (element: any, index: number, array: any[]) => boolean
+ map: (element: any) => any
+ concat: LiveSelector
+ reverse: undefined
+ slice: [number | undefined, number | undefined]
+ sort: ((a: any, b: any) => number) | undefined
+ flat: undefined
+ nth: number
+ replace: (array: any[]) => any[]
}
-type Keys = SelectorChainType[keyof SelectorChainType]['type']
-type Params = { [key in keyof SelectorChainType]: SelectorChainType[key]['param'] }
+type MapOf<
+ Original,
+ Type = {
+ [T in keyof Original]: {
+ type: T
+ param: Original[T]
+ }
+ },
+ EachType = Type[keyof Type]
+> = EachType
+type SelectorChainTypeItem = MapOf
+
/**
- * Create a live selector that can continuously select the element you want
+ * Create a live selector that can continuously select the element you want.
+ *
+ * @remarks
+ * Call {@link LiveSelector.evaluateOnce | #evaluateOnce} to evaluate the element. Falsy value will be ignored.
*
- * call `#evaluateOnce` to evaluate the element. Falsy will be ignored.
+ * @param T - Type of Element that LiveSelector contains
*/
export class LiveSelector {
- private generateMethod = (type: Key) => (param: Params[Key]): LiveSelector => {
+ /**
+ * Record a method call into {@link LiveSelector.selectorChain}
+ */
+ private appendSelectorChain = (type: Key) => (
+ param: SelectorChainType[Key],
+ ): LiveSelector => {
this.selectorChain.push({ type: type as any, param: param as any })
return this as LiveSelector
}
- private readonly selectorChain: (SelectorChainType[keyof SelectorChainType])[] = []
+ /**
+ * Records of previous calls on LiveSelector
+ */
+ private readonly selectorChain: SelectorChainTypeItem[] = []
+ /**
+ * Clone this LiveSelector and return a new LiveSelector.
+ * @returns a new LiveSelector with same action
+ * @example
+ * ```ts
+ * ls.clone()
+ * ```
+ */
+ clone() {
+ const ls = new LiveSelector()
+ ls.selectorChain.push(...this.selectorChain)
+ return ls
+ }
//#region Add elements
/**
* Select the first element that is a descendant of node that matches selectors.
*
- * @example ```ts
- * ls.querySelector('div#root')```
+ * @param selector - Selector
+ *
+ * @example
+ * ```ts
+ * ls.querySelector('div#root')
+ * ```
*/
- querySelector(selectors: K): LiveSelector
- querySelector(selectors: K): LiveSelector
- querySelector(selectors: string): LiveSelector
- querySelector(selectors: string): LiveSelector {
- return this.generateMethod('querySelector')(selectors)
+ querySelector(selector: K): LiveSelector
+ querySelector(selector: K): LiveSelector
+ querySelector(selector: string): LiveSelector
+ querySelector(selector: string): LiveSelector {
+ return this.appendSelectorChain('querySelector')(selector)
}
/**
* Select all element descendants of node that match selectors.
*
- * @example ```ts
- * ls.querySelector('div > div')```
+ * @param selector - Selector
+ * @example
+ * ```ts
+ * ls.querySelector('div > div')
+ * ```
+ */
+ querySelectorAll(selector: K): LiveSelector
+ querySelectorAll(selector: K): LiveSelector
+ querySelectorAll(selector: string): LiveSelector
+ querySelectorAll(selector: string): LiveSelector {
+ return this.appendSelectorChain('querySelectorAll')(selector)
+ }
+ /**
+ * Select all element base on the current result.
+ * @param className - Class name
+ * @example
+ * Equal to ls.querySelectorAll('.a .b')
+ * ```ts
+ * ls.getElementsByClassName('a').getElementsByClassName('b')
+ * ```
+ */
+ getElementsByClassName(className: string): LiveSelector
+ getElementsByClassName(className: string): LiveSelector {
+ return this.appendSelectorChain('getElementsByClassName')(className)
+ }
+ /**
+ * Select all element base on the current result.
+ * @param tag - Tag name
+ * @example
+ * Equal to ls.querySelectorAll('a b')
+ * ```ts
+ * ls.getElementsByTagName('a').getElementsByTagName('b')
+ * ```
*/
- querySelectorAll(selectors: K): LiveSelector
- querySelectorAll(selectors: K): LiveSelector
- querySelectorAll(selectors: string): LiveSelector
- querySelectorAll(selectors: string): LiveSelector {
- return this.generateMethod('querySelectorAll')(selectors)
+ getElementsByTagName