diff --git a/examples/react/package.json b/examples/react/package.json
index 48124c2e6f..cf6789f3c4 100644
--- a/examples/react/package.json
+++ b/examples/react/package.json
@@ -22,7 +22,6 @@
"@types/react": "^16.8.6",
"@types/react-dom": "^16.9.4",
"source-map-loader": "^0.2.4",
- "ts-loader": "^6.2.1",
- "typescript": "^3.7.4"
+ "ts-loader": "^6.2.1"
}
}
diff --git a/examples/react/src/index.css b/examples/react/src/index.css
index 00e2c3884c..485f4aa6c6 100644
--- a/examples/react/src/index.css
+++ b/examples/react/src/index.css
@@ -6,12 +6,14 @@
* the Apache License 2.0. The full license can be found in the LICENSE file.
*
*/
+
+ @import "~@finos/perspective-viewer/dist/umd/material-dense.css";
- perspective-viewer {
+perspective-viewer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
- }
+}
\ No newline at end of file
diff --git a/examples/react/src/index.tsx b/examples/react/src/index.tsx
index 3a7dba14cb..2a7b250936 100644
--- a/examples/react/src/index.tsx
+++ b/examples/react/src/index.tsx
@@ -9,43 +9,43 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
-import {useEffect, useRef} from "react";
-import perspective, {Table} from "@finos/perspective";
+import * as perspective from "@finos/perspective";
+
import "@finos/perspective-viewer";
import "@finos/perspective-viewer-datagrid";
import "@finos/perspective-viewer-d3fc";
+import {PerspectiveViewerConfig, PerspectiveViewerElement} from "@finos/perspective-viewer";
+
import "./index.css";
-import "@finos/perspective-viewer/dist/umd/material.css";
-import {HTMLPerspectiveViewerElement, PerspectiveViewerOptions} from "@finos/perspective-viewer";
-const worker = perspective.shared_worker();
+const worker = perspective.default.shared_worker();
-const getTable = async (): Promise
=> {
+const getTable = async (): Promise => {
const req = fetch("./superstore.arrow");
const resp = await req;
const buffer = await resp.arrayBuffer();
return await worker.table(buffer as any);
};
-const config: PerspectiveViewerOptions = {
- "row-pivots": ["State"]
+const config: PerspectiveViewerConfig = {
+ row_pivots: ["State"]
};
const App = (): React.ReactElement => {
- const viewer = useRef(null);
+ const viewer = React.useRef(null);
- useEffect(() => {
+ React.useEffect(() => {
getTable().then(table => {
if (viewer.current) {
- viewer.current.load(table);
+ viewer.current.load(Promise.resolve(table));
viewer.current.restore(config);
}
});
}, []);
- // You can also the use the stringified config values as attributes
- return ;
+ return ;
};
+
window.addEventListener("load", () => {
ReactDOM.render(, document.getElementById("root"));
});
diff --git a/examples/react/webpack.config.js b/examples/react/webpack.config.js
index 5492dc1505..d19a7f20fe 100644
--- a/examples/react/webpack.config.js
+++ b/examples/react/webpack.config.js
@@ -35,12 +35,12 @@ module.exports = {
},
{
test: /\.css$/,
+ exclude: /node_modules/,
use: [{loader: "style-loader"}, {loader: "css-loader"}]
}
]
},
devServer: {
- // superstore.arrow is served from here
contentBase: [path.join(__dirname, "dist"), path.join(__dirname, "../../node_modules/superstore-arrow")]
}
};
diff --git a/package.json b/package.json
index 771cf48fb5..42a3dfe3db 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
"@babel/preset-env": "^7.8.4",
"@rollup/plugin-babel": "^5.2.3",
"@rollup/plugin-node-resolve": "^11.1.1",
+ "@rollup/plugin-typescript": "^8.2.5",
"@types/ws": "^7.2.2",
"@typescript-eslint/eslint-plugin": "^2.4.0",
"@typescript-eslint/parser": "^2.4.0",
@@ -72,11 +73,7 @@
"npm-pack-here": "^1.2.0",
"npm-run-all": "^4.1.3",
"postcss": "^8.2.6",
- "postcss-copy-assets": "^0.3.1",
- "postcss-easy-import": "^3.0.0",
- "postcss-font-grabber": "^3.0.2",
"postcss-loader": "^4.1.0",
- "postcss-url": "^10.1.3",
"pre-commit": "^1.2.2",
"prettier": "^1.19.1",
"puppeteer": "^10.2.0",
@@ -91,7 +88,10 @@
"term-img": "^4.1.0",
"ts-jest": "^25.1.0",
"ts-loader": "^6.2.0",
- "typescript": "^3.7.4",
+ "typedoc": "^0.21.9",
+ "typedoc-plugin-markdown": "^3.10.4",
+ "typedoc-plugin-no-inherit": "^1.3.0",
+ "typescript": "4.3.3",
"webfontloader": "^1.6.28",
"webpack": "^5.14.0",
"webpack-cli": "^4.3.1",
diff --git a/packages/perspective-jupyterlab/package.json b/packages/perspective-jupyterlab/package.json
index 0d3f02fcd8..58dfe20488 100644
--- a/packages/perspective-jupyterlab/package.json
+++ b/packages/perspective-jupyterlab/package.json
@@ -53,8 +53,7 @@
"isomorphic-fetch": "^2.2.1",
"jest-transform-css": "^2.0.0",
"source-map-support": "^0.5.9",
- "ts-jest": "^25.1.0",
- "typescript": "^3.7.4"
+ "ts-jest": "^25.1.0"
},
"jupyterlab": {
"extension": true
diff --git a/packages/perspective-jupyterlab/src/ts/psp_widget.ts b/packages/perspective-jupyterlab/src/ts/psp_widget.ts
index 391107f60a..02d1b2b1f0 100644
--- a/packages/perspective-jupyterlab/src/ts/psp_widget.ts
+++ b/packages/perspective-jupyterlab/src/ts/psp_widget.ts
@@ -9,16 +9,16 @@
import "@finos/perspective-viewer";
-import {Table, TableData} from "@finos/perspective";
+import {Table, TableData, Aggregate, Sort, Expression, Filter, ColumnName} from "@finos/perspective";
import {Message} from "@lumino/messaging";
import {Widget} from "@lumino/widgets";
import {MIME_TYPE, PSP_CLASS, PSP_CONTAINER_CLASS, PSP_CONTAINER_CLASS_DARK} from "./utils";
-import {HTMLPerspectiveViewerElement, Pivots, Aggregates, Sort, Expressions, PerspectiveViewerOptions, Filters, Columns} from "@finos/perspective-viewer";
+import {PerspectiveViewerElement, PerspectiveViewerConfig} from "@finos/perspective-viewer";
let _increment = 0;
-export interface PerspectiveWidgetOptions extends PerspectiveViewerOptions {
+export interface PerspectiveWidgetOptions extends PerspectiveViewerConfig {
dark?: boolean;
client?: boolean;
server?: boolean;
@@ -27,9 +27,9 @@ export interface PerspectiveWidgetOptions extends PerspectiveViewerOptions {
// these shouldn't exist, PerspectiveViewerOptions should be sufficient e.g.
// ["row-pivots"]
- column_pivots?: Pivots;
- row_pivots?: Pivots;
- expressions?: Expressions;
+ column_pivots?: Array;
+ row_pivots?: Array;
+ expressions?: Array;
editable?: boolean;
}
@@ -56,21 +56,21 @@ export class PerspectiveWidget extends Widget {
*
* @param options
*/
- _set_attributes(options: PerspectiveViewerOptions & PerspectiveWidgetOptions): void {
+ _set_attributes(options: PerspectiveViewerConfig & PerspectiveWidgetOptions): void {
const plugin: string = options.plugin || "datagrid";
- const columns: Columns = options.columns || [];
- const row_pivots: Pivots = options.row_pivots || options.row_pivots || [];
- const column_pivots: Pivots = options.column_pivots || options.column_pivots || [];
- const aggregates: Aggregates = options.aggregates || {};
- const sort: Sort = options.sort || [];
- const filter: Filters = options.filter || [];
- const expressions: Expressions = options.expressions || options.expressions || [];
+ const columns: ColumnName[] = options.columns || [];
+ const row_pivots: ColumnName[] = options.row_pivots || options.row_pivots || [];
+ const column_pivots: ColumnName[] = options.column_pivots || options.column_pivots || [];
+ const aggregates: {[column: string]: Aggregate} = options.aggregates || {};
+ const sort: Sort[] = options.sort || [];
+ const filter: Filter[] = options.filter || [];
+ const expressions: Expression[] = options.expressions || options.expressions || [];
const plugin_config: object = options.plugin_config || {};
const dark: boolean = options.dark || false;
const editable: boolean = options.editable || false;
const server: boolean = options.server || false;
const client: boolean = options.client || false;
- const selectable: boolean = options.selectable || false;
+ // const selectable: boolean = options.selectable || false;
this.server = server;
this.client = client;
@@ -89,7 +89,7 @@ export class PerspectiveWidget extends Widget {
};
// this.plugin_config = plugin_config;
- this.selectable = selectable;
+ // this.selectable = selectable;
}
/**********************/
@@ -122,22 +122,18 @@ export class PerspectiveWidget extends Widget {
}
async notifyResize(): Promise {
- if (this.isVisible) {
- await this.viewer.notifyResize();
- }
+ await this.viewer.notifyResize();
}
async toggleConfig(): Promise {
- if (this.isVisible) {
- await this.viewer.toggleConfig();
- }
+ await this.viewer.toggleConfig();
}
- async save(): Promise {
+ async save(): Promise {
return await this.viewer.save();
}
- async restore(config: PerspectiveViewerOptions): Promise {
+ async restore(config: PerspectiveViewerConfig): Promise {
return await this.viewer.restore(config);
}
@@ -156,15 +152,17 @@ export class PerspectiveWidget extends Widget {
*
* @param data
*/
- _update(data: TableData): void {
- this.viewer.table.update(data);
+ async _update(data: TableData): Promise {
+ const table = await this.viewer.getTable();
+ await table.update(data);
}
/**
* Removes all rows from the viewer's table. Does not reset viewer state.
*/
async clear(): Promise {
- await this.viewer.table.clear();
+ const table = await this.viewer.getTable();
+ await table.clear();
}
/**
@@ -174,7 +172,8 @@ export class PerspectiveWidget extends Widget {
* @param data
*/
async replace(data: TableData): Promise {
- await this.viewer.table.replace(data);
+ const table = await this.viewer.getTable();
+ await table.replace(data);
}
/**
@@ -194,8 +193,8 @@ export class PerspectiveWidget extends Widget {
return await this.viewer.getEditPort();
}
- get table(): Table {
- return this.viewer.table;
+ async getTable(): Promise {
+ return await this.viewer.getTable();
}
/***************************************************************************
@@ -209,7 +208,7 @@ export class PerspectiveWidget extends Widget {
*
* @returns {PerspectiveViewer} The widget's viewer instance.
*/
- get viewer(): HTMLPerspectiveViewerElement {
+ get viewer(): PerspectiveViewerElement {
return this._viewer;
}
@@ -306,7 +305,7 @@ export class PerspectiveWidget extends Widget {
}
}
- static createNode(node: HTMLDivElement): HTMLPerspectiveViewerElement {
+ static createNode(node: HTMLDivElement): PerspectiveViewerElement {
node.classList.add("p-Widget");
node.classList.add(PSP_CONTAINER_CLASS);
const viewer = document.createElement("perspective-viewer");
@@ -342,11 +341,11 @@ export class PerspectiveWidget extends Widget {
return viewer;
}
- private _viewer: HTMLPerspectiveViewerElement;
+ private _viewer: PerspectiveViewerElement;
private _plugin_config: object;
private _client: boolean;
private _server: boolean;
private _dark: boolean;
private _editable: boolean;
- private _viewer_config: PerspectiveViewerOptions;
+ private _viewer_config: PerspectiveViewerConfig;
}
diff --git a/packages/perspective-jupyterlab/src/ts/renderer.ts b/packages/perspective-jupyterlab/src/ts/renderer.ts
index 06dfb40c65..42055d84f7 100644
--- a/packages/perspective-jupyterlab/src/ts/renderer.ts
+++ b/packages/perspective-jupyterlab/src/ts/renderer.ts
@@ -83,7 +83,10 @@ export class PerspectiveDocumentWidget extends DocumentWidget
throw "Not handled";
}
- if (this._psp.viewer.table === undefined) {
+ try {
+ const table = await this._psp.viewer.getTable();
+ table.replace(data);
+ } catch (e) {
// construct new table
const table_promise = WORKER.table(data);
@@ -109,10 +112,7 @@ export class PerspectiveDocumentWidget extends DocumentWidget
this.context.model.fromJSON(result);
this.context.save();
}
- });
- } else {
- // replace existing table for whatever reason
- this._psp.replace(data);
+ });
}
} catch (e) {
baddialog();
diff --git a/packages/perspective-jupyterlab/src/ts/widget.ts b/packages/perspective-jupyterlab/src/ts/widget.ts
index e01dc99b7f..7058cb9564 100644
--- a/packages/perspective-jupyterlab/src/ts/widget.ts
+++ b/packages/perspective-jupyterlab/src/ts/widget.ts
@@ -10,7 +10,7 @@
import {Message} from "@lumino/messaging";
import {DOMWidgetView} from "@jupyter-widgets/base";
-import {PerspectiveViewerOptions} from "@finos/perspective-viewer";
+import {PerspectiveViewerConfig} from "@finos/perspective-viewer";
import {PerspectiveWidget, PerspectiveWidgetOptions} from "./psp_widget";
export type PerspectiveJupyterWidgetOptions = {
@@ -21,7 +21,7 @@ export type PerspectiveJupyterWidgetOptions = {
* PerspectiveJupyterWidget is the ipywidgets front-end for the Perspective Jupyterlab plugin.
*/
export class PerspectiveJupyterWidget extends PerspectiveWidget {
- constructor(name = "Perspective", options: PerspectiveViewerOptions & PerspectiveJupyterWidgetOptions & PerspectiveWidgetOptions) {
+ constructor(name = "Perspective", options: PerspectiveViewerConfig & PerspectiveJupyterWidgetOptions & PerspectiveWidgetOptions) {
const view = options.view;
delete options.view;
super(name, options);
diff --git a/packages/perspective/index.d.ts b/packages/perspective/index.d.ts
index e4ea8fc04c..6b74133f05 100644
--- a/packages/perspective/index.d.ts
+++ b/packages/perspective/index.d.ts
@@ -1,85 +1,39 @@
declare module "@finos/perspective" {
import * as ws from "ws";
- /**** object types ****/
- export enum TypeNames {
- STRING = "string",
- FLOAT = "float",
- INTEGER = "integer",
- BOOLEAN = "boolean",
- DATE = "date",
- DATETIME = "datetime",
- OBJECT = "object"
- }
-
- export type ValuesByType = {
- [key in TypeNames]: Array;
- };
-
- export type ValueByType = {
- TypeNames: Array;
- };
-
- export enum SortOrders {
- ASC = "asc",
- ASC_ABS = "asc abs",
- DESC = "desc",
- DESC_ABS = "desc abs",
- NONE = "none"
- }
-
- enum NUMBER_AGGREGATES {
- ABS_SUM = "abs sum",
- ANY = "any",
- AVERAGE = "avg",
- COUNT = "count",
- DISTINCT_COUNT = "distinct count",
- DOMINANT = "dominant",
- FIRST = "first",
- LAST = "last",
- HIGH = "high",
- LOW = "low",
- MEAN = "mean",
- MEDIAN = "median",
- PCT_SUM_PARENT = "pct sum parent",
- PCT_SUM_TOTAL = "pct sum grand total",
- STANDARD_DEVIATION = "stddev",
- SUM = "sum",
- SUM_ABS = "sum abs",
- SUM_NOT_NULL = "sum not null",
- UNIQUE = "unique",
- VARIANCE = "var"
- }
-
- enum STRING_AGGREGATES {
- ANY = "any",
- COUNT = "count",
- DISTINCT_COUNT = "distinct count",
- DISTINCT_LEAF = "distinct leaf",
- DOMINANT = "dominant",
- FIRST = "first",
- LAST = "last",
- UNIQUE = "unique"
- }
-
- enum BOOLEAN_AGGREGATES {
- AND = "and",
- ANY = "any",
- COUNT = "count",
- DISTINCT_COUNT = "distinct count",
- DISTINCT_LEAF = "distinct leaf",
- DOMINANT = "dominant",
- FIRST = "first",
- LAST = "last",
- OR = "or",
- UNIQUE = "unique"
- }
-
- /**** Schema ****/
- type SchemaType = TypeNames | NUMBER_AGGREGATES | STRING_AGGREGATES | BOOLEAN_AGGREGATES;
+ export type Type = "string" | "float" | "integer" | "boolean" | "date" | "datetime" | "object";
+
+ export type SortDir = "asc" | "asc abs" | "desc" | "desc abs" | "col asc" | "col asc abs" | "col desc" | "col desc abs";
+
+ export type Aggregate =
+ | "abs sum"
+ | "and"
+ | "any"
+ | "avg"
+ | "count"
+ | "distinct count"
+ | "distinct leaf"
+ | "dominant"
+ | "first"
+ | "high"
+ | "last"
+ | "low"
+ | "or"
+ | "median"
+ | "pct sum parent"
+ | "pct sum grand total"
+ | "stddev"
+ | "sum"
+ | "sum abs"
+ | "sum not null"
+ | "unique"
+ | "var"
+ | ["weighted mean", ColumnName];
+
+ export type FilterOp = "<" | ">" | "<=" | ">=" | "==" | "!=" | "is null" | "is not null" | "in" | "not in" | "begins with" | "contains";
export type Schema = {
- [key: string]: TypeNames;
+ [key: string]: Type;
};
export interface SerializeConfig {
@@ -127,14 +81,19 @@ declare module "@finos/perspective" {
limit?: number;
};
+ export type ColumnName = string;
+ export type Expression = string;
+ export type Filter = [ColumnName, FilterOp, string | number | Date | boolean | Array];
+ export type Sort = [ColumnName, SortDir];
+
export type ViewConfig = {
- columns?: Array;
- row_pivots?: Array;
- column_pivots?: Array;
- aggregates?: {[column_name: string]: string};
- sort?: Array>;
- filter?: Array>;
- expressions?: Array;
+ columns?: Array;
+ row_pivots?: Array;
+ column_pivots?: Array;
+ aggregates?: {[column_name: string]: Aggregate};
+ sort?: Array;
+ filter?: Array;
+ expressions?: Array;
};
export type Table = {
@@ -192,9 +151,6 @@ declare module "@finos/perspective" {
export function perspective_assets(assets: string[], host_psp: boolean): (request: any, response: any) => void;
type perspective = {
- TYPE_AGGREGATES: ValuesByType;
- TYPE_FILTERS: ValuesByType;
- SORT_ORDERS: SortOrders;
table(data_or_schema: TableData | Schema, options?: TableOptions): Promise;
worker(): PerspectiveWorker;
shared_worker(): PerspectiveWorker;
@@ -206,16 +162,3 @@ declare module "@finos/perspective" {
export default impl;
}
-
-declare module "@finos/perspective/build/psp.async.wasm" {
- const impl: ArrayBuffer;
- export default impl;
-}
-
-declare module "@finos/perspective/build/psp.sync.wasm" {
- const impl: ArrayBuffer;
- export default impl;
-}
-
-declare module "@finos/perspective/build/perspective.wasm.worker.js" {}
-declare module "@finos/perspective/build/perspective.asmjs.worker.js" {}
diff --git a/packages/perspective/package.json b/packages/perspective/package.json
index 5b511feb23..c3635776c6 100644
--- a/packages/perspective/package.json
+++ b/packages/perspective/package.json
@@ -18,7 +18,7 @@
"index.d.ts",
"babel.config.js"
],
- "typings": "index.d.ts",
+ "types": "index.d.ts",
"scripts": {
"build:babel:esm": "babel src/js --source-maps --out-dir dist/esm",
"build:babel:cjs": "BABEL_MODULE=auto babel dist/esm --source-maps --out-dir dist/cjs",
diff --git a/rust/perspective-viewer/README.md b/rust/perspective-viewer/README.md
new file mode 100644
index 0000000000..c20750ad75
--- /dev/null
+++ b/rust/perspective-viewer/README.md
@@ -0,0 +1,673 @@
+# @finos/perspective-viewer
+
+Module for the `` custom element. This module has no
+(real) exports, but importing it has a side effect: the
+`PerspectiveViewerElement`class is registered as a custom element, after
+which it can be used as a standard DOM element.
+
+Though `` is written mostly in Rust, the nature
+of WebAssembly's compilation makes it a dynamic module; in order to
+guarantee that the Custom Elements extension methods are registered
+synchronously with this package's import, we need perform said registration
+within this wrapper module.
+
+The documentation in this module defines the instance structure of a
+`` DOM object instantiated typically, through HTML or any
+relevent DOM method e.g. `document.createElement("perspective-viewer")` or
+`document.getElementsByTagName("perspective-viewer")`.
+
+## Table of contents
+
+### Classes
+
+- [PerspectiveViewerElement](#PerspectiveViewerElement)
+
+### Type aliases
+
+- [PerspectiveViewerConfig](#perspectiveviewerconfig)
+
+## Type aliases
+
+### PerspectiveViewerConfig
+
+Ƭ **PerspectiveViewerConfig**: `perspective.ViewConfig` & { `plugin?`: `string` ; `plugin_config?`: `object` ; `settings?`: `boolean` }
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:56](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L56)
+
+
+# Class: PerspectiveViewerElement
+
+The Custom Elements implementation for ``, as well at its
+API. `PerspectiveViewerElement` should not be constructed directly (like its
+parent class `HTMLElement`); instead, use `document.createElement()` or
+declare your `` element in HTML. Once instantiated,
+`` works just like a standard `HTMLElement`, with a few
+extra perspective-specific methods.
+
+**`example`**
+```javascript
+const viewer = document.createElement("perspective-viewer");
+```
+
+**`example`**
+```javascript
+document.body.innerHTML = `
+
+`;
+const viewer = document.body.querySelector("#viewer");
+```
+
+## Hierarchy
+
+- `HTMLElement`
+
+ ↳ **`PerspectiveViewerElement`**
+
+## Table of contents
+
+### Data Methods
+
+- [getTable](#gettable)
+- [load](#load)
+
+### Persistence Methods
+
+- [reset](#reset)
+- [restore](#restore)
+- [save](#save)
+
+### Plugin Methods
+
+- [getAllPlugins](#getallplugins)
+- [getPlugin](#getplugin)
+- [registerPlugin](#registerplugin)
+
+### UI Action Methods
+
+- [copy](#copy)
+- [download](#download)
+- [toggleConfig](#toggleconfig)
+
+### Util Methods
+
+- [delete](#delete)
+- [flush](#flush)
+- [getEditPort](#geteditport)
+- [notifyResize](#notifyresize)
+- [restyleElement](#restyleelement)
+- [setThrottle](#setthrottle)
+
+## Data Methods
+
+### getTable
+
+▸ **getTable**(): `Promise`<`Table`\>
+
+Returns the `perspective.Table()` which was supplied to `load()`. If
+`load()` has been called but the supplied `Promise`
+has not resolved, `getTable()` will `await`; if `load()` has not yet
+been called, an `Error` will be thrown.
+
+**`example`** Share a `Table`
+```javascript
+const viewers = document.querySelectorAll("perspective-viewer");
+const [viewer1, viewer2] = Array.from(viewers);
+const table = await viewer1.getTable();
+await viewer2.load(table);
+```
+
+#### Returns
+
+`Promise`<`Table`\>
+
+A `Promise` which resolves to a `perspective.Table`
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:194](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L194)
+
+___
+
+### load
+
+▸ **load**(`table`): `Promise`<`void`\>
+
+Load a `perspective.Table`. If `load` or `update` have already been
+called on this element, its internal `perspective.Table` will _not_ be
+deleted, but it will bed de-referenced by this ``.
+
+**`example`** Load perspective.table
+```javascript
+const my_viewer = document.getElementById('#my_viewer');
+const tbl = perspective.table("x,y\n1,a\n2,b");
+my_viewer.load(tbl);
+```
+
+**`example`** Load Promise
+```javascript
+const my_viewer = document.getElementById('#my_viewer');
+const tbl = perspective.table("x,y\n1,a\n2,b");
+my_viewer.load(tbl);
+```
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `table` | `Promise`<`Table`\> |
+
+#### Returns
+
+`Promise`<`void`\>
+
+A promise which resolves once the data is
+loaded, a `perspective.View` has been created, and the active plugin has
+rendered.
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:151](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L151)
+
+___
+
+## Persistence Methods
+
+### reset
+
+▸ **reset**(): `Promise`<`void`\>
+
+Reset's this element's view state and attributes to default. Does not
+delete this element's `perspective.table` or otherwise modify the data
+state.
+
+**`example`**
+```javascript
+const viewer = document.querySelector("perspective-viewer");
+await viewer.reset();
+```
+
+#### Returns
+
+`Promise`<`void`\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:308](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L308)
+
+___
+
+### restore
+
+▸ **restore**(`config`): `Promise`<`void`\>
+
+Restore this element to a state as generated by a reciprocal call to
+`save`. In `json` (default) format, `PerspectiveViewerConfig`'s fields
+have specific semantics:
+
+ - When a key is missing, this field is ignored; ``
+ will maintain whatever settings for this field is currently applied.
+ - When the key is supplied, but the value is `undefined`, the field is
+ reset to its default value for this current `View`, i.e. the state it
+ would be in after `load()` resolves.
+ - When the key is defined to a value, the value is applied for this
+ field.
+
+This behavior is convenient for explicitly controlling current vs desired
+UI state in a single request, but it does make it a bit inconvenient to
+use `restore()` to reset a `` to default as you must
+do so explicitly for each key; for this case, use `reset()` instead of
+restore.
+
+As noted in `save()`, this configuration state does not include the
+`Table` or its `Schema`. In order for `restore()` to work correctly, it
+must be called on a `` that has a `Table already
+`load()`-ed, with the same (or a type-compatible superset) `Schema`.
+It does not need have the same rows, or even be populated.
+
+**`example`** Restore a viewer from `localStorage`
+```javascript
+const viewer = document.querySelector("perspective-viewer");
+const token = localStorage.getItem("viewer_state");
+await viewer.restore(token);
+```
+
+#### Parameters
+
+| Name | Type | Description |
+| :------ | :------ | :------ |
+| `config` | `string` \| [`PerspectiveViewerConfig`](#perspectiveviewerconfig) \| `ArrayBuffer` | returned by `save()`. This can be any format returned by `save()`; the specific deserialization is chosen by `typeof config`. |
+
+#### Returns
+
+`Promise`<`void`\>
+
+A promise which resolves when the changes have been applied and
+rendered.
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:237](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L237)
+
+___
+
+### save
+
+▸ **save**(): `Promise`<[`PerspectiveViewerConfig`](#perspectiveviewerconfig)\>
+
+Serialize this element's attribute/interaction state, but _not_ the
+`perspective.Table` or its `Schema`. `save()` is designed to be used in
+conjunction with `restore()` to persist user settings and bookmarks, but
+the `PerspectiveViewerConfig` object returned in `json` format can also
+be written by hand quite easily, which is useful for authoring
+pre-conceived configs.
+
+**`example`** Save a viewer to `localStorage`
+```javascript
+const viewer = document.querySelector("perspective-viewer");
+const token = await viewer.save("string");
+localStorage.setItem("viewer_state", token);
+```
+
+#### Returns
+
+`Promise`<[`PerspectiveViewerConfig`](#perspectiveviewerconfig)\>
+
+a serialized element in the chosen format.
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:262](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L262)
+
+▸ **save**(`format`): `Promise`<[`PerspectiveViewerConfig`](#perspectiveviewerconfig)\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `format` | ``"json"`` |
+
+#### Returns
+
+`Promise`<[`PerspectiveViewerConfig`](#perspectiveviewerconfig)\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:263](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L263)
+
+▸ **save**(`format`): `Promise`<`ArrayBuffer`\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `format` | ``"arraybuffer"`` |
+
+#### Returns
+
+`Promise`<`ArrayBuffer`\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:264](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L264)
+
+▸ **save**(`format`): `Promise`<`string`\>
+
+#### Parameters
+
+| Name | Type |
+| :------ | :------ |
+| `format` | ``"string"`` |
+
+#### Returns
+
+`Promise`<`string`\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:265](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L265)
+
+___
+
+## Plugin Methods
+
+### getAllPlugins
+
+▸ **getAllPlugins**(): `Promise`<`HTMLElement`[]\>
+
+Get all plugin custom element instances, in order of registration.
+
+If no plugins have been registered (via `registerPlugin()`), calling
+`getAllPlugins()` will cause `perspective-viewer-debug` to be registered
+as a side effect.
+
+#### Returns
+
+`Promise`<`HTMLElement`[]\>
+
+An `Array` of the plugin instances for this
+``.
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:478](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L478)
+
+___
+
+### getPlugin
+
+▸ **getPlugin**(`name`): `Promise`<`HTMLElement`\>
+
+Get the currently active plugin custom element instance, or a specific
+named instance if requested. `getPlugin(name)` does not activate the
+plugin requested, so if this plugin is not active the returned
+`HTMLElement` will not have a `parentElement`.
+
+If no plugins have been registered (via `registerPlugin()`), calling
+`getPlugin()` will cause `perspective-viewer-debug` to be registered as a
+side effect.
+
+#### Parameters
+
+| Name | Type | Description |
+| :------ | :------ | :------ |
+| `name` | `any` | Optionally a specific plugin name, defaulting to the current active plugin. |
+
+#### Returns
+
+`Promise`<`HTMLElement`\>
+
+The active or requested plugin instance.
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:461](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L461)
+
+___
+
+### registerPlugin
+
+▸ `Static` **registerPlugin**(`name`): `Promise`<`void`\>
+
+Register a new plugin via its custom element name. This method is called
+automatically as a side effect of importing a plugin module, so this
+method should only typically be called by plugin authors.
+
+#### Parameters
+
+| Name | Type | Description |
+| :------ | :------ | :------ |
+| `name` | `any` | The `name` of the custom element to register, as supplied to the `customElements.define(name)` method. |
+
+#### Returns
+
+`Promise`<`void`\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:123](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L123)
+
+___
+
+## UI Action Methods
+
+### copy
+
+▸ **copy**(`flat`): `Promise`<`void`\>
+
+Copies this element's view data (as a CSV) to the clipboard. This method
+must be called from an event handler, subject to the browser's
+restrictions on clipboard access. See
+[https://www.w3.org/TR/clipboard-apis/#allow-read-clipboard](https://www.w3.org/TR/clipboard-apis/#allow-read-clipboard).
+
+**`example`**
+```javascript
+const viewer = document.querySelector("perspective-viewer");
+const button = document.querySelector("button");
+button.addEventListener("click", async () => {
+ await viewer.copy();
+});
+```
+
+#### Parameters
+
+| Name | Type | Description |
+| :------ | :------ | :------ |
+| `flat` | `boolean` | Whether to use the element's current view config, or to use a default "flat" view. |
+
+#### Returns
+
+`Promise`<`void`\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:357](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L357)
+
+___
+
+### download
+
+▸ **download**(`flat`): `Promise`<`void`\>
+
+Download this element's data as a CSV file.
+
+#### Parameters
+
+| Name | Type | Description |
+| :------ | :------ | :------ |
+| `flat` | `boolean` | Whether to use the element's current view config, or to use a default "flat" view. |
+
+#### Returns
+
+`Promise`<`void`\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:334](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L334)
+
+___
+
+### toggleConfig
+
+▸ **toggleConfig**(`force?`): `Promise`<`void`\>
+
+Opens/closes the element's config menu, equivalent to clicking the
+settings button in the UI. This method is equivalent to
+`viewer.restore({settings: force})` when `force` is present, but
+`restore()` cannot toggle as `toggleConfig()` can, you would need to
+first read the settings state from `save()` otherwise.
+
+Calling `toggleConfig()` may be delayed if an async render is currently
+in process, and it may only partially render the UI if `load()` has not
+yet resolved.
+
+**`example`**
+```javascript
+await viewer.toggleConfig();
+```
+
+#### Parameters
+
+| Name | Type | Description |
+| :------ | :------ | :------ |
+| `force?` | `boolean` | If supplied, explicitly set the config state to "open" (`true`) or "closed" (`false`). |
+
+#### Returns
+
+`Promise`<`void`\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:441](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L441)
+
+___
+
+## Util Methods
+
+### delete
+
+▸ **delete**(): `Promise`<`void`\>
+
+Deletes this element and clears it's internal state (but not its
+user state). This (or the underlying `perspective.view`'s equivalent
+method) must be called in order for its memory to be reclaimed, as well
+as the reciprocal method on the `perspective.table` which this viewer is
+bound to.
+
+#### Returns
+
+`Promise`<`void`\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:322](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L322)
+
+___
+
+### flush
+
+▸ **flush**(): `Promise`<`void`\>
+
+Flush any pending modifications to this ``. Since
+``'s API is almost entirely `async`, it may take
+some milliseconds before any method call such as `restore()` affects
+the rendered element. If you want to make sure any invoked method which
+affects the rendered has had its results rendered, call and await
+`flush()`
+
+**`example`** Flush an unawaited `restore()`
+```javascript
+const viewer = document.querySelector("perspective-viewer");
+viewer.restore({row_pivots: ["State"]});
+await viewer.flush();
+console.log("Viewer has been rendered with a pivot!");
+```
+
+#### Returns
+
+`Promise`<`void`\>
+
+A promise which resolves when the current
+pending state changes have been applied and rendered.
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:291](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L291)
+
+___
+
+### getEditPort
+
+▸ **getEditPort**(): `Promise`<`number`\>
+
+Gets the edit port, the port number for which `Table` updates from this
+`` are generated. This port number will be present
+in the options object for a `View.on_update()` callback for any update
+which was originated by the ``/user, which can be
+used to distinguish server-originated updates from user edits.
+
+**`example`**
+```javascript
+const viewer = document.querySelector("perspective-viewer");
+const editport = await viewer.getEditPort();
+const table = await viewer.getTable();
+const view = await table.view();
+view.on_update(obj => {
+ if (obj.port_id = editport) {
+ console.log("User edit detected");
+ }
+});
+```
+
+#### Returns
+
+`Promise`<`number`\>
+
+A promise which resolves to the current edit port.
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:397](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L397)
+
+___
+
+### notifyResize
+
+▸ **notifyResize**(): `Promise`<`void`\>
+
+Redraw this `` and plugin when its dimensions or
+visibility have been updated. This method _must_ be called in these
+cases, and will not by default respond to dimension or style changes to
+its parent container. `notifyResize()` does not recalculate the current
+`View`, but all plugins will re-request the data window (which itself
+may be smaller or larger due to resize).
+
+**`example`** Bind `notfyResize()` to browser dimensions
+```javascript
+const viewer = document.querySelector("perspective-viewer");
+window.addEventListener("resize", () => viewer.notifyResize());
+```
+
+#### Returns
+
+`Promise`<`void`\>
+
+A `Promise` which resolves when this resize event has
+finished rendering.
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:173](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L173)
+
+___
+
+### restyleElement
+
+▸ **restyleElement**(): `Promise`<`void`\>
+
+Restyles the elements and to pick up any style changes. While most of
+perspective styling is plain CSS and can be updated at any time, some
+CSS rules are read and cached, e.g. the series colors for
+`@finos/perspective-viewer-d3fc` which are read from CSS then reapplied
+as SVG and Canvas attributes.
+
+#### Returns
+
+`Promise`<`void`\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:371](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L371)
+
+___
+
+### setThrottle
+
+▸ **setThrottle**(`value?`): `Promise`<`void`\>
+
+Determines the render throttling behavior. Can be an integer, for
+millisecond window to throttle render event; or, if `undefined`,
+will try to determine the optimal throttle time from this component's
+render framerate.
+
+**`example`** Limit FPS to 1 frame per second
+```javascript
+await viewer.setThrottle(1000);
+```
+
+#### Parameters
+
+| Name | Type | Description |
+| :------ | :------ | :------ |
+| `value?` | `number` | an optional throttle rate in milliseconds (integer). If not supplied, adaptive throttling is calculated from the average plugin render time. |
+
+#### Returns
+
+`Promise`<`void`\>
+
+#### Defined in
+
+[rust/perspective-viewer/src/ts/index.ts:417](https://github.com/finos/perspective/blob/4e5bed7d/rust/perspective-viewer/src/ts/index.ts#L417)
+
+
diff --git a/rust/perspective-viewer/babel.config.js b/rust/perspective-viewer/babel.config.js
deleted file mode 100644
index fe6e7ee13d..0000000000
--- a/rust/perspective-viewer/babel.config.js
+++ /dev/null
@@ -1,17 +0,0 @@
-module.exports = {
- presets: [
- [
- "@babel/preset-env",
- {
- targets: {
- chrome: "70",
- node: "12",
- ios: "13"
- },
- modules: process.env.BABEL_MODULE || false
- }
- ]
- ],
- plugins: [["@babel/plugin-proposal-decorators", {legacy: true}], "transform-custom-element-classes", "@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-optional-chaining"],
- sourceMaps: true
-};
diff --git a/rust/perspective-viewer/concat-md.js b/rust/perspective-viewer/concat-md.js
new file mode 100644
index 0000000000..e810980a88
--- /dev/null
+++ b/rust/perspective-viewer/concat-md.js
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2018, the Perspective Authors.
+ *
+ * This file is part of the Perspective library, distributed under the terms
+ * of the Apache License 2.0. The full license can be found in the LICENSE
+ * file.
+ *
+ */
+
+// Forked from gist
+// https://gist.github.com/davideicardi/787df4a9dc0de66c1db8f5a57e511230
+
+const fs = require("fs");
+const {Transform, PassThrough} = require("stream");
+
+function concatStreams(streams) {
+ let pass = new PassThrough();
+ let waiting = streams.length;
+ for (let stream of streams) {
+ pass = stream.pipe(pass, {end: false});
+ stream.once("end", () => --waiting === 0 && pass.emit("end"));
+ }
+ return pass;
+}
+
+class AddEndOfLine extends Transform {
+ constructor(options) {
+ super(options);
+ }
+ _transform(data, encoding, callback) {
+ this.push(data);
+ this.push("\n\n");
+ callback();
+ }
+}
+
+class ConvertLinksToAnchors extends Transform {
+ constructor(options) {
+ super(options);
+ }
+ _transform(data, encoding, callback) {
+ const pattern = /\[(.+)\]\((.+\.md)?(#(.+))?\)/g;
+ const newData = data.toString().replace(pattern, (m, p1, p2, p3) => {
+ const anchor = `${p3 && p3.length > 0 ? p3.slice(1) : p1}`;
+ return `[${p1}](#${anchor})`;
+ });
+
+ this.push(newData);
+ callback();
+ }
+}
+
+const inPaths = ["./dist/docs/README.md", "./dist/docs/classes/PerspectiveViewerElement.md"];
+
+const outPath = "./README.md";
+const inputs = inPaths.map(x => fs.createReadStream(x));
+const output = fs.createWriteStream(outPath);
+
+concatStreams(inputs)
+ .pipe(new AddEndOfLine())
+ .pipe(new ConvertLinksToAnchors())
+ .pipe(output)
+ .on("finish", function() {
+ console.log("Done merging!");
+ });
diff --git a/rust/perspective-viewer/index.d.ts b/rust/perspective-viewer/index.d.ts
deleted file mode 100644
index b3839f5258..0000000000
--- a/rust/perspective-viewer/index.d.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-/******************************************************************************
- *
- * Copyright (c) 2017, the Perspective Authors.
- *
- * This file is part of the Perspective library, distributed under the terms of
- * the Apache License 2.0. The full license can be found in the LICENSE file.
- *
- */
-
-import React from "react";
-import {Table, View} from "@finos/perspective";
-
-export interface HTMLPerspectiveViewerElement extends PerspectiveViewerOptions, HTMLElement {
- load(data: Promise): void;
- delete(): Promise;
- flush(): Promise;
- getEditPort(): Promise;
- toggleConfig(): Promise;
- download(flat: boolean): Promise;
- getTable(): Promise;
- copy(flat: boolean): Promise;
- save(): Promise;
- restore(x: PerspectiveViewerOptions): Promise;
- reset(): void;
- notifyResize(): void;
- restyleElement(): void;
-
- readonly table?: Table;
- readonly view?: View;
-}
-
-export type Filters = Array<[string, string, string]>;
-export type Sort = Array<[string, string] | string>;
-export type Expressions = string[];
-export type Aggregates = {[column_name: string]: string};
-export type Pivots = string[];
-export type Columns = string[];
-
-export interface PerspectiveViewerOptions {
- plugin?: string;
- columns?: Columns;
- row_pivots?: Pivots;
- column_pivots?: Pivots;
- aggregates?: Aggregates;
- filter?: Filters;
- sort?: Sort;
- expressions?: Expressions;
- plugin_config?: object;
- editable?: boolean;
- selectable?: boolean;
-}
-
-interface PerspectiveViewerHTMLAttributes extends Pick {
- aggregates?: string;
- expressions?: string;
- row_pivots?: string;
- column_pivots?: string;
- filters?: string;
- sort?: string;
- columns?: string;
-}
-
-interface ReactPerspectiveViewerHTMLAttributes extends PerspectiveViewerHTMLAttributes, React.HTMLAttributes {}
-
-type PerspectiveElement = {class?: string} & React.DetailedHTMLProps, HTMLPerspectiveViewerElement>;
-
-declare global {
- namespace JSX {
- interface IntrinsicElements {
- "perspective-viewer": PerspectiveElement;
- }
- }
-
- interface Document {
- createElement(tagName: "perspective-viewer", options?: ElementCreationOptions): HTMLPerspectiveViewerElement;
- }
-}
diff --git a/rust/perspective-viewer/package.json b/rust/perspective-viewer/package.json
index e6f5973d86..de782a09dd 100644
--- a/rust/perspective-viewer/package.json
+++ b/rust/perspective-viewer/package.json
@@ -19,7 +19,7 @@
"src/**/*",
"index.d.ts"
],
- "typings": "index.d.ts",
+ "types": "dist/esm/index.d.ts",
"scripts": {
"build:wasm": "wasm-pack build --out-dir dist/pkg --target web && rm dist/pkg/package.json",
"build:rollup": "rollup --config rollup.config.js",
@@ -32,6 +32,10 @@
"postbuild": "rimraf pkg/package.json pkg/.gitignore",
"clean": "rimraf dist && rimraf pkg && rimraf target",
"clean:screenshots": "rimraf \"test/screenshots/**/*.@(failed|diff).png\"",
+ "docs": "npm-run-all docs:build docs:concat docs:deploy",
+ "docs:build": "typedoc --hideBreadcrumbs --out dist/docs --readme none --excludePrivate src/ts/index.ts",
+ "docs:concat": "node ./concat-md.js",
+ "docs:deploy": "(echo \"---\nid: perspective\ntitle: perspective-viewer API\n---\n\n\"; cat README.md) > ../../docs/obj/perspective-viewer.md",
"fix": "yarn lint --fix",
"lint": "eslint src examples/*.md examples/*.html",
"test:build:rust": "cpx ../../packages/perspective/dist/umd/perspective.inline.js pkg/",
@@ -47,7 +51,7 @@
},
"dependencies": {
"@finos/perspective": "^0.10.3",
- "mobile-drag-drop": "^2.3.0-rc.2",
+ "mobile-drag-drop-shadow-dom": "3.0.0",
"monaco-editor": "0.24.0",
"monaco-editor-webpack-plugin": "3.1.0"
}
diff --git a/rust/perspective-viewer/rollup.config.js b/rust/perspective-viewer/rollup.config.js
index ba745e45d5..d0a635328c 100644
--- a/rust/perspective-viewer/rollup.config.js
+++ b/rust/perspective-viewer/rollup.config.js
@@ -1,7 +1,7 @@
-import babel from "@rollup/plugin-babel";
import filesize from "rollup-plugin-filesize";
import postcss from "rollup-plugin-postcss";
import sourcemaps from "rollup-plugin-sourcemaps";
+import typescript from "@rollup/plugin-typescript";
import path from "path";
import fs from "fs";
@@ -59,18 +59,15 @@ export default () => {
})
]
},
- {
- input: "src/js/index.js",
- external: [/pkg/, /monaco\-editor/],
+ ...["index", "monaco"].map(name => ({
+ input: `src/ts/${name}.ts`,
+ external: [/pkg/, /node_modules/, /monaco\-editor/],
output: {
sourcemap: true,
dir: "dist/esm/"
},
plugins: [
- babel({
- exclude: "node_modules/**",
- babelHelpers: "bundled"
- }),
+ typescript({tsconfig: "./tsconfig.json"}),
filesize(),
postcss({
inject: false,
@@ -82,7 +79,7 @@ export default () => {
watch: {
clearScreen: false
}
- },
+ })),
...generate_themes()
];
};
diff --git a/rust/perspective-viewer/src/js/dragdrop.js b/rust/perspective-viewer/src/js/dragdrop.js
deleted file mode 100644
index 2ec5e102ea..0000000000
--- a/rust/perspective-viewer/src/js/dragdrop.js
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
-
-Forked from https://github.com/timruffles/mobile-drag-drop/ v2.3.0-rc.2
-
-Copyright (c) 2013 Tim Ruffles
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-const DRAG_DROP_STYLE = `
-.dnd-poly-drag-image {
- opacity: .5 !important;
-}
-.dnd-poly-drag-image.dnd-poly-snapback {
- transition-property: transform, -webkit-transform !important;
- transition-duration: 250ms !important;
- transition-timing-function: ease-out !important;
-}
-`;
-
-const style_elem = document.createElement("style");
-style_elem.textContent = DRAG_DROP_STYLE;
-document.head.appendChild(style_elem);
-
-const CLASS_PREFIX = "dnd-poly-";
-const CLASS_DRAG_IMAGE = CLASS_PREFIX + "drag-image";
-const CLASS_DRAG_IMAGE_SNAPBACK = CLASS_PREFIX + "snapback";
-const CLASS_DRAG_OPERATION_ICON = CLASS_PREFIX + "icon";
-const EVENT_PREFIX = "dnd-poly-";
-const EVENT_DRAG_DRAGSTART_PENDING = EVENT_PREFIX + "dragstart-pending";
-const EVENT_DRAG_DRAGSTART_CANCEL = EVENT_PREFIX + "dragstart-cancel";
-const ALLOWED_EFFECTS = ["none", "copy", "copyLink", "copyMove", "link", "linkMove", "move", "all"];
-const DROP_EFFECTS = ["none", "copy", "move", "link"];
-
-function detectFeatures() {
- const features = {
- dragEvents: "ondragstart" in document.documentElement,
- draggable: "draggable" in document.documentElement,
- userAgentSupportingNativeDnD: undefined
- };
- const isBlinkEngine = !!window.chrome || /chrome/i.test(navigator.userAgent);
- features.userAgentSupportingNativeDnD = !(/iPad|iPhone|iPod|Android/.test(navigator.userAgent) || (isBlinkEngine && "ontouchstart" in document.documentElement));
- return features;
-}
-function supportsPassiveEventListener() {
- let supportsPassiveEventListeners = false;
- try {
- const opts = Object.defineProperty({}, "passive", {
- get: function() {
- supportsPassiveEventListeners = true;
- }
- });
- window.addEventListener("test", null, opts);
- } catch (e) {}
- return supportsPassiveEventListeners;
-}
-
-const supportsPassive = supportsPassiveEventListener();
-function isDOMElement(object) {
- return object && object.tagName;
-}
-function addDocumentListener(ev, handler, passive) {
- if (passive === void 0) {
- passive = true;
- }
- document.addEventListener(ev, handler, supportsPassive ? {passive: passive} : false);
-}
-function removeDocumentListener(ev, handler) {
- document.removeEventListener(ev, handler);
-}
-function onEvt(el, event, handler, capture) {
- if (capture === void 0) {
- capture = false;
- }
- const options = supportsPassive ? {passive: true, capture: capture} : capture;
- el.addEventListener(event, handler, options);
- return {
- off: function() {
- el.removeEventListener(event, handler, options);
- }
- };
-}
-function prepareNodeCopyAsDragImage(srcNode, dstNode) {
- if (srcNode.nodeType === 1) {
- const cs = getComputedStyle(srcNode);
- for (let i = 0; i < cs.length; i++) {
- const csName = cs[i];
- dstNode.style.setProperty(csName, cs.getPropertyValue(csName), cs.getPropertyPriority(csName));
- }
- dstNode.style.pointerEvents = "none";
- dstNode.removeAttribute("id");
- dstNode.removeAttribute("class");
- dstNode.removeAttribute("draggable");
- if (dstNode.nodeName === "CANVAS") {
- const canvasSrc = srcNode;
- const canvasDst = dstNode;
- const canvasSrcImgData = canvasSrc.getContext("2d").getImageData(0, 0, canvasSrc.width, canvasSrc.height);
- canvasDst.getContext("2d").putImageData(canvasSrcImgData, 0, 0);
- }
- }
- if (srcNode.hasChildNodes()) {
- for (let i = 0; i < srcNode.childNodes.length; i++) {
- prepareNodeCopyAsDragImage(srcNode.childNodes[i], dstNode.childNodes[i]);
- }
- }
-}
-function createDragImage(sourceNode) {
- const dragImage = sourceNode.cloneNode(true);
- prepareNodeCopyAsDragImage(sourceNode, dragImage);
- return dragImage;
-}
-function average(array) {
- if (array.length === 0) {
- return 0;
- }
- return (
- array.reduce(function(s, v) {
- return v + s;
- }, 0) / array.length
- );
-}
-function isTouchIdentifierContainedInTouchEvent(touchEvent, touchIdentifier) {
- for (let i = 0; i < touchEvent.changedTouches.length; i++) {
- const touch = touchEvent.changedTouches[i];
- if (touch.identifier === touchIdentifier) {
- return true;
- }
- }
- return false;
-}
-function updateCentroidCoordinatesOfTouchesIn(coordinateProp, event, outPoint) {
- const pageXs = [],
- pageYs = [];
- for (let i = 0; i < event.touches.length; i++) {
- const touch = event.touches[i];
- pageXs.push(touch[coordinateProp + "X"]);
- pageYs.push(touch[coordinateProp + "Y"]);
- }
- outPoint.x = average(pageXs);
- outPoint.y = average(pageYs);
-}
-const TRANSFORM_CSS_VENDOR_PREFIXES = ["", "-webkit-"];
-function extractTransformStyles(sourceNode) {
- return TRANSFORM_CSS_VENDOR_PREFIXES.map(function(prefix) {
- const transform = sourceNode.style[prefix + "transform"];
- if (!transform || transform === "none") {
- return "";
- }
- return transform.replace(/translate\(\D*\d+[^,]*,\D*\d+[^,]*\)\s*/g, "");
- });
-}
-function translateElementToPoint(element, pnt, originalTransforms, offset, centerOnCoordinates) {
- if (centerOnCoordinates === void 0) {
- centerOnCoordinates = true;
- }
- let x = pnt.x,
- y = pnt.y;
- if (offset) {
- x += offset.x;
- y += offset.y;
- }
- if (centerOnCoordinates) {
- x -= parseInt(element.offsetWidth, 10) / 2;
- y -= parseInt(element.offsetHeight, 10) / 2;
- }
- const translate = "translate3d(" + x + "px," + y + "px, 0)";
- for (let i = 0; i < TRANSFORM_CSS_VENDOR_PREFIXES.length; i++) {
- const transformProp = TRANSFORM_CSS_VENDOR_PREFIXES[i] + "transform";
- element.style[transformProp] = translate + " " + originalTransforms[i];
- }
-}
-function applyDragImageSnapback(sourceEl, dragImage, dragImageTransforms, transitionEndCb) {
- const cs = getComputedStyle(sourceEl);
- if (cs.visibility === "hidden" || cs.display === "none") {
- console.log("dnd-poly: source node is not visible. skipping snapback transition.");
- transitionEndCb();
- return;
- }
- dragImage.classList.add(CLASS_DRAG_IMAGE_SNAPBACK);
- const csDragImage = getComputedStyle(dragImage);
- const durationInS = parseFloat(csDragImage.transitionDuration);
- if (isNaN(durationInS) || durationInS === 0) {
- console.log("dnd-poly: no transition used - skipping snapback");
- transitionEndCb();
- return;
- }
- console.log("dnd-poly: starting dragimage snap back");
- const rect = sourceEl.getBoundingClientRect();
- const pnt = {
- x: rect.left,
- y: rect.top
- };
- pnt.x += document.body.scrollLeft || document.documentElement.scrollLeft;
- pnt.y += document.body.scrollTop || document.documentElement.scrollTop;
- pnt.x -= parseInt(cs.marginLeft, 10);
- pnt.y -= parseInt(cs.marginTop, 10);
- const delayInS = parseFloat(csDragImage.transitionDelay);
- const durationInMs = Math.round((durationInS + delayInS) * 1000);
- translateElementToPoint(dragImage, pnt, dragImageTransforms, undefined, false);
- setTimeout(transitionEndCb, durationInMs);
-}
-
-const DataTransfer = (function() {
- function DataTransfer(_dataStore, _setDragImageHandler) {
- this._dataStore = _dataStore;
- this._setDragImageHandler = _setDragImageHandler;
- this._dropEffect = DROP_EFFECTS[0];
- }
- Object.defineProperty(DataTransfer.prototype, "dropEffect", {
- get: function() {
- return this._dropEffect;
- },
- set: function(value) {
- if (this._dataStore.mode !== 0 && ALLOWED_EFFECTS.indexOf(value) > -1) {
- this._dropEffect = value;
- }
- },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(DataTransfer.prototype, "types", {
- get: function() {
- if (this._dataStore.mode !== 0) {
- return Object.freeze(this._dataStore.types);
- }
- },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(DataTransfer.prototype, "effectAllowed", {
- get: function() {
- return this._dataStore.effectAllowed;
- },
- set: function(value) {
- if (this._dataStore.mode === 2 && ALLOWED_EFFECTS.indexOf(value) > -1) {
- this._dataStore.effectAllowed = value;
- }
- },
- enumerable: true,
- configurable: true
- });
- DataTransfer.prototype.setData = function(type, data) {
- if (this._dataStore.mode === 2) {
- if (type.indexOf(" ") > -1) {
- throw new Error("illegal arg: type contains space");
- }
- this._dataStore.data[type] = data;
- if (this._dataStore.types.indexOf(type) === -1) {
- this._dataStore.types.push(type);
- }
- }
- };
- DataTransfer.prototype.getData = function(type) {
- if (this._dataStore.mode === 1 || this._dataStore.mode === 2) {
- return this._dataStore.data[type] || "";
- }
- };
- DataTransfer.prototype.clearData = function(format) {
- if (this._dataStore.mode === 2) {
- if (format && this._dataStore.data[format]) {
- delete this._dataStore.data[format];
- const index = this._dataStore.types.indexOf(format);
- if (index > -1) {
- this._dataStore.types.splice(index, 1);
- }
- return;
- }
- this._dataStore.data = {};
- this._dataStore.types = [];
- }
- };
- DataTransfer.prototype.setDragImage = function(image, x, y) {
- if (this._dataStore.mode === 2) {
- this._setDragImageHandler(image, x, y);
- }
- };
- return DataTransfer;
-})();
-
-function tryFindDraggableTarget(event) {
- let el = event.target;
- do {
- if (el.draggable === false) {
- continue;
- }
- if (el.draggable === true) {
- return el;
- }
- if (el.getAttribute && el.getAttribute("draggable") === "true") {
- return el;
- }
- } while ((el = el.parentNode) && el !== document.body);
-}
-function determineDropEffect(effectAllowed, sourceNode) {
- if (!effectAllowed) {
- if (sourceNode.nodeType === 3 && sourceNode.tagName === "A") {
- return DROP_EFFECTS[3];
- }
- return DROP_EFFECTS[1];
- }
- if (effectAllowed === ALLOWED_EFFECTS[0]) {
- return DROP_EFFECTS[0];
- }
- if (effectAllowed.indexOf(ALLOWED_EFFECTS[1]) === 0 || effectAllowed === ALLOWED_EFFECTS[7]) {
- return DROP_EFFECTS[1];
- }
- if (effectAllowed.indexOf(ALLOWED_EFFECTS[4]) === 0) {
- return DROP_EFFECTS[3];
- }
- if (effectAllowed === ALLOWED_EFFECTS[6]) {
- return DROP_EFFECTS[2];
- }
- return DROP_EFFECTS[1];
-}
-function createDragEventFromTouch(targetElement, e, type, cancelable, window, dataTransfer, relatedTarget) {
- if (relatedTarget === void 0) {
- relatedTarget = null;
- }
- const touch = e.changedTouches[0];
- const dndEvent = new Event(type, {
- bubbles: true,
- cancelable: cancelable
- });
- dndEvent.dataTransfer = dataTransfer;
- dndEvent.relatedTarget = relatedTarget;
- dndEvent.screenX = touch.screenX;
- dndEvent.screenY = touch.screenY;
- dndEvent.clientX = touch.clientX;
- dndEvent.clientY = touch.clientY;
- dndEvent.pageX = touch.pageX;
- dndEvent.pageY = touch.pageY;
- const targetRect = targetElement.getBoundingClientRect();
- dndEvent.offsetX = dndEvent.clientX - targetRect.left;
- dndEvent.offsetY = dndEvent.clientY - targetRect.top;
- return dndEvent;
-}
-function dispatchDragEvent(dragEvent, targetElement, touchEvent, dataStore, dataTransfer, cancelable, relatedTarget) {
- if (cancelable === void 0) {
- cancelable = true;
- }
- if (relatedTarget === void 0) {
- relatedTarget = null;
- }
- console.log("dnd-poly: dispatching " + dragEvent);
- const leaveEvt = createDragEventFromTouch(targetElement, touchEvent, dragEvent, cancelable, document.defaultView, dataTransfer, relatedTarget);
- const cancelled = !targetElement.dispatchEvent(leaveEvt);
- dataStore.mode = 0;
- return cancelled;
-}
-function determineDragOperation(effectAllowed, dropEffect) {
- if (!effectAllowed || effectAllowed === ALLOWED_EFFECTS[7]) {
- return dropEffect;
- }
- if (dropEffect === DROP_EFFECTS[1]) {
- if (effectAllowed.indexOf(DROP_EFFECTS[1]) === 0) {
- return DROP_EFFECTS[1];
- }
- } else if (dropEffect === DROP_EFFECTS[3]) {
- if (effectAllowed.indexOf(DROP_EFFECTS[3]) === 0 || effectAllowed.indexOf("Link") > -1) {
- return DROP_EFFECTS[3];
- }
- } else if (dropEffect === DROP_EFFECTS[2]) {
- if (effectAllowed.indexOf(DROP_EFFECTS[2]) === 0 || effectAllowed.indexOf("Move") > -1) {
- return DROP_EFFECTS[2];
- }
- }
- return DROP_EFFECTS[0];
-}
-
-const DragOperationController = (function() {
- function DragOperationController(_initialEvent, _config, _sourceNode, _dragOperationEndedCb) {
- this._initialEvent = _initialEvent;
- this._config = _config;
- this._sourceNode = _sourceNode;
- this._dragOperationEndedCb = _dragOperationEndedCb;
- this._dragOperationState = 0;
- this._immediateUserSelection = null;
- this._currentDropTarget = null;
- console.log("dnd-poly: setting up potential drag operation..");
- this._lastTouchEvent = _initialEvent;
- this._initialTouch = _initialEvent.changedTouches[0];
- this._touchMoveHandler = this._onTouchMove.bind(this);
- this._touchEndOrCancelHandler = this._onTouchEndOrCancel.bind(this);
- addDocumentListener("touchmove", this._touchMoveHandler, false);
- addDocumentListener("touchend", this._touchEndOrCancelHandler, false);
- addDocumentListener("touchcancel", this._touchEndOrCancelHandler, false);
- }
- DragOperationController.prototype._setup = function() {
- const _this = this;
- console.log("dnd-poly: starting drag and drop operation");
- this._dragOperationState = 1;
- this._currentDragOperation = DROP_EFFECTS[0];
- this._dragDataStore = {
- data: {},
- effectAllowed: undefined,
- mode: 3,
- types: []
- };
- this._currentHotspotCoordinates = {
- x: null,
- y: null
- };
- this._dragImagePageCoordinates = {
- x: null,
- y: null
- };
- let dragImageSrc = this._sourceNode;
- this._dataTransfer = new DataTransfer(this._dragDataStore, function(element, x, y) {
- dragImageSrc = element;
- if (typeof x === "number" || typeof y === "number") {
- _this._dragImageOffset = {
- x: x || 0,
- y: y || 0
- };
- }
- });
- this._dragDataStore.mode = 2;
- this._dataTransfer.dropEffect = DROP_EFFECTS[0];
- if (dispatchDragEvent("dragstart", this._sourceNode, this._lastTouchEvent, this._dragDataStore, this._dataTransfer)) {
- console.log("dnd-poly: dragstart cancelled");
- this._dragOperationState = 3;
- this._cleanup();
- return false;
- }
- updateCentroidCoordinatesOfTouchesIn("page", this._lastTouchEvent, this._dragImagePageCoordinates);
- const dragImage = this._config.dragImageSetup(dragImageSrc);
- this._dragImageTransforms = extractTransformStyles(dragImage);
- dragImage.style.position = "absolute";
- dragImage.style.left = "0px";
- dragImage.style.top = "0px";
- dragImage.style.zIndex = "999999";
- dragImage.classList.add(CLASS_DRAG_IMAGE);
- dragImage.classList.add(CLASS_DRAG_OPERATION_ICON);
- this._dragImage = dragImage;
- if (!this._dragImageOffset) {
- if (this._config.dragImageOffset) {
- this._dragImageOffset = {
- x: this._config.dragImageOffset.x,
- y: this._config.dragImageOffset.y
- };
- } else if (this._config.dragImageCenterOnTouch) {
- const cs = getComputedStyle(dragImageSrc);
- this._dragImageOffset = {
- x: 0 - parseInt(cs.marginLeft, 10),
- y: 0 - parseInt(cs.marginTop, 10)
- };
- } else {
- const targetRect = dragImageSrc.getBoundingClientRect();
- const cs = getComputedStyle(dragImageSrc);
- this._dragImageOffset = {
- x: targetRect.left - this._initialTouch.clientX - parseInt(cs.marginLeft, 10) + targetRect.width / 2,
- y: targetRect.top - this._initialTouch.clientY - parseInt(cs.marginTop, 10) + targetRect.height / 2
- };
- }
- }
- translateElementToPoint(this._dragImage, this._dragImagePageCoordinates, this._dragImageTransforms, this._dragImageOffset, this._config.dragImageCenterOnTouch);
- document.body.appendChild(this._dragImage);
- this._iterationIntervalId = window.setInterval(function() {
- if (_this._iterationLock) {
- console.log("dnd-poly: iteration skipped because previous iteration hast not yet finished.");
- return;
- }
- _this._iterationLock = true;
- _this._dragAndDropProcessModelIteration();
- _this._iterationLock = false;
- }, this._config.iterationInterval);
- return true;
- };
- DragOperationController.prototype._cleanup = function() {
- console.log("dnd-poly: cleanup");
- if (this._iterationIntervalId) {
- clearInterval(this._iterationIntervalId);
- this._iterationIntervalId = null;
- }
- removeDocumentListener("touchmove", this._touchMoveHandler);
- removeDocumentListener("touchend", this._touchEndOrCancelHandler);
- removeDocumentListener("touchcancel", this._touchEndOrCancelHandler);
- if (this._dragImage) {
- this._dragImage.parentNode.removeChild(this._dragImage);
- this._dragImage = null;
- }
- this._dragOperationEndedCb(this._config, this._lastTouchEvent, this._dragOperationState);
- };
- DragOperationController.prototype._onTouchMove = function(event) {
- const _this = this;
- if (isTouchIdentifierContainedInTouchEvent(event, this._initialTouch.identifier) === false) {
- return;
- }
- this._lastTouchEvent = event;
- if (this._dragOperationState === 0) {
- let startDrag = void 0;
- if (this._config.dragStartConditionOverride) {
- try {
- startDrag = this._config.dragStartConditionOverride(event);
- } catch (e) {
- console.error("dnd-poly: error in dragStartConditionOverride hook: " + e);
- startDrag = false;
- }
- } else {
- startDrag = event.touches.length === 1;
- }
- if (!startDrag) {
- this._cleanup();
- return;
- }
- if (this._setup() === true) {
- this._initialEvent.preventDefault();
- event.preventDefault();
- }
- return;
- }
- console.log("dnd-poly: moving draggable..");
- event.preventDefault();
- updateCentroidCoordinatesOfTouchesIn("client", event, this._currentHotspotCoordinates);
- updateCentroidCoordinatesOfTouchesIn("page", event, this._dragImagePageCoordinates);
- if (this._config.dragImageTranslateOverride) {
- try {
- let handledDragImageTranslate_1 = false;
- this._config.dragImageTranslateOverride(
- event,
- {
- x: this._currentHotspotCoordinates.x,
- y: this._currentHotspotCoordinates.y
- },
- this._immediateUserSelection,
- function(offsetX, offsetY) {
- if (!_this._dragImage) {
- return;
- }
- handledDragImageTranslate_1 = true;
- _this._currentHotspotCoordinates.x += offsetX;
- _this._currentHotspotCoordinates.y += offsetY;
- _this._dragImagePageCoordinates.x += offsetX;
- _this._dragImagePageCoordinates.y += offsetY;
- translateElementToPoint(_this._dragImage, _this._dragImagePageCoordinates, _this._dragImageTransforms, _this._dragImageOffset, _this._config.dragImageCenterOnTouch);
- }
- );
- if (handledDragImageTranslate_1) {
- return;
- }
- } catch (e) {
- console.log("dnd-poly: error in dragImageTranslateOverride hook: " + e);
- }
- }
- translateElementToPoint(this._dragImage, this._dragImagePageCoordinates, this._dragImageTransforms, this._dragImageOffset, this._config.dragImageCenterOnTouch);
- };
- DragOperationController.prototype._onTouchEndOrCancel = function(event) {
- if (isTouchIdentifierContainedInTouchEvent(event, this._initialTouch.identifier) === false) {
- return;
- }
- if (this._config.dragImageTranslateOverride) {
- try {
- this._config.dragImageTranslateOverride(undefined, undefined, undefined, function() {});
- } catch (e) {
- console.log("dnd-poly: error in dragImageTranslateOverride hook: " + e);
- }
- }
- if (this._dragOperationState === 0) {
- this._cleanup();
- return;
- }
- event.preventDefault();
- this._dragOperationState = event.type === "touchcancel" ? 3 : 2;
- };
- DragOperationController.prototype._dragAndDropProcessModelIteration = function() {
- const _this = this;
- const previousDragOperation = this._currentDragOperation;
- this._dragDataStore.mode = 3;
- this._dataTransfer.dropEffect = DROP_EFFECTS[0];
- const dragCancelled = dispatchDragEvent("drag", this._sourceNode, this._lastTouchEvent, this._dragDataStore, this._dataTransfer);
- if (dragCancelled) {
- console.log("dnd-poly: drag event cancelled.");
- this._currentDragOperation = DROP_EFFECTS[0];
- }
- if (dragCancelled || this._dragOperationState === 2 || this._dragOperationState === 3) {
- const dragFailed = this._dragOperationEnded(this._dragOperationState);
- if (dragFailed) {
- applyDragImageSnapback(this._sourceNode, this._dragImage, this._dragImageTransforms, function() {
- _this._finishDragOperation();
- });
- return;
- }
- this._finishDragOperation();
- return;
- }
- const newUserSelection = this._config.elementFromPoint(this._currentHotspotCoordinates.x, this._currentHotspotCoordinates.y);
- console.log("dnd-poly: new immediate user selection is: " + newUserSelection);
- const previousTargetElement = this._currentDropTarget;
- if (newUserSelection !== this._immediateUserSelection && newUserSelection !== this._currentDropTarget) {
- this._immediateUserSelection = newUserSelection;
- if (this._currentDropTarget !== null) {
- this._dragDataStore.mode = 3;
- this._dataTransfer.dropEffect = DROP_EFFECTS[0];
- dispatchDragEvent("dragexit", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false);
- }
- if (this._immediateUserSelection === null) {
- this._currentDropTarget = this._immediateUserSelection;
- console.log("dnd-poly: current drop target changed to null");
- } else {
- this._dragDataStore.mode = 3;
- this._dataTransfer.dropEffect = determineDropEffect(this._dragDataStore.effectAllowed, this._sourceNode);
- if (dispatchDragEvent("dragenter", this._immediateUserSelection, this._lastTouchEvent, this._dragDataStore, this._dataTransfer)) {
- console.log("dnd-poly: dragenter default prevented");
- this._currentDropTarget = this._immediateUserSelection;
- this._currentDragOperation = determineDragOperation(this._dataTransfer.effectAllowed, this._dataTransfer.dropEffect);
- } else {
- if (this._immediateUserSelection !== document.body) {
- this._currentDropTarget = document.body;
- }
- }
- }
- }
- if (previousTargetElement !== this._currentDropTarget && isDOMElement(previousTargetElement)) {
- console.log("dnd-poly: current drop target changed.");
- this._dragDataStore.mode = 3;
- this._dataTransfer.dropEffect = DROP_EFFECTS[0];
- dispatchDragEvent("dragleave", previousTargetElement, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false, this._currentDropTarget);
- }
- if (isDOMElement(this._currentDropTarget)) {
- this._dragDataStore.mode = 3;
- this._dataTransfer.dropEffect = determineDropEffect(this._dragDataStore.effectAllowed, this._sourceNode);
- if (dispatchDragEvent("dragover", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer) === false) {
- console.log("dnd-poly: dragover not prevented on possible drop-target.");
- this._currentDragOperation = DROP_EFFECTS[0];
- } else {
- console.log("dnd-poly: dragover prevented.");
- this._currentDragOperation = determineDragOperation(this._dataTransfer.effectAllowed, this._dataTransfer.dropEffect);
- }
- }
- console.log("dnd-poly: d'n'd iteration ended. current drag operation: " + this._currentDragOperation);
- if (previousDragOperation !== this._currentDragOperation) {
- this._dragImage.classList.remove(CLASS_PREFIX + previousDragOperation);
- }
- const currentDragOperationClass = CLASS_PREFIX + this._currentDragOperation;
- this._dragImage.classList.add(currentDragOperationClass);
- };
- DragOperationController.prototype._dragOperationEnded = function(state) {
- console.log("dnd-poly: drag operation end detected with " + this._currentDragOperation);
- const dragFailed = this._currentDragOperation === DROP_EFFECTS[0] || this._currentDropTarget === null || state === 3;
- if (dragFailed) {
- if (isDOMElement(this._currentDropTarget)) {
- this._dragDataStore.mode = 3;
- this._dataTransfer.dropEffect = DROP_EFFECTS[0];
- dispatchDragEvent("dragleave", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false);
- }
- } else {
- if (isDOMElement(this._currentDropTarget)) {
- this._dragDataStore.mode = 1;
- this._dataTransfer.dropEffect = this._currentDragOperation;
- if (dispatchDragEvent("drop", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer) === true) {
- this._currentDragOperation = this._dataTransfer.dropEffect;
- } else {
- this._currentDragOperation = DROP_EFFECTS[0];
- }
- }
- }
- return dragFailed;
- };
- DragOperationController.prototype._finishDragOperation = function() {
- console.log("dnd-poly: dragimage snap back transition ended");
- this._dragDataStore.mode = 3;
- this._dataTransfer.dropEffect = this._currentDragOperation;
- dispatchDragEvent("dragend", this._sourceNode, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false);
- this._dragOperationState = 2;
- this._cleanup();
- };
- return DragOperationController;
-})();
-
-const config = {
- iterationInterval: 150,
- tryFindDraggableTarget: tryFindDraggableTarget,
- dragImageSetup: createDragImage,
- elementFromPoint: function(x, y) {
- return document.elementFromPoint(x, y);
- }
-};
-let activeDragOperation;
-function onTouchstart(e, composePath) {
- console.log("dnd-poly: global touchstart");
- if (activeDragOperation) {
- console.log("dnd-poly: drag operation already active");
- return;
- }
- const dragTarget = config.tryFindDraggableTarget(e, composePath);
- if (!dragTarget) {
- console.log("dnd-poly: no draggable at touchstart coordinates");
- return;
- }
- try {
- activeDragOperation = new DragOperationController(e, config, dragTarget, dragOperationEnded);
- } catch (err) {
- dragOperationEnded(config, e, 3);
- throw err;
- }
-}
-function onDelayTouchstart(evt) {
- console.log("dnd-poly: setup delayed dragstart..");
- const el = evt.target;
- const composePath = evt.composedPath();
- const heldItem = function() {
- console.log("dnd-poly: starting delayed drag..");
- end.off();
- cancel.off();
- move.off();
- scroll.off();
- onTouchstart(evt, composePath);
- };
- const onReleasedItem = function(event) {
- console.log("dnd-poly: aborting delayed drag because of " + event.type);
- end.off();
- cancel.off();
- move.off();
- scroll.off();
- if (el) {
- el.dispatchEvent(new CustomEvent(EVENT_DRAG_DRAGSTART_CANCEL, {bubbles: true, cancelable: true}));
- }
- clearTimeout(timer);
- };
- if (el) {
- el.dispatchEvent(new CustomEvent(EVENT_DRAG_DRAGSTART_PENDING, {bubbles: true, cancelable: true}));
- }
- const timer = window.setTimeout(heldItem, config.holdToDrag);
- const end = onEvt(el, "touchend", onReleasedItem);
- const cancel = onEvt(el, "touchcancel", onReleasedItem);
- const move = onEvt(el, "touchmove", onReleasedItem);
- const scroll = onEvt(window, "scroll", onReleasedItem, true);
-}
-
-function dragOperationEnded(_config, event, state) {
- if (state === 0) {
- console.log("dnd-poly: Drag never started. Last event was " + event.type);
- if (_config.defaultActionOverride) {
- try {
- _config.defaultActionOverride(event);
- if (event.defaultPrevented) {
- console.log("dnd-poly: defaultActionOverride has taken care of triggering the default action. preventing default on original event");
- }
- } catch (e) {
- console.log("dnd-poly: error in defaultActionOverride: " + e);
- }
- }
- }
- activeDragOperation = null;
-}
-
-function polyfill(override) {
- if (override) {
- Object.keys(override).forEach(function(key) {
- config[key] = override[key];
- });
- }
- if (!config.forceApply) {
- const detectedFeatures = detectFeatures();
- if (detectedFeatures.userAgentSupportingNativeDnD && detectedFeatures.draggable && detectedFeatures.dragEvents) {
- return false;
- }
- }
- console.log("dnd-poly: Applying mobile drag and drop polyfill.");
- if (config.holdToDrag) {
- console.log("dnd-poly: holdToDrag set to " + config.holdToDrag);
- addDocumentListener("touchstart", onDelayTouchstart, false);
- } else {
- addDocumentListener("touchstart", onTouchstart, false);
- }
- return true;
-}
-
-function tryFindDraggableTarget_override(event, composePath) {
- const cp = composePath || event.composedPath();
- for (let o of cp) {
- let el = o;
- do {
- if (el.draggable === false) {
- continue;
- }
- if (el.getAttribute && el.getAttribute("draggable") === "true") {
- return el;
- }
- } while ((el = el.parentNode) && el !== document.body);
- }
-}
-
-function elementFromPoint(x, y) {
- for (let o of this._path) {
- if (o.elementFromPoint) {
- let el = o.elementFromPoint(x, y);
- if (el) {
- while (el.shadowRoot) {
- el = el.shadowRoot.elementFromPoint(x, y);
- }
- return el;
- }
- }
- }
-}
-
-function dragStartConditionOverride(event) {
- this._path = event.composedPath();
- return true;
-}
-
-window.addEventListener("touchmove", function() {});
-
-polyfill({
- tryFindDraggableTarget: tryFindDraggableTarget_override,
- elementFromPoint: elementFromPoint,
- dragStartConditionOverride: dragStartConditionOverride,
- holdToDrag: 500
-});
diff --git a/rust/perspective-viewer/src/js/index.js b/rust/perspective-viewer/src/js/index.js
deleted file mode 100644
index bf60baf4ef..0000000000
--- a/rust/perspective-viewer/src/js/index.js
+++ /dev/null
@@ -1,143 +0,0 @@
-/******************************************************************************
- *
- * Copyright (c) 2018, the Perspective Authors.
- *
- * This file is part of the Perspective library, distributed under the terms
- * of the Apache License 2.0. The full license can be found in the LICENSE
- * file.
- *
- */
-
-import "./dragdrop.js";
-import init, * as internal from "../pkg/perspective_viewer.js";
-
-const WASM_INTERNAL = import(
- /* webpackChunkName: "perspective-viewer.custom-element" */
- /* webpackMode: "eager" */
- "../pkg/perspective_viewer_bg.wasm"
-);
-
-async function init_wasm() {
- const {default: wasm_internal} = await WASM_INTERNAL;
- await init(wasm_internal);
- internal.set_panic_hook();
- return internal;
-}
-
-export const wasm = init_wasm();
-
-let _index = undefined;
-async function _await_index(f) {
- await new Promise(setTimeout);
- if (!_index) {
- _index = await wasm;
- }
- return f();
-}
-
-class PerspectiveViewerElement extends HTMLElement {
- constructor() {
- super();
- _await_index(() => {
- this._instance = new _index.PerspectiveViewerElement(this);
- });
- }
-
- connectedCallback() {
- _await_index(() => {
- this._instance.connected_callback();
- });
- }
-
- static registerPlugin(name) {
- _await_index(() => {
- _index.register_plugin(name);
- });
- }
-
- load(table) {
- return _await_index(() => this._instance.js_load(table));
- }
-
- notifyResize() {
- return _await_index(() => this._instance.js_resize());
- }
-
- getTable() {
- return _await_index(() => this._instance.js_get_table());
- }
-
- restore(...args) {
- return _await_index(() => this._instance.js_restore(...args));
- }
-
- flush() {
- return _await_index(() => this._instance.js_flush());
- }
-
- reset() {
- return _await_index(() => this._instance.js_reset());
- }
-
- save(...args) {
- return _await_index(() => this._instance.js_save(...args));
- }
-
- delete() {
- return _await_index(() => this._instance.js_delete());
- }
-
- download(...args) {
- return _await_index(() => this._instance.js_download(...args));
- }
-
- copy(...args) {
- return _await_index(() => this._instance.js_copy(...args));
- }
-
- getEditPort() {
- return _await_index(() => console.error("Not Implemented"));
- }
-
- setThrottle(...args) {
- return _await_index(() => this._instance.js_set_throttle(...args));
- }
-
- toggleConfig(force) {
- return _await_index(() => this._instance.js_toggle_config(force));
- }
-
- get_plugin(name) {
- return _await_index(() => this._instance.js_get_plugin(name));
- }
-
- get_all_plugins() {
- return _await_index(() => this._instance.js_get_all_plugins());
- }
-}
-
-if (document.createElement("perspective-viewer").constructor === HTMLElement) {
- window.customElements.define("perspective-viewer", PerspectiveViewerElement);
-}
-
-class PerspectiveColumnStyleElement extends HTMLElement {
- constructor() {
- super();
- }
-
- open(target, config, default_config) {
- _await_index(() => {
- if (this._instance) {
- this._instance.reset(config, default_config);
- } else {
- this._instance = new _index.PerspectiveColumnStyleElement(this, config, default_config);
- }
-
- this._instance.open(target);
- });
- }
-}
-
-if (document.createElement("perspective-column-style").constructor === HTMLElement) {
- window.customElements.define("perspective-column-style", PerspectiveColumnStyleElement);
-}
diff --git a/rust/perspective-viewer/src/js/monaco.js b/rust/perspective-viewer/src/js/monaco.js
deleted file mode 100644
index fd42d7e72f..0000000000
--- a/rust/perspective-viewer/src/js/monaco.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/******************************************************************************
- *
- * Copyright (c) 2018, the Perspective Authors.
- *
- * This file is part of the Perspective library, distributed under the terms
- * of the Apache License 2.0. The full license can be found in the LICENSE
- * file.
- *
- */
-
-import "monaco-editor/esm/vs/editor/browser/controller/coreCommands.js";
-import "monaco-editor/esm/vs/editor/browser/widget/codeEditorWidget.js";
-import "monaco-editor/esm/vs/editor/browser/widget/diffEditorWidget.js";
-import "monaco-editor/esm/vs/editor/browser/widget/diffNavigator.js";
-import "monaco-editor/esm/vs/editor/contrib/anchorSelect/anchorSelect.js";
-import "monaco-editor/esm/vs/editor/contrib/bracketMatching/bracketMatching.js";
-import "monaco-editor/esm/vs/editor/contrib/caretOperations/caretOperations.js";
-import "monaco-editor/esm/vs/editor/contrib/caretOperations/transpose.js";
-import "monaco-editor/esm/vs/editor/contrib/clipboard/clipboard.js";
-import "monaco-editor/esm/vs/editor/contrib/codeAction/codeActionContributions.js";
-import "monaco-editor/esm/vs/editor/contrib/codelens/codelensController.js";
-import "monaco-editor/esm/vs/editor/contrib/colorPicker/colorContributions.js";
-import "monaco-editor/esm/vs/editor/contrib/comment/comment.js";
-import "monaco-editor/esm/vs/editor/contrib/contextmenu/contextmenu.js";
-import "monaco-editor/esm/vs/editor/contrib/cursorUndo/cursorUndo.js";
-import "monaco-editor/esm/vs/editor/contrib/dnd/dnd.js";
-import "monaco-editor/esm/vs/editor/contrib/documentSymbols/documentSymbols.js";
-import "monaco-editor/esm/vs/editor/contrib/find/findController.js";
-import "monaco-editor/esm/vs/editor/contrib/folding/folding.js";
-import "monaco-editor/esm/vs/editor/contrib/fontZoom/fontZoom.js";
-import "monaco-editor/esm/vs/editor/contrib/format/formatActions.js";
-import "monaco-editor/esm/vs/editor/contrib/gotoError/gotoError.js";
-import "monaco-editor/esm/vs/editor/contrib/gotoSymbol/goToCommands.js";
-import "monaco-editor/esm/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.js";
-import "monaco-editor/esm/vs/editor/contrib/hover/hover.js";
-import "monaco-editor/esm/vs/editor/contrib/inPlaceReplace/inPlaceReplace.js";
-import "monaco-editor/esm/vs/editor/contrib/indentation/indentation.js";
-import "monaco-editor/esm/vs/editor/contrib/inlineHints/inlineHintsController.js";
-import "monaco-editor/esm/vs/editor/contrib/linesOperations/linesOperations.js";
-import "monaco-editor/esm/vs/editor/contrib/linkedEditing/linkedEditing.js";
-import "monaco-editor/esm/vs/editor/contrib/links/links.js";
-import "monaco-editor/esm/vs/editor/contrib/multicursor/multicursor.js";
-import "monaco-editor/esm/vs/editor/contrib/parameterHints/parameterHints.js";
-import "monaco-editor/esm/vs/editor/contrib/rename/rename.js";
-import "monaco-editor/esm/vs/editor/contrib/smartSelect/smartSelect.js";
-import "monaco-editor/esm/vs/editor/contrib/snippet/snippetController2.js";
-import "monaco-editor/esm/vs/editor/contrib/suggest/suggestController.js";
-import "monaco-editor/esm/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.js";
-import "monaco-editor/esm/vs/editor/contrib/unusualLineTerminators/unusualLineTerminators.js";
-import "monaco-editor/esm/vs/editor/contrib/viewportSemanticTokens/viewportSemanticTokens.js";
-import "monaco-editor/esm/vs/editor/contrib/wordHighlighter/wordHighlighter.js";
-import "monaco-editor/esm/vs/editor/contrib/wordOperations/wordOperations.js";
-import "monaco-editor/esm/vs/editor/contrib/wordPartOperations/wordPartOperations.js";
-import "monaco-editor/esm/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.js";
-import "monaco-editor/esm/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.js";
-import "monaco-editor/esm/vs/editor/standalone/browser/inspectTokens/inspectTokens.js";
-import "monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.js";
-import "monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.js";
-import "monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.js";
-import "monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.js";
-import "monaco-editor/esm/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.js";
-import "monaco-editor/esm/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.js";
diff --git a/rust/perspective-viewer/src/rust/config/filters.rs b/rust/perspective-viewer/src/rust/config/filters.rs
index e33f69cdf3..433157a3e8 100644
--- a/rust/perspective-viewer/src/rust/config/filters.rs
+++ b/rust/perspective-viewer/src/rust/config/filters.rs
@@ -46,6 +46,9 @@ pub enum FilterOp {
#[serde(rename = "contains")]
Contains,
+ #[serde(rename = "not in")]
+ NotIn,
+
#[serde(rename = "in")]
In,
@@ -88,6 +91,7 @@ impl Display for FilterOp {
let op = match self {
FilterOp::Contains => "contains",
FilterOp::In => "in",
+ FilterOp::NotIn => "not in",
FilterOp::BeginsWith => "begins with",
FilterOp::EndsWith => "ends with",
FilterOp::IsNull => "is null",
@@ -112,6 +116,7 @@ impl FromStr for FilterOp {
match input {
"contains" => Ok(FilterOp::Contains),
"in" => Ok(FilterOp::In),
+ "not in" => Ok(FilterOp::NotIn),
"begins with" => Ok(FilterOp::BeginsWith),
"ends with" => Ok(FilterOp::EndsWith),
"is null" => Ok(FilterOp::IsNull),
diff --git a/rust/perspective-viewer/src/rust/js/monaco.rs b/rust/perspective-viewer/src/rust/js/monaco.rs
index fc69b6f0d7..87a8cb70d9 100644
--- a/rust/perspective-viewer/src/rust/js/monaco.rs
+++ b/rust/perspective-viewer/src/rust/js/monaco.rs
@@ -41,7 +41,7 @@ extern "C" {
return import(
/* webpackChunkName: \"monaco-exts\" */
/* webpackMode: \"eager\" */
- '../../../../src/js/monaco.js'
+ '../../../../dist/esm/monaco.js'
);
}
")
diff --git a/rust/perspective-viewer/src/ts/index.ts b/rust/perspective-viewer/src/ts/index.ts
new file mode 100644
index 0000000000..e20bc6026c
--- /dev/null
+++ b/rust/perspective-viewer/src/ts/index.ts
@@ -0,0 +1,526 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2018, the Perspective Authors.
+ *
+ * This file is part of the Perspective library, distributed under the terms
+ * of the Apache License 2.0. The full license can be found in the LICENSE
+ * file.
+ *
+ */
+
+/**
+ * Module for the `` custom element. This module has no
+ * (real) exports, but importing it has a side effect: the
+ * `PerspectiveViewerElement`class is registered as a custom element, after
+ * which it can be used as a standard DOM element.
+ *
+ * Though `` is written mostly in Rust, the nature
+ * of WebAssembly's compilation makes it a dynamic module; in order to
+ * guarantee that the Custom Elements extension methods are registered
+ * synchronously with this package's import, we need perform said registration
+ * within this wrapper module.
+ *
+ * The documentation in this module defines the instance structure of a
+ * `` DOM object instantiated typically, through HTML or any
+ * relevent DOM method e.g. `document.createElement("perspective-viewer")` or
+ * `document.getElementsByTagName("perspective-viewer")`.
+ *
+ * @module perspective-viewer
+ */
+
+import "mobile-drag-drop-shadow-dom";
+import init, * as internal from "../../dist/pkg/perspective_viewer.js";
+import * as perspective from "@finos/perspective";
+
+// There is no way to provide a default rejection handler within a promise and
+// also not lock the await-er, so this module attaches a global handler to
+// filter out cancelled query messages.
+window.addEventListener("unhandledrejection", event => {
+ if (event.reason?.message === "View method cancelled") {
+ event.preventDefault();
+ }
+});
+
+async function init_wasm({default: wasm_module}): Promise {
+ await init(wasm_module);
+ internal.set_panic_hook();
+ return internal;
+}
+
+const WASM_MODULE = import(
+ /* webpackChunkName: "perspective-viewer.custom-element" */
+ /* webpackMode: "eager" */
+ "../../dist/pkg/perspective_viewer_bg.wasm"
+).then(init_wasm);
+
+export type PerspectiveViewerConfig = perspective.ViewConfig & {
+ plugin?: string;
+ settings?: boolean;
+ plugin_config?: object;
+};
+
+/**
+ * The Custom Elements implementation for ``, as well at its
+ * API. `PerspectiveViewerElement` should not be constructed directly (like its
+ * parent class `HTMLElement`); instead, use `document.createElement()` or
+ * declare your `` element in HTML. Once instantiated,
+ * `` works just like a standard `HTMLElement`, with a few
+ * extra perspective-specific methods.
+ *
+ * @example
+ * ```javascript
+ * const viewer = document.createElement("perspective-viewer");
+ * ```
+ * @example
+ * ```javascript
+ * document.body.innerHTML = `
+ *
+ * `;
+ * const viewer = document.body.querySelector("#viewer");
+ * ```
+ * @noInheritDoc
+ */
+export class PerspectiveViewerElement extends HTMLElement {
+ private instance: internal.PerspectiveViewerElement;
+
+ /**
+ * Should not be called directly (will throw `TypeError: Illegal
+ * constructor`).
+ * @ignore
+ */
+ constructor() {
+ super();
+ this.load_wasm();
+ }
+
+ private async load_wasm(): Promise {
+ const module = await WASM_MODULE;
+ if (!this.instance) {
+ this.instance = new module.PerspectiveViewerElement(this);
+ }
+ }
+
+ /**
+ * Part of the Custom Elements API. This method is called by the browser,
+ * and should not be called directly by applications.
+ *
+ * @ignore
+ */
+ async connectedCallback(): Promise {
+ await this.load_wasm();
+ this.instance.connected_callback();
+ }
+
+ /**
+ * Register a new plugin via its custom element name. This method is called
+ * automatically as a side effect of importing a plugin module, so this
+ * method should only typically be called by plugin authors.
+ *
+ * @category Plugin
+ * @param name The `name` of the custom element to register, as supplied
+ * to the `customElements.define(name)` method.
+ */
+ static async registerPlugin(name): Promise {
+ const module = await WASM_MODULE;
+ module.register_plugin(name);
+ }
+
+ /**
+ * Load a `perspective.Table`. If `load` or `update` have already been
+ * called on this element, its internal `perspective.Table` will _not_ be
+ * deleted, but it will bed de-referenced by this ``.
+ *
+ * @category Data
+ * @param data A `Promise` which resolves to the `perspective.Table`
+ * @returns {Promise} A promise which resolves once the data is
+ * loaded, a `perspective.View` has been created, and the active plugin has
+ * rendered.
+ * @example Load perspective.table
+ * ```javascript
+ * const my_viewer = document.getElementById('#my_viewer');
+ * const tbl = perspective.table("x,y\n1,a\n2,b");
+ * my_viewer.load(tbl);
+ * ```
+ * @example Load Promise
+ * ```javascript
+ * const my_viewer = document.getElementById('#my_viewer');
+ * const tbl = perspective.table("x,y\n1,a\n2,b");
+ * my_viewer.load(tbl);
+ * ```
+ */
+ async load(table: Promise): Promise {
+ await this.load_wasm();
+ await this.instance.js_load(table);
+ }
+
+ /**
+ * Redraw this `` and plugin when its dimensions or
+ * visibility have been updated. This method _must_ be called in these
+ * cases, and will not by default respond to dimension or style changes to
+ * its parent container. `notifyResize()` does not recalculate the current
+ * `View`, but all plugins will re-request the data window (which itself
+ * may be smaller or larger due to resize).
+ *
+ * @category Util
+ * @returns A `Promise` which resolves when this resize event has
+ * finished rendering.
+ * @example Bind `notfyResize()` to browser dimensions
+ * ```javascript
+ * const viewer = document.querySelector("perspective-viewer");
+ * window.addEventListener("resize", () => viewer.notifyResize());
+ * ```
+ */
+ async notifyResize(): Promise {
+ await this.load_wasm();
+ await this.instance.js_resize();
+ }
+
+ /**
+ * Returns the `perspective.Table()` which was supplied to `load()`. If
+ * `load()` has been called but the supplied `Promise`
+ * has not resolved, `getTable()` will `await`; if `load()` has not yet
+ * been called, an `Error` will be thrown.
+ *
+ * @category Data
+ * @returns A `Promise` which resolves to a `perspective.Table`
+ * @example Share a `Table`
+ * ```javascript
+ * const viewers = document.querySelectorAll("perspective-viewer");
+ * const [viewer1, viewer2] = Array.from(viewers);
+ * const table = await viewer1.getTable();
+ * await viewer2.load(table);
+ * ```
+ */
+ async getTable(): Promise {
+ await this.load_wasm();
+ const table = await this.instance.js_get_table();
+ return table;
+ }
+
+ /**
+ * Restore this element to a state as generated by a reciprocal call to
+ * `save`. In `json` (default) format, `PerspectiveViewerConfig`'s fields
+ * have specific semantics:
+ *
+ * - When a key is missing, this field is ignored; ``
+ * will maintain whatever settings for this field is currently applied.
+ * - When the key is supplied, but the value is `undefined`, the field is
+ * reset to its default value for this current `View`, i.e. the state it
+ * would be in after `load()` resolves.
+ * - When the key is defined to a value, the value is applied for this
+ * field.
+ *
+ * This behavior is convenient for explicitly controlling current vs desired
+ * UI state in a single request, but it does make it a bit inconvenient to
+ * use `restore()` to reset a `` to default as you must
+ * do so explicitly for each key; for this case, use `reset()` instead of
+ * restore.
+ *
+ * As noted in `save()`, this configuration state does not include the
+ * `Table` or its `Schema`. In order for `restore()` to work correctly, it
+ * must be called on a `` that has a `Table already
+ * `load()`-ed, with the same (or a type-compatible superset) `Schema`.
+ * It does not need have the same rows, or even be populated.
+ *
+ * @category Persistence
+ * @param config returned by `save()`. This can be any format returned by
+ * `save()`; the specific deserialization is chosen by `typeof config`.
+ * @returns A promise which resolves when the changes have been applied and
+ * rendered.
+ * @example Restore a viewer from `localStorage`
+ * ```javascript
+ * const viewer = document.querySelector("perspective-viewer");
+ * const token = localStorage.getItem("viewer_state");
+ * await viewer.restore(token);
+ * ```
+ */
+ async restore(config: PerspectiveViewerConfig | string | ArrayBuffer): Promise {
+ await this.load_wasm();
+ await this.instance.js_restore(config);
+ }
+
+ /**
+ * Serialize this element's attribute/interaction state, but _not_ the
+ * `perspective.Table` or its `Schema`. `save()` is designed to be used in
+ * conjunction with `restore()` to persist user settings and bookmarks, but
+ * the `PerspectiveViewerConfig` object returned in `json` format can also
+ * be written by hand quite easily, which is useful for authoring
+ * pre-conceived configs.
+ *
+ * @category Persistence
+ * @param format The serialization format - `json` (JavaScript object),
+ * `arraybuffer` or `string`. `restore()` uses the returned config's type
+ * to infer format.
+ * @returns a serialized element in the chosen format.
+ * @example Save a viewer to `localStorage`
+ * ```javascript
+ * const viewer = document.querySelector("perspective-viewer");
+ * const token = await viewer.save("string");
+ * localStorage.setItem("viewer_state", token);
+ * ```
+ */
+ async save(): Promise;
+ async save(format: "json"): Promise;
+ async save(format: "arraybuffer"): Promise;
+ async save(format: "string"): Promise;
+ async save(format?: "json" | "arraybuffer" | "string"): Promise {
+ await this.load_wasm();
+ const config = await this.instance.js_save(format);
+ return config;
+ }
+
+ /**
+ * Flush any pending modifications to this ``. Since
+ * ``'s API is almost entirely `async`, it may take
+ * some milliseconds before any method call such as `restore()` affects
+ * the rendered element. If you want to make sure any invoked method which
+ * affects the rendered has had its results rendered, call and await
+ * `flush()`
+ *
+ * @category Util
+ * @returns {Promise} A promise which resolves when the current
+ * pending state changes have been applied and rendered.
+ * @example Flush an unawaited `restore()`
+ * ```javascript
+ * const viewer = document.querySelector("perspective-viewer");
+ * viewer.restore({row_pivots: ["State"]});
+ * await viewer.flush();
+ * console.log("Viewer has been rendered with a pivot!");
+ * ```
+ */
+ async flush(): Promise {
+ await this.load_wasm();
+ await this.instance.js_flush();
+ }
+
+ /**
+ * Reset's this element's view state and attributes to default. Does not
+ * delete this element's `perspective.table` or otherwise modify the data
+ * state.
+ *
+ * @category Persistence
+ * @example
+ * ```javascript
+ * const viewer = document.querySelector("perspective-viewer");
+ * await viewer.reset();
+ * ```
+ */
+ async reset(): Promise {
+ await this.load_wasm();
+ await this.instance.js_reset();
+ }
+
+ /**
+ * Deletes this element and clears it's internal state (but not its
+ * user state). This (or the underlying `perspective.view`'s equivalent
+ * method) must be called in order for its memory to be reclaimed, as well
+ * as the reciprocal method on the `perspective.table` which this viewer is
+ * bound to.
+ *
+ * @category Util
+ */
+ async delete(): Promise {
+ await this.load_wasm();
+ await this.instance.js_delete();
+ }
+
+ /**
+ * Download this element's data as a CSV file.
+ *
+ * @category UI Action
+ * @param flat Whether to use the element's current view
+ * config, or to use a default "flat" view.
+ */
+ async download(flat: boolean): Promise {
+ await this.load_wasm();
+ await this.instance.js_download(flat);
+ }
+
+ /**
+ * Copies this element's view data (as a CSV) to the clipboard. This method
+ * must be called from an event handler, subject to the browser's
+ * restrictions on clipboard access. See
+ * {@link https://www.w3.org/TR/clipboard-apis/#allow-read-clipboard}.
+ *
+ * @category UI Action
+ * @param flat Whether to use the element's current view
+ * config, or to use a default "flat" view.
+ * @example
+ * ```javascript
+ * const viewer = document.querySelector("perspective-viewer");
+ * const button = document.querySelector("button");
+ * button.addEventListener("click", async () => {
+ * await viewer.copy();
+ * });
+ * ```
+ */
+ async copy(flat: boolean): Promise {
+ await this.load_wasm();
+ await this.instance.js_copy(flat);
+ }
+
+ /**
+ * Restyles the elements and to pick up any style changes. While most of
+ * perspective styling is plain CSS and can be updated at any time, some
+ * CSS rules are read and cached, e.g. the series colors for
+ * `@finos/perspective-viewer-d3fc` which are read from CSS then reapplied
+ * as SVG and Canvas attributes.
+ *
+ * @category Util
+ */
+ async restyleElement(): Promise {
+ console.error("Not Implemented");
+ }
+
+ /**
+ * Gets the edit port, the port number for which `Table` updates from this
+ * `` are generated. This port number will be present
+ * in the options object for a `View.on_update()` callback for any update
+ * which was originated by the ``/user, which can be
+ * used to distinguish server-originated updates from user edits.
+ *
+ * @category Util
+ * @returns A promise which resolves to the current edit port.
+ * @example
+ * ```javascript
+ * const viewer = document.querySelector("perspective-viewer");
+ * const editport = await viewer.getEditPort();
+ * const table = await viewer.getTable();
+ * const view = await table.view();
+ * view.on_update(obj => {
+ * if (obj.port_id = editport) {
+ * console.log("User edit detected");
+ * }
+ * });
+ * ```
+ */
+ async getEditPort(): Promise {
+ console.error("Not Implemented");
+ return -1;
+ }
+
+ /**
+ * Determines the render throttling behavior. Can be an integer, for
+ * millisecond window to throttle render event; or, if `undefined`,
+ * will try to determine the optimal throttle time from this component's
+ * render framerate.
+ *
+ * @category Util
+ * @param value an optional throttle rate in milliseconds (integer). If not
+ * supplied, adaptive throttling is calculated from the average plugin
+ * render time.
+ * @example Limit FPS to 1 frame per second
+ * ```javascript
+ * await viewer.setThrottle(1000);
+ * ```
+ */
+ async setThrottle(value?: number): Promise {
+ await this.load_wasm();
+ await this.instance.js_set_throttle(value);
+ }
+
+ /**
+ * Opens/closes the element's config menu, equivalent to clicking the
+ * settings button in the UI. This method is equivalent to
+ * `viewer.restore({settings: force})` when `force` is present, but
+ * `restore()` cannot toggle as `toggleConfig()` can, you would need to
+ * first read the settings state from `save()` otherwise.
+ *
+ * Calling `toggleConfig()` may be delayed if an async render is currently
+ * in process, and it may only partially render the UI if `load()` has not
+ * yet resolved.
+ *
+ * @category UI Action
+ * @param force If supplied, explicitly set the config state to "open"
+ * (`true`) or "closed" (`false`).
+ * @example
+ * ```javascript
+ * await viewer.toggleConfig();
+ * ```
+ */
+ async toggleConfig(force?: boolean): Promise {
+ await this.load_wasm();
+ await this.instance.js_toggle_config(force);
+ }
+
+ /**
+ * Get the currently active plugin custom element instance, or a specific
+ * named instance if requested. `getPlugin(name)` does not activate the
+ * plugin requested, so if this plugin is not active the returned
+ * `HTMLElement` will not have a `parentElement`.
+ *
+ * If no plugins have been registered (via `registerPlugin()`), calling
+ * `getPlugin()` will cause `perspective-viewer-debug` to be registered as a
+ * side effect.
+ *
+ * @category Plugin
+ * @param name Optionally a specific plugin name, defaulting to the current
+ * active plugin.
+ * @returns The active or requested plugin instance.
+ */
+ async getPlugin(name): Promise {
+ await this.load_wasm();
+ const plugin = await this.instance.js_get_plugin(name);
+ return plugin;
+ }
+
+ /**
+ * Get all plugin custom element instances, in order of registration.
+ *
+ * If no plugins have been registered (via `registerPlugin()`), calling
+ * `getAllPlugins()` will cause `perspective-viewer-debug` to be registered
+ * as a side effect.
+ *
+ * @category Plugin
+ * @returns An `Array` of the plugin instances for this
+ * ``.
+ */
+ async getAllPlugins(): Promise> {
+ await this.load_wasm();
+ const plugins = await this.instance.js_get_all_plugins();
+ return plugins;
+ }
+}
+
+if (document.createElement("perspective-viewer").constructor === HTMLElement) {
+ window.customElements.define("perspective-viewer", PerspectiveViewerElement);
+}
+
+class PerspectiveColumnStyleElement extends HTMLElement {
+ private instance: internal.PerspectiveColumnStyleElement;
+
+ constructor() {
+ super();
+ }
+
+ async open(target: HTMLElement, config: any, default_config: any): Promise {
+ if (this.instance) {
+ this.instance.reset(config, default_config);
+ } else {
+ this.instance = new internal.PerspectiveColumnStyleElement(this, config, default_config);
+ }
+
+ this.instance.open(target);
+ }
+}
+
+if (document.createElement("perspective-column-style").constructor === HTMLElement) {
+ window.customElements.define("perspective-column-style", PerspectiveColumnStyleElement);
+}
+
+type ReactPerspectiveViewerAttributes = React.HTMLAttributes;
+
+type JsxPerspectiveViewerElement = {class?: string} & React.DetailedHTMLProps, PerspectiveViewerElement>;
+
+declare global {
+ // eslint-disable-next-line @typescript-eslint/no-namespace
+ namespace JSX {
+ interface IntrinsicElements {
+ "perspective-viewer": JsxPerspectiveViewerElement;
+ }
+ }
+
+ interface Document {
+ createElement(tagName: "perspective-viewer", options?: ElementCreationOptions): PerspectiveViewerElement;
+ }
+}
diff --git a/rust/perspective-viewer/src/ts/monaco.ts b/rust/perspective-viewer/src/ts/monaco.ts
new file mode 100644
index 0000000000..2b4e000792
--- /dev/null
+++ b/rust/perspective-viewer/src/ts/monaco.ts
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2018, the Perspective Authors.
+ *
+ * This file is part of the Perspective library, distributed under the terms
+ * of the Apache License 2.0. The full license can be found in the LICENSE
+ * file.
+ *
+ */
+
+ import "monaco-editor/esm/vs/editor/browser/controller/coreCommands.js";
+ import "monaco-editor/esm/vs/editor/browser/widget/codeEditorWidget.js";
+ import "monaco-editor/esm/vs/editor/browser/widget/diffEditorWidget.js";
+ import "monaco-editor/esm/vs/editor/browser/widget/diffNavigator.js";
+ import "monaco-editor/esm/vs/editor/contrib/anchorSelect/anchorSelect.js";
+ import "monaco-editor/esm/vs/editor/contrib/bracketMatching/bracketMatching.js";
+ import "monaco-editor/esm/vs/editor/contrib/caretOperations/caretOperations.js";
+ import "monaco-editor/esm/vs/editor/contrib/caretOperations/transpose.js";
+ import "monaco-editor/esm/vs/editor/contrib/clipboard/clipboard.js";
+ import "monaco-editor/esm/vs/editor/contrib/codeAction/codeActionContributions.js";
+ import "monaco-editor/esm/vs/editor/contrib/codelens/codelensController.js";
+ import "monaco-editor/esm/vs/editor/contrib/colorPicker/colorContributions.js";
+ import "monaco-editor/esm/vs/editor/contrib/comment/comment.js";
+ import "monaco-editor/esm/vs/editor/contrib/contextmenu/contextmenu.js";
+ import "monaco-editor/esm/vs/editor/contrib/cursorUndo/cursorUndo.js";
+ import "monaco-editor/esm/vs/editor/contrib/dnd/dnd.js";
+ import "monaco-editor/esm/vs/editor/contrib/documentSymbols/documentSymbols.js";
+ import "monaco-editor/esm/vs/editor/contrib/find/findController.js";
+ import "monaco-editor/esm/vs/editor/contrib/folding/folding.js";
+ import "monaco-editor/esm/vs/editor/contrib/fontZoom/fontZoom.js";
+ import "monaco-editor/esm/vs/editor/contrib/format/formatActions.js";
+ import "monaco-editor/esm/vs/editor/contrib/gotoError/gotoError.js";
+ import "monaco-editor/esm/vs/editor/contrib/gotoSymbol/goToCommands.js";
+ import "monaco-editor/esm/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.js";
+ import "monaco-editor/esm/vs/editor/contrib/hover/hover.js";
+ import "monaco-editor/esm/vs/editor/contrib/inPlaceReplace/inPlaceReplace.js";
+ import "monaco-editor/esm/vs/editor/contrib/indentation/indentation.js";
+ import "monaco-editor/esm/vs/editor/contrib/inlineHints/inlineHintsController.js";
+ import "monaco-editor/esm/vs/editor/contrib/linesOperations/linesOperations.js";
+ import "monaco-editor/esm/vs/editor/contrib/linkedEditing/linkedEditing.js";
+ import "monaco-editor/esm/vs/editor/contrib/links/links.js";
+ import "monaco-editor/esm/vs/editor/contrib/multicursor/multicursor.js";
+ import "monaco-editor/esm/vs/editor/contrib/parameterHints/parameterHints.js";
+ import "monaco-editor/esm/vs/editor/contrib/rename/rename.js";
+ import "monaco-editor/esm/vs/editor/contrib/smartSelect/smartSelect.js";
+ import "monaco-editor/esm/vs/editor/contrib/snippet/snippetController2.js";
+ import "monaco-editor/esm/vs/editor/contrib/suggest/suggestController.js";
+ import "monaco-editor/esm/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.js";
+ import "monaco-editor/esm/vs/editor/contrib/unusualLineTerminators/unusualLineTerminators.js";
+ import "monaco-editor/esm/vs/editor/contrib/viewportSemanticTokens/viewportSemanticTokens.js";
+ import "monaco-editor/esm/vs/editor/contrib/wordHighlighter/wordHighlighter.js";
+ import "monaco-editor/esm/vs/editor/contrib/wordOperations/wordOperations.js";
+ import "monaco-editor/esm/vs/editor/contrib/wordPartOperations/wordPartOperations.js";
+ import "monaco-editor/esm/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.js";
+ import "monaco-editor/esm/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.js";
+ import "monaco-editor/esm/vs/editor/standalone/browser/inspectTokens/inspectTokens.js";
+ import "monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.js";
+ import "monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.js";
+ import "monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.js";
+ import "monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.js";
+ import "monaco-editor/esm/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.js";
+ import "monaco-editor/esm/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.js";
+
\ No newline at end of file
diff --git a/rust/perspective-viewer/test/results/results.json b/rust/perspective-viewer/test/results/results.json
index 58a93351fa..03f0fbfac6 100644
--- a/rust/perspective-viewer/test/results/results.json
+++ b/rust/perspective-viewer/test/results/results.json
@@ -3,7 +3,7 @@
"superstore.html/doesn't leak elements.": "d0fd18b3d4d7c183c5ed155b4bf37972",
"superstore.html/doesn't leak views when setting row pivots.": "54daaa4bbbe59f6ed4acc301ba871bab",
"superstore.html/doesn't leak views when setting filters.": "6dfc1e505f1428424c3265f0236f22fc",
- "__GIT_COMMIT__": "a3256b28c3261b64d89ddc993298a8d049c39886",
+ "__GIT_COMMIT__": "9a0427a1de46d2da89ee3d5290d0baba3fd31aa2",
"blank.html/Handles reloading with a schema.": "e58c62f6e0ff16dc4d753f99e0fc39c3",
"superstore_shows_a_grid_without_any_settings_applied_": "ae1c4690d978598ca14c8669244ce604",
"superstore_Responsive_Layout_shows_horizontal_columns_on_small_vertical_viewports_": "57ba3ad341cf8a0e4df6ab96715ff2a0",
diff --git a/rust/perspective-viewer/tsconfig.json b/rust/perspective-viewer/tsconfig.json
new file mode 100644
index 0000000000..99954ff72c
--- /dev/null
+++ b/rust/perspective-viewer/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "module": "esnext",
+ "target": "es2018",
+ "declaration": true,
+ "outDir": "dist/esm",
+ "rootDir": "src/ts",
+ "allowSyntheticDefaultImports": true,
+ "moduleResolution": "node"
+ },
+ "files": [
+ "src/ts/index.ts",
+ "src/ts/monaco.ts"
+ ]
+}
diff --git a/yarn.lock b/yarn.lock
index 31a6845650..9093ffee77 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2864,6 +2864,14 @@
is-module "^1.0.0"
resolve "^1.19.0"
+"@rollup/plugin-typescript@^8.2.5":
+ version "8.2.5"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.2.5.tgz#e0319761b2b5105615e5a0c371ae05bc2984b7de"
+ integrity sha512-QL/LvDol/PAGB2O0S7/+q2HpSUNodpw7z6nGn9BfoVCPOZ0r4EALrojFU29Bkoi2Hr2jgTocTejJ5GGWZfOxbQ==
+ dependencies:
+ "@rollup/pluginutils" "^3.1.0"
+ resolve "^1.17.0"
+
"@rollup/pluginutils@^3.0.9", "@rollup/pluginutils@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
@@ -6004,11 +6012,6 @@ csstype@^3.0.2, csstype@~3.0.3:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.6.tgz#865d0b5833d7d8d40f4e5b8a6d76aea3de4725ef"
integrity sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==
-cuint@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b"
- integrity sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=
-
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@@ -8539,6 +8542,18 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, gl
once "^1.3.0"
path-is-absolute "^1.0.0"
+glob@^7.1.7:
+ version "7.1.7"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
+ integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
global-modules@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
@@ -8734,6 +8749,18 @@ handlebars@^4.0.11, handlebars@^4.7.6:
optionalDependencies:
uglify-js "^3.1.4"
+handlebars@^4.7.7:
+ version "4.7.7"
+ resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
+ integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
+ dependencies:
+ minimist "^1.2.5"
+ neo-async "^2.6.0"
+ source-map "^0.6.1"
+ wordwrap "^1.0.0"
+ optionalDependencies:
+ uglify-js "^3.1.4"
+
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
@@ -10743,6 +10770,13 @@ json5@^1.0.1:
dependencies:
minimist "^1.2.0"
+json5@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
+ integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
+ dependencies:
+ minimist "^1.2.5"
+
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
@@ -11317,6 +11351,11 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
+lunr@^2.3.9:
+ version "2.3.9"
+ resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1"
+ integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==
+
macos-release@^2.2.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.4.1.tgz#64033d0ec6a5e6375155a74b1a1eba8e509820ac"
@@ -11337,7 +11376,7 @@ make-dir@^2.0.0, make-dir@^2.1.0:
pify "^4.0.1"
semver "^5.6.0"
-make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0, make-dir@~3.1.0:
+make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
@@ -11459,6 +11498,11 @@ marked@^1.1.1:
resolved "https://registry.yarnpkg.com/marked/-/marked-1.2.7.tgz#6e14b595581d2319cdcf033a24caaf41455a01fb"
integrity sha512-No11hFYcXr/zkBvL6qFmAp1z6BKY3zqLMHny/JN/ey+al7qwCM2+CMBL9BOgqMxZU36fz4cCWfn2poWIf7QRXA==
+marked@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/marked/-/marked-3.0.2.tgz#60ce97d6aec34dd882ab4bb4df82494666854e17"
+ integrity sha512-TMJQQ79Z0e3rJYazY0tIoMsFzteUGw9fB3FD+gzuIT3zLuG9L9ckIvUfF51apdJkcqc208jJN2KbtPbOvXtbjA==
+
math-expression-evaluator@^1.2.14:
version "1.3.7"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.3.7.tgz#1b62225db86af06f7ea1fd9576a34af605a5b253"
@@ -11646,11 +11690,6 @@ mime@^2.4.4:
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.7.tgz#962aed9be0ed19c91fd7dc2ece5d7f4e89a90d74"
integrity sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==
-mime@~2.5.2:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe"
- integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
-
mimic-fn@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
@@ -11685,7 +11724,7 @@ minimalistic-assert@^1.0.0:
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
-minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2, minimatch@~3.0.4:
+minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -11844,10 +11883,10 @@ mkdirp@0.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.5, mkdirp@~0.5.1:
dependencies:
minimist "^1.2.5"
-mobile-drag-drop@^2.3.0-rc.2:
- version "2.3.0-rc.2"
- resolved "https://registry.yarnpkg.com/mobile-drag-drop/-/mobile-drag-drop-2.3.0-rc.2.tgz#00d6e85e04512a620fd5357366e8786bd29aa7aa"
- integrity sha512-4rHP0PUeWkSp0O3waNHPQZCHeZnLu8bE59MerWOnZJ249BCyICXL1WWp3xqkMKXEDFYuhfk3bS42bKB9IeN9uw==
+mobile-drag-drop-shadow-dom@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/mobile-drag-drop-shadow-dom/-/mobile-drag-drop-shadow-dom-3.0.0.tgz#f91014af66a0331338d4dfef30ecc5ddcb5a0687"
+ integrity sha512-cNDH83lfYhllESH+ddjyxXdnjunLec0ldnygm3nWY1zMtfeA1tHoVsAasZy63QhnRuN4ps0pGuL8TolUK/sYjA==
modify-values@^1.0.0:
version "1.0.1"
@@ -12535,6 +12574,13 @@ onetime@^5.1.0, onetime@^5.1.2:
dependencies:
mimic-fn "^2.1.0"
+onigasm@^2.2.5:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/onigasm/-/onigasm-2.2.5.tgz#cc4d2a79a0fa0b64caec1f4c7ea367585a676892"
+ integrity sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==
+ dependencies:
+ lru-cache "^5.1.1"
+
open@^6.3.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9"
@@ -13254,14 +13300,6 @@ postcss-convert-values@^4.0.1:
postcss "^7.0.0"
postcss-value-parser "^3.0.0"
-postcss-copy-assets@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/postcss-copy-assets/-/postcss-copy-assets-0.3.1.tgz#f64275406966e48d02e7617d31b2aae7f921d944"
- integrity sha1-9kJ1QGlm5I0C52F9MbKq5/kh2UQ=
- dependencies:
- mkdirp "^0.5.1"
- postcss "^5.0.2"
-
postcss-discard-comments@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d"
@@ -13326,20 +13364,6 @@ postcss-discard-unused@^2.2.1:
postcss "^5.0.14"
uniqs "^2.0.0"
-postcss-easy-import@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/postcss-easy-import/-/postcss-easy-import-3.0.0.tgz#8eaaf5ae59566083d0cae98735dfd803e3ab194d"
- integrity sha512-cfNsear/v8xlkl9v5Wm8y4Do/puiDQTFF+WX2Fo++h7oKt1fKWVVW/5Ca8hslYDQWnjndrg813cA23Pt1jsYdg==
- dependencies:
- globby "^6.1.0"
- is-glob "^4.0.0"
- lodash "^4.17.4"
- object-assign "^4.0.1"
- pify "^3.0.0"
- postcss "^6.0.11"
- postcss-import "^10.0.0"
- resolve "^1.1.7"
-
postcss-filter-plugins@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz#82245fdf82337041645e477114d8e593aa18b8ec"
@@ -13347,22 +13371,6 @@ postcss-filter-plugins@^2.0.0:
dependencies:
postcss "^5.0.4"
-postcss-font-grabber@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/postcss-font-grabber/-/postcss-font-grabber-3.0.2.tgz#6ec0cc4b2296f9d2a94f5f6a09367d9076e3f20c"
- integrity sha512-zt4JD9W6oThxxs1VFyzRCdHhsLzz5tuoPpNr22ZlSYPpaV3dPXXDuGQSo9hXASvTm4ATN6X2x6GS/1eGI2rqLg==
-
-postcss-import@^10.0.0:
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-10.0.0.tgz#4c85c97b099136cc5ea0240dc1dfdbfde4e2ebbe"
- integrity sha1-TIXJewmRNsxeoCQNwd/b/eTi674=
- dependencies:
- object-assign "^4.0.1"
- postcss "^6.0.1"
- postcss-value-parser "^3.2.3"
- read-cache "^1.0.0"
- resolve "^1.1.7"
-
postcss-load-config@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.0.0.tgz#f1312ddbf5912cd747177083c5ef7a19d62ee484"
@@ -13837,16 +13845,6 @@ postcss-unique-selectors@^4.0.1:
postcss "^7.0.0"
uniqs "^2.0.0"
-postcss-url@^10.1.3:
- version "10.1.3"
- resolved "https://registry.yarnpkg.com/postcss-url/-/postcss-url-10.1.3.tgz#54120cc910309e2475ec05c2cfa8f8a2deafdf1e"
- integrity sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==
- dependencies:
- make-dir "~3.1.0"
- mime "~2.5.2"
- minimatch "~3.0.4"
- xxhashjs "~0.2.2"
-
postcss-value-parser@^3.0.0, postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
@@ -13885,7 +13883,7 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0
source-map "^0.5.6"
supports-color "^3.2.3"
-postcss@^6.0.1, postcss@^6.0.11:
+postcss@^6.0.1:
version "6.0.23"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324"
integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==
@@ -13996,7 +13994,7 @@ progress@2.0.1:
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.1.tgz#c9242169342b1c29d275889c95734621b1952e31"
integrity sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==
-progress@^2.0.0:
+progress@^2.0.0, progress@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
@@ -14358,13 +14356,6 @@ react@16.8.6, react@^16.8.4, react@^16.8.6, react@^17.0.1:
prop-types "^15.6.2"
scheduler "^0.13.6"
-read-cache@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
- integrity sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=
- dependencies:
- pify "^2.3.0"
-
read-cmd-shim@^1.0.1:
version "1.0.5"
resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz#87e43eba50098ba5a32d0ceb583ab8e43b961c16"
@@ -15369,6 +15360,15 @@ shellwords@^0.1.1:
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
+shiki@^0.9.8:
+ version "0.9.10"
+ resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.9.10.tgz#feb8d4938b5dd71c5c8b1c1c7cd28fbbd37da087"
+ integrity sha512-xeM7Oc6hY+6iW5O/T5hor8ul7mEprzyl5y4r5zthEHToQNw7MIhREMgU3r2gKDB0NaMLNrkcEQagudCdzE13Lg==
+ dependencies:
+ json5 "^2.2.0"
+ onigasm "^2.2.5"
+ vscode-textmate "5.2.0"
+
signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
@@ -16751,10 +16751,41 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-typescript@^3.7.4:
- version "3.9.7"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
- integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
+typedoc-default-themes@^0.12.10:
+ version "0.12.10"
+ resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.12.10.tgz#614c4222fe642657f37693ea62cad4dafeddf843"
+ integrity sha512-fIS001cAYHkyQPidWXmHuhs8usjP5XVJjWB8oZGqkTowZaz3v7g3KDZeeqE82FBrmkAnIBOY3jgy7lnPnqATbA==
+
+typedoc-plugin-markdown@^3.10.4:
+ version "3.10.4"
+ resolved "https://registry.yarnpkg.com/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.10.4.tgz#4e0e9c584a1e421beafa4c3666896615f069da6b"
+ integrity sha512-if9w7S9fXLg73AYi/EoRSEhTOZlg3I8mIP8YEmvzSE33VrNXC9/hA0nVcLEwFVJeQY7ay6z67I6kW0KIv7LjeA==
+ dependencies:
+ handlebars "^4.7.7"
+
+typedoc-plugin-no-inherit@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/typedoc-plugin-no-inherit/-/typedoc-plugin-no-inherit-1.3.0.tgz#8fd3b01d7fe48767bd827f933ff53e00f90005c0"
+ integrity sha512-Om4yu8sDHkHWi6FcOYUbg6fv2jh7kS51xbuZ/zs4VEtO5bJwTkO8FlzRUyDrTA3puxvF9XcoottntD0mpEgULg==
+
+typedoc@^0.21.9:
+ version "0.21.9"
+ resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.21.9.tgz#6fbdc7152024a00f03af53a0ca40f44e91f0f129"
+ integrity sha512-VRo7aII4bnYaBBM1lhw4bQFmUcDQV8m8tqgjtc7oXl87jc1Slbhfw2X5MccfcR2YnEClHDWgsiQGgNB8KJXocA==
+ dependencies:
+ glob "^7.1.7"
+ handlebars "^4.7.7"
+ lunr "^2.3.9"
+ marked "^3.0.2"
+ minimatch "^3.0.0"
+ progress "^2.0.3"
+ shiki "^0.9.8"
+ typedoc-default-themes "^0.12.10"
+
+typescript@4.3.3:
+ version "4.3.3"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.3.tgz#5401db69bd3203daf1851a1a74d199cb3112c11a"
+ integrity sha512-rUvLW0WtF7PF2b9yenwWUi9Da9euvDRhmH7BLyBG4DCFfOJ850LGNknmRpp8Z8kXNUPObdZQEfKOiHtXuQHHKA==
typestyle@^2.0.4:
version "2.1.0"
@@ -17160,6 +17191,11 @@ vfile@^2.0.0:
unist-util-stringify-position "^1.0.0"
vfile-message "^1.0.0"
+vscode-textmate@5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e"
+ integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==
+
w3c-hr-time@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
@@ -17671,13 +17707,6 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
-xxhashjs@~0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8"
- integrity sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==
- dependencies:
- cuint "^0.2.2"
-
y18n@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4"