diff --git a/docs/README.md b/docs/README.md
index 1303f5851..379aa52d3 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -3,8 +3,16 @@ id: introduction
title: Introduction
---
-## What is nebula.js?
+
+
+
-`nebula.js` is a collection of JavaScript libraries, visualizations and CLIs that helps developers build and integrate visualizations on top of Qlik's Associative Engine.
+## Nebula.js documentation
-The collection is organized under the `@nebula.js` scope in the form of npm packages. The primary package is `@nebula.js/stardust` which contains APIs for integrating existing visualizations with mashups, as well as APIs for building custom visualizations.
+You can find the documentation on [Qlik's developer portal](https://qlik.dev/libraries-and-tools/nebulajs).
+
+To quickly get started, check out the tutorial on how to [embed visualization into your own web app](https://qlik.dev/tutorials/build-a-simple-mashup-using-nebulajs).
+
+You can also walk through the tutorial on how to [build your own extension](https://qlik.dev/tutorials/build-a-helloworld-extension-using-nebulajs).
+
+Explore the full [stardust API reference](https://qlik.dev/apis/javascript/nebulajs-stardust).
diff --git a/docs/api-reference.md b/docs/api-reference.md
deleted file mode 100644
index fd44478dd..000000000
--- a/docs/api-reference.md
+++ /dev/null
@@ -1,978 +0,0 @@
----
-id: api-reference
-title: API Reference
----
-
-# @nebula.js/stardust
-
-> version: 0.6.0-alpha.0
-
-## Table of contents
-
-- [function: embed(app[, instanceConfig])](#function-embedapp-instanceconfig)
- - [embed.createConfiguration(configuration)](#embedcreateconfigurationconfiguration)
-- [function: useState(initialState)](#function-usestateinitialstate)
-- [function: useEffect(effect[, deps])](#function-useeffecteffect-deps)
-- [function: useMemo(factory, deps)](#function-usememofactory-deps)
-- [function: usePromise(factory[, deps])](#function-usepromisefactory-deps)
-- [function: useElement()](#function-useelement)
-- [function: useRect()](#function-userect)
-- [function: useLayout()](#function-uselayout)
-- [function: useStaleLayout()](#function-usestalelayout)
-- [function: useAppLayout()](#function-useapplayout)
-- [function: useModel()](#function-usemodel)
-- [function: useApp()](#function-useapp)
-- [function: useGlobal()](#function-useglobal)
-- [function: useSelections()](#function-useselections)
-- [function: useTheme()](#function-usetheme)
-- [function: useTranslator()](#function-usetranslator)
-- [function: useAction(factory[, deps])](#function-useactionfactory-deps)
-- [function: useConstraints()](#function-useconstraints)
-- [function: useOptions()](#function-useoptions)
-- [function: onTakeSnapshot(snapshotCallback)](#function-ontakesnapshotsnapshotcallback)
-- [interface: Context](#interface-context)
-- [interface: Configuration](#interface-configuration)
-- [undefined: Galaxy.translator](#undefined-galaxytranslator)
-- [undefined: Galaxy.flags](#undefined-galaxyflags)
-- [undefined: Galaxy.anything](#undefined-galaxyanything)
-- [class: Embed](#class-embed)
- - [embed.render(cfg)](#embedrendercfg)
- - [embed.context(ctx)](#embedcontextctx)
- - [embed.selections()](#embedselections)
-- [interface: ThemeInfo](#interface-themeinfo)
-- [class: SupernovaController](#class-supernovacontroller)
- - [supernovaController.destroy()](#supernovacontrollerdestroy)
-- [interface: Flags](#interface-flags)
-- [interface: CreateConfig](#interface-createconfig)
-- [interface: BaseConfig](#interface-baseconfig)
-- [interface: GetConfig](#interface-getconfig)
-- [type Field = <[string]|`EngineAPI.INxDimension`|`EngineAPI.INxMeasure`|[LibraryField]>](#type-field-stringqaenxdimensionqaenxmeasurelibraryfield)
-- [interface: LibraryField](#interface-libraryfield)
-- [class: AppSelections](#class-appselections)
- - [appSelections.mount(element)](#appselectionsmountelement)
- - [appSelections.unmount()](#appselectionsunmount)
-- [class: ObjectSelections](#class-objectselections)
- - [objectSelections.begin(paths)](#objectselectionsbeginpaths)
- - [objectSelections.clear()](#objectselectionsclear)
- - [objectSelections.confirm()](#objectselectionsconfirm)
- - [objectSelections.cancel()](#objectselectionscancel)
- - [objectSelections.select(s)](#objectselectionsselects)
- - [objectSelections.canClear()](#objectselectionscanclear)
- - [objectSelections.canConfirm()](#objectselectionscanconfirm)
- - [objectSelections.canCancel()](#objectselectionscancancel)
- - [objectSelections.isActive()](#objectselectionsisactive)
- - [objectSelections.isModal()](#objectselectionsismodal)
- - [objectSelections.goModal(paths)](#objectselectionsgomodalpaths)
- - [objectSelections.noModal([accept])](#objectselectionsnomodalaccept)
- - [objectSelections.abortModal()](#objectselectionsabortmodal)
-- [interface: LoadType(type)](#interface-loadtypetype)
-- [interface: TypeInfo](#interface-typeinfo)
-- [interface: Supernova(galaxy)](#interface-supernovagalaxy)
-- [interface: SupernovaDefinition](#interface-supernovadefinition)
-- [interface: SetStateFn(newState)](#interface-setstatefnnewstate)
-- [type EffectCallback = <[Function]>](#type-effectcallback-function)
-- [interface: Rect](#interface-rect)
-- [interface: ActionDefinition](#interface-actiondefinition)
-- [interface: Constraints](#interface-constraints)
-- [interface: QAEDefinition](#interface-qaedefinition)
-- [interface: DataTarget](#interface-datatarget)
-- [interface: FieldTarget](#interface-fieldtarget)
-- [class: Translator](#class-translator)
- - [translator.add(item)](#translatoradditem)
- - [translator.get(str[, args])](#translatorgetstr-args)
-- [class: Theme](#class-theme)
- - [theme.getDataColorScales()](#themegetdatacolorscales)
- - [theme.getDataColorPalettes()](#themegetdatacolorpalettes)
- - [theme.getDataColorPickerPalettes()](#themegetdatacolorpickerpalettes)
- - [theme.getDataColorSpecials()](#themegetdatacolorspecials)
- - [theme.getColorPickerColor(c)](#themegetcolorpickercolorc)
- - [theme.getContrastingColorTo(color)](#themegetcontrastingcolortocolor)
- - [theme.getStyle(basePath, path, attribute)](#themegetstylebasepath-path-attribute)
- - [interface: ScalePalette](#interface-scalepalette)
- - [interface: DataPalette](#interface-datapalette)
- - [interface: ColorPickerPalette](#interface-colorpickerpalette)
- - [interface: DataColorSpecials](#interface-datacolorspecials)
-
-## API
-
-### function: embed(app[, instanceConfig])
-
-- `app` <`EngineAPI.IApp`>
-- `instanceConfig` <[Configuration]>
-- `returns:` <[Embed]>
-
-Initiates a new embed instance using the specified `app`.
-
-```js
-import { embed } from '@nebula.js/stardust';
-const n = embed(app);
-n.render({ id: 'abc' });
-```
-
-#### embed.createConfiguration(configuration)
-
-- `configuration` <[Configuration]> The configuration object
-- `returns:` <[Embed]>
-
-Creates a new `embed` scope bound to the specified `configuration`.
-
-The configuration is merged with all previous scopes.
-
-```js
-import { embed } from '@nebula.js/stardust';
-// create a 'master' config which registers all types
-const m = embed.createConfiguration({
- types: [
- {
- name: 'mekko',
- version: '1.0.0',
- load: () => Promise.resolve(mekko),
- },
- ],
-});
-
-// create an alternate config with dark theme
-// and inherit the config from the previous
-const d = m.createConfiguration({
- context: {
- theme: 'dark',
- },
-});
-
-m(app).render({ type: 'mekko' }); // will render the object with default theme
-d(app).render({ type: 'mekko' }); // will render the object with 'dark' theme
-embed(app).render({ type: 'mekko' }); // will throw error since 'mekko' is not a register type on the default instance
-```
-
-### function: useState(initialState)
-
-- `initialState` <`S`|[Function]> The initial state.
-- `returns:` <[Array]> The value and a function to update it.
-
-Creates a stateful value.
-
-```js
-import { useState } from '@nebula.js/stardust';
-// ...
-// initiate with simple primitive value
-const [zoomed, setZoomed] = useState(false);
-
-// update
-setZoomed(true);
-
-// lazy initiation
-const [value, setValue] = useState(() => heavy());
-```
-
-### function: useEffect(effect[, deps])
-
-- `effect` <[EffectCallback]> The callback.
-- `deps` <[Array]<`any`>> The dependencies which should trigger the callback.
-
-Triggers a callback function when a dependent value changes.
-
-```js
-import { useEffect } from '@nebula.js/stardust';
-// ...
-useEffect(() => {
- console.log('mounted');
- return () => {
- console.log('unmounted');
- };
-}, []);
-```
-
-### function: useMemo(factory, deps)
-
-- `factory` <[Function]> The factory function.
-- `deps` <[Array]<`any`>> The dependencies.
-- `returns:` <`T`> The value returned from the factory function.
-
-Creates a stateful value when a dependent changes.
-
-```js
-import { useMemo } from '@nebula.js/stardust';
-// ...
-const v = useMemo(() => {
- return doSomeHeavyCalculation();
-}), []);
-```
-
-### function: usePromise(factory[, deps])
-
-- `factory` <[Function]> The factory function that calls the promise.
-- `deps` <[Array]<`any`>> The dependencies.
-- `returns:` <[Array]> The resolved value.
-
-Runs a callback function when a dependent changes.
-
-```js
-import { usePromise } from '@nebula.js/stardust';
-import { useModel } from '@nebula.js/stardust';
-// ...
-const model = useModel();
-const [resolved, rejected] = usePromise(() => model.getLayout(), []);
-```
-
-### function: useElement()
-
-- `returns:` <`HTMLElement`>
-
-Gets the HTMLElement this supernova is rendered into.
-
-```js
-import { useElement } from '@nebula.js/stardust';
-// ...
-const el = useElement();
-el.innerHTML = 'Hello!';
-```
-
-### function: useRect()
-
-- `returns:` <[Rect]> The size of the element.
-
-Gets the size of the HTMLElement the supernova is rendered into.
-
-```js
-import { useRect } from '@nebula.js/stardust';
-// ...
-const rect = useRect();
-useEffect(() => {
- console.log('resize');
-}, [rect.width, rect.height]);
-```
-
-### function: useLayout()
-
-- `returns:` <`EngineAPI.IGenericObjectLayout`>
-
-Gets the layout of the generic object associated with this supernova.
-
-```js
-import { useLayout } from '@nebula.js/stardust';
-// ...
-const layout = useLayout();
-console.log(layout);
-```
-
-### function: useStaleLayout()
-
-- `returns:` <`EngineAPI.IGenericObjectLayout`>
-
-Gets the layout of the generic object associated with this supernova.
-
-Unlike the regular layout, a _stale_ layout is not changed when a generic object enters
-the modal state. This is mostly notable in that `qSelectionInfo.qInSelections` in the layout is
-always `false`.
-The returned value from `useStaleLayout()` and `useLayout()` are identical when the object
-is not in a modal state.
-
-```js
-import { useStaleLayout } from '@nebula.js/stardust';
-// ...
-const staleLayout = useStaleLayout();
-console.log(staleLayout);
-```
-
-### function: useAppLayout()
-
-- `returns:` <`EngineAPI.INxAppLayout`> The app layout
-
-Gets the layout of the app associated with this supernova.
-
-```js
-import { useAppLayout } from '@nebula.js/stardust';
-// ...
-const appLayout = useAppLayout();
-console.log(appLayout.qLocaleInfo);
-```
-
-### function: useModel()
-
-- `returns:` <`EngineAPI.IGenericObject`|`undefined`>
-
-Gets the generic object API of the generic object connected to this supernova.
-
-```js
-import { useModel } from '@nebula.js/stardust';
-// ...
-const model = useModel();
-useEffect(() => {
- model.getInfo().then((info) => {
- console.log(info);
- });
-}, []);
-```
-
-### function: useApp()
-
-- `returns:` <`EngineAPI.IApp`|`undefined`> The doc API.
-
-Gets the doc API.
-
-```js
-import { useApp } from '@nebula.js/stardust';
-// ...
-const app = useApp();
-useEffect(() => {
- app.getAllInfos().then((infos) => {
- console.log(infos);
- });
-}, []);
-```
-
-### function: useGlobal()
-
-- `returns:` <`EngineAPI.IGlobal`|`undefined`> The global API.
-
-Gets the global API.
-
-```js
-import { useGlobal } from '@nebula.js/stardust';
-
-// ...
-const g = useGlobal();
-useEffect(() => {
- g.engineVersion().then((version) => {
- console.log(version);
- });
-}, []);
-```
-
-### function: useSelections()
-
-- `returns:` <[ObjectSelections]> The object selections.
-
-Gets the object selections.
-
-```js
-import { useSelections } from '@nebula.js/stardust';
-import { useElement } from '@nebula.js/stardust';
-import { useEffect } from '@nebula.js/stardust';
-// ...
-const selections = useSelections();
-const element = useElement();
-useEffect(() => {
- const onClick = () => {
- selections.begin('/qHyperCubeDef');
- };
- element.addEventListener('click', onClick);
- return () => {
- element.removeEventListener('click', onClick);
- };
-}, []);
-```
-
-### function: useTheme()
-
-- `returns:` <[Theme]> The theme.
-
-Gets the theme.
-
-```js
-import { useTheme } from '@nebula.js/stardust';
-
-const theme = useTheme();
-console.log(theme.getContrastinColorTo('#ff0000'));
-```
-
-### function: useTranslator()
-
-- `returns:` <[Translator]> The translator.
-
-Gets the translator.
-
-```js
-import { useTranslator } from '@nebula.js/stardust';
-// ...
-const translator = useTranslator();
-console.log(translator.get('SomeString'));
-```
-
-### function: useAction(factory[, deps])
-
-- `factory` <[Function]>
-- `deps` <[Array]<`any`>>
-- `returns:` <`A`>
-
-Registers a custom action.
-
-```js
-import { useAction } from '@nebula.js/stardust';
-// ...
-const [zoomed, setZoomed] = useState(false);
-const act = useAction(
- () => ({
- hidden: false,
- disabled: zoomed,
- action() {
- setZoomed((prev) => !prev);
- },
- icon: {},
- }),
- [zoomed]
-);
-```
-
-### function: useConstraints()
-
-- `returns:` <[Constraints]>
-
-Gets the desired constraints that should be applied when rendering the supernova.
-
-The constraints are set on the nuclues configuration before the supernova is rendered
-and should respected by you when implementing the supernova.
-
-```js
-// configure embed to disallow active interactions when rendering
-embed(app, {
- context: {
- constraints: {
- active: true, // do not allow interactions
- },
- },
-}).render({ element, id: 'sdfsdf' });
-```
-
-```js
-import { useConstraints } from '@nebula.js/stardust';
-// ...
-const constraints = useConstraints();
-useEffect(() => {
- if (constraints.active) {
- // do not add any event listener if active constraint is set
- return undefined;
- }
- const listener = () => {};
- element.addEventListener('click', listener);
- return () => {
- element.removeEventListener('click', listener);
- };
-}, [constraints]);
-```
-
-### function: useOptions()
-
-- `returns:` <[Object]>
-
-Gets the options object provided when rendering the supernova.
-
-This is an empty object by default but enables customization of the supernova through this object.
-Options are different from setting properties on the generic object in that options
-are only temporary settings applied to the supernova when rendered.
-
-You have the responsibility to provide documentation of the options you support, if any.
-
-```js
-// when embedding the supernova, anything can be set in options
-embed(app).render({
- element,
- type: 'my-chart',
- options: {
- showNavigation: true,
- },
-});
-```
-
-```js
-// it is up to you use and implement the provided options
-import { useOptions } from '@nebula.js/stardust';
-import { useEffect } from '@nebula.js/stardust';
-// ...
-const options = useOptions();
-useEffect(() => {
- if (!options.showNavigation) {
- // hide navigation
- } else {
- // show navigation
- }
-}, [options.showNavigation]);
-```
-
-### function: onTakeSnapshot(snapshotCallback)
-
-- `snapshotCallback` <[Function]>
-
-Registers a callback that is called when a snapshot is taken.
-
-```js
-import { onTakeSnapshot } from '@nebula.js/stardust';
-import { useState } from '@nebula.js/stardust';
-import { useLayout } from '@nebula.js/stardust';
-
-const layout = useLayout();
-const [zoomed] = useState(layout.isZoomed || false);
-
-onTakeSnapshot((copyOfLayout) => {
- copyOfLayout.isZoomed = zoomed;
- return Promise.resolve(copyOfLayout);
-});
-```
-
-### interface: Context
-
-- `constraints` <[Object]>
- - `active` <[boolean]>
- - `passive` <[boolean]>
- - `select` <[boolean]>
-- `theme` <[string]> Defaults to `light`
-- `language` <[string]> Defaults to `en-US`
-
-### interface: Configuration
-
-- `context` <[Context]>
-- `types` <[Array]<[TypeInfo]>>
-- `themes` <[Array]<[ThemeInfo]>>
-- `anything` <[Object]>
-
-### undefined: Galaxy.translator
-
-### undefined: Galaxy.flags
-
-### undefined: Galaxy.anything
-
-### class: Embed
-
-#### embed.render(cfg)
-
-- `cfg` <[CreateConfig]|[GetConfig]> The render configuration.
-- `returns:` <[Promise]<[SupernovaController]>> A controller to the rendered visualization
-
-Renders a visualization into an HTMLElement.
-
-```js
-// render from existing object
-n.render({
- element: el,
- id: 'abcdef',
-});
-```
-
-```js
-// render on the fly
-n.render({
- type: 'barchart',
- fields: ['Product', { qLibraryId: 'u378hn', type: 'measure' }],
-});
-```
-
-#### embed.context(ctx)
-
-- `ctx` <[Context]> The context to update.
-- `returns:` <[Promise]<`undefined`>>
-
-Updates the current context of this embed instance.
-Use this when you want to change some part of the current context, like theme.
-
-```js
-// change theme
-n.context({ theme: 'dark' });
-```
-
-```js
-// limit constraints
-n.context({ constraints: { active: true } });
-```
-
-#### embed.selections()
-
-- `returns:` <[Promise]<[AppSelections]>>
-
-Gets the app selections of this instance.
-
-```js
-const selections = await n.selections();
-selections.mount(element);
-```
-
-### interface: ThemeInfo
-
-- `id` <[string]> Theme identifier
-- `load` <[Function]> A function that should return a Promise that resolve to a raw JSON theme
-
-### class: SupernovaController
-
-A controller to further modify a supernova after it has been rendered.
-
-```js
-const ctl = await embed(app).render({
- element,
- type: 'barchart',
-});
-ctl.destroy();
-```
-
-#### supernovaController.destroy()
-
-Destroys the supernova and removes if from the the DOM.
-
-```js
-const ctl = ctl.destroy();
-```
-
-### interface: Flags
-
-- `isEnabled` <[Function]> Checks whether the specified flag is enabled.
-
-### interface: CreateConfig
-
-- extends: <[BaseConfig]>
-
-* `type` <[string]>
-* `version` <[string]>
-* `fields` <[Array]>
-* `properties` <`EngineAPI.IGenericObjectProperties`>
-
-### interface: BaseConfig
-
-- `element` <`HTMLElement`>
-- `options` <[Object]>
-
-### interface: GetConfig
-
-- extends: <[BaseConfig]>
-
-* `id` <[string]>
-
-### type Field = <[string]|`EngineAPI.INxDimension`|`EngineAPI.INxMeasure`|[LibraryField]>
-
-### interface: LibraryField
-
-- `qLibraryId` <[string]>
-- `type` <`'dimension'`|`'measure'`>
-
-### class: AppSelections
-
-#### appSelections.mount(element)
-
-- `element` <`HTMLElement`>
-
-Mounts the app selection UI into the provided HTMLElement
-
-```js
-selections.mount(element);
-```
-
-#### appSelections.unmount()
-
-Unmounts the app selection UI from the DOM
-
-```js
-selections.unmount();
-```
-
-### class: ObjectSelections
-
-#### objectSelections.begin(paths)
-
-- `paths` <[Array]<[string]>>
-- `returns:` <[Promise]<`undefined`>>
-
-#### objectSelections.clear()
-
-- `returns:` <[Promise]<`undefined`>>
-
-#### objectSelections.confirm()
-
-- `returns:` <[Promise]<`undefined`>>
-
-#### objectSelections.cancel()
-
-- `returns:` <[Promise]<`undefined`>>
-
-#### objectSelections.select(s)
-
-- `s` <[Object]>
- - `method` <[string]>
- - `params` <[Array]<`any`>>
-- `returns:` <[Promise]<[boolean]>>
-
-#### objectSelections.canClear()
-
-- `returns:` <[boolean]>
-
-#### objectSelections.canConfirm()
-
-- `returns:` <[boolean]>
-
-#### objectSelections.canCancel()
-
-- `returns:` <[boolean]>
-
-#### objectSelections.isActive()
-
-- `returns:` <[boolean]>
-
-#### objectSelections.isModal()
-
-- `returns:` <[boolean]>
-
-#### objectSelections.goModal(paths)
-
-- `paths` <[Array]<[string]>>
-- `returns:` <[Promise]<`undefined`>>
-
-#### objectSelections.noModal([accept])
-
-- `accept` <[boolean]>
-- `returns:` <[Promise]<`undefined`>>
-
-#### objectSelections.abortModal()
-
-- `returns:` <[Promise]<`undefined`>>
-
-### interface: LoadType(type)
-
-- `type` <[Object]>
- - `name` <[string]>
- - `version` <[string]>
-- `returns:` <[Promise]<[Supernova]>>
-
-### interface: TypeInfo
-
-- `name` <[string]>
-- `version` <[string]>
-- `load` <[LoadType]>
-- `meta` <[Object]>
-
-### interface: Supernova(galaxy)
-
-- `galaxy` <`Galaxy`>
-- `returns:` <[SupernovaDefinition]>
-
-The entry point for defining a supernova.
-
-```js
-import { useElement, useLayout } from '@nebula.js/stardust';
-
-export default function () {
- return {
- qae: {
- properties: {
- dude: 'Heisenberg',
- },
- },
- component() {
- const el = useElement();
- const layout = useLayout();
- el.innerHTML = `What's my name? ${layout.dude}!!!`;
- },
- };
-}
-```
-
-### interface: SupernovaDefinition
-
-- `qae` <[QAEDefinition]>
-- `component` <[Function]>
-
-### interface: SetStateFn(newState)
-
-- `newState` <`S`|[Function]> The new state
-
-### type EffectCallback = <[Function]>
-
-### interface: Rect
-
-- `top` <[number]>
-- `left` <[number]>
-- `width` <[number]>
-- `height` <[number]>
-
-### interface: ActionDefinition
-
-- `action` <`A`>
-- `hidden` <[boolean]>
-- `disabled` <[boolean]>
-- `icon` <[Object]>
- - `viewBox` <[string]> Defaults to `"0 0 16 16"`
- - `shapes` <[Array]<[Object]>>
-
-### interface: Constraints
-
-- `passive` <[boolean]>
-- `active` <[boolean]>
-- `select` <[boolean]>
-
-### interface: QAEDefinition
-
-- `properties` <`EngineAPI.IGenericObjectProperties`>
-- `data` <[Object]>
- - `targets` <[Array]<[DataTarget]>>
-
-### interface: DataTarget
-
-- `path` <[string]>
-- `dimensions` <[FieldTarget]<`EngineAPI.INxDimension`>>
-- `measures` <[FieldTarget]<`EngineAPI.INxMeasure`>>
-
-### interface: FieldTarget
-
-- `min` <[Function]>
-- `max` <[Function]>
-- `added` <[Function]>
-- `removed` <[Function]>
-
-### class: Translator
-
-#### translator.add(item)
-
-- `item` <[Object]>
- - `id` <[string]>
- - `locale` <[Object]<[string],[string]>>
-
-Registers a string in multiple locales
-
-```js
-translator.add({
- id: 'company.hello_user',
- locale: {
- 'en-US': 'Hello {0}',
- 'sv-SE': 'Hej {0}',
- },
-});
-translator.get('company.hello_user', ['John']); // Hello John
-```
-
-#### translator.get(str[, args])
-
-- `str` <[string]> Id of the registered string
-- `args` <[Array]<[string]>> Values passed down for string interpolation
-- `returns:` <[string]> The translated string
-
-Translates a string for current locale
-
-### class: Theme
-
-#### theme.getDataColorScales()
-
-- `returns:` <[Array]<[ScalePalette]>>
-
-#### theme.getDataColorPalettes()
-
-- `returns:` <[Array]<[DataPalette]>>
-
-#### theme.getDataColorPickerPalettes()
-
-- `returns:` <[Array]<[ColorPickerPalette]>>
-
-#### theme.getDataColorSpecials()
-
-- `returns:` <[DataColorSpecials]>
-
-#### theme.getColorPickerColor(c)
-
-- `c` <[Object]>
- - `index` <[number]>
- - `color` <[string]>
-- `returns:` <[string]> The resolved color.
-
-Resolve a color object using the color picker palette from the provided JSON theme.
-
-```js
-theme.getColorPickerColor({ index: 1 });
-theme.getColorPickerColor({ color: 'red' });
-```
-
-#### theme.getContrastingColorTo(color)
-
-- `color` <[string]> A color to measure the contrast against
-- `returns:` <[string]> - The color that has the best contrast against the specified `color`.
-
-Get the best contrasting color against the specified `color`.
-This is typically used to find a suitable text color for a label placed on an arbitrarily colored background.
-
-The returned colors are derived from the theme.
-
-```js
-theme.getContrastingColorTo('#400');
-```
-
-#### theme.getStyle(basePath, path, attribute)
-
-- `basePath` <[string]> Base path in the theme's json structure to start the search in (specified as a name path separated by dots)
-- `path` <[string]> Expected path for the attribute (specified as a name path separated by dots)
-- `attribute` <[string]> Name of the style attribute
-- `returns:` <[string]> The style value
-
-Get the value of a style attribute in the theme by searching in the theme's json structure.
-The search starts at the specified base path and continue upwards until the value is found.
-If possible it will get the attribute's value using the given path.
-
-```js
-theme.getStyle('object', 'title.main', 'fontSize');
-theme.getStyle('', '', 'fontSize');
-```
-
-#### interface: ScalePalette
-
-- `key` <[string]>
-- `type` <`'gradient'`|`'class'`>
-- `colors` <[Array]<[string]>>
-
-#### interface: DataPalette
-
-- `key` <[string]>
-- `type` <`'pyramid'`|`'row'`>
-- `colors` <[Array]|[Array]>
-
-#### interface: ColorPickerPalette
-
-- `key` <[string]>
-- `colors` <[Array]<[string]>>
-
-#### interface: DataColorSpecials
-
-- `primary` <[string]>
-- `nil` <[string]>
-- `others` <[string]>
-
-[engineapi.iapp]: undefined
-[s]: undefined
-[function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
-[array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
-[any]: undefined
-[t]: undefined
-[htmlelement]: undefined
-[engineapi.igenericobjectlayout]: undefined
-[engineapi.inxapplayout]: undefined
-[engineapi.igenericobject]: undefined
-[undefined]: undefined
-[engineapi.iglobal]: undefined
-[a]: undefined
-[object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
-[boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type
-[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type
-[promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
-[engineapi.igenericobjectproperties]: undefined
-[engineapi.inxdimension]: undefined
-[engineapi.inxmeasure]: undefined
-[galaxy]: undefined
-[number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type
-[context]: #interface-context
-[configuration]: #interface-configuration
-[embed]: #class-embed
-[themeinfo]: #interface-themeinfo
-[supernovacontroller]: #class-supernovacontroller
-[createconfig]: #interface-createconfig
-[baseconfig]: #interface-baseconfig
-[getconfig]: #interface-getconfig
-[libraryfield]: #interface-libraryfield
-[appselections]: #class-appselections
-[objectselections]: #class-objectselections
-[loadtype]: #interface-loadtypetype
-[typeinfo]: #interface-typeinfo
-[supernova]: #interface-supernovagalaxy
-[supernovadefinition]: #interface-supernovadefinition
-[effectcallback]: #type-effectcallback-function
-[rect]: #interface-rect
-[constraints]: #interface-constraints
-[qaedefinition]: #interface-qaedefinition
-[datatarget]: #interface-datatarget
-[fieldtarget]: #interface-fieldtarget
-[translator]: #class-translator
-[theme]: #class-theme
-[scalepalette]: #interface-scalepalette
-[datapalette]: #interface-datapalette
-[colorpickerpalette]: #interface-colorpickerpalette
-[datacolorspecials]: #interface-datacolorspecials
diff --git a/docs/app-selections.md b/docs/app-selections.md
deleted file mode 100644
index 2869fbf0f..000000000
--- a/docs/app-selections.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-id: app-selections
-title: Current app selections
----
-
-An essential part of the Qlik experience is filtering data through selections. Most charts support selections in the data they render, which will then filter out data and affect other charts connected to the same data model.
-
-## Current app selections bar
-
-The current app selections bar shows you the currently active selections in the specified app. To render this bar you first need an `HTMLElement`:
-
-```html
-
-```
-
-You can then `mount` the selections UI into that element:
-
-```js
-const n = embed(enigmaApp);
-
-(await n.selections()).mount(document.querySelector('.curr-selections'));
-```
-
-Without any selections it should like this:
-
-
-
-As you start applying selections in the various charts, the UI will update to reflect the current state:
-
-
-
-## Multiple bars
-
-If you are connected to multiple apps, you can show the current selections in each one by mounting the bar into different elements:
-
-```js
-(await embed(enigmaApp).selections()).mount(document.querySelector('.curr-selections'));
-
-(await embed(anotherApp, { context: { theme: 'dark' } }).selections()).mount(
- document.querySelector('.another-curr-selections')
-);
-```
-
-
diff --git a/docs/assets/hub-app.png b/docs/assets/hub-app.png
deleted file mode 100644
index bf5cfb540..000000000
Binary files a/docs/assets/hub-app.png and /dev/null differ
diff --git a/docs/assets/hub-connect.png b/docs/assets/hub-connect.png
deleted file mode 100644
index ece5bc960..000000000
Binary files a/docs/assets/hub-connect.png and /dev/null differ
diff --git a/docs/assets/hub-dev.png b/docs/assets/hub-dev.png
deleted file mode 100644
index c7cce5e98..000000000
Binary files a/docs/assets/hub-dev.png and /dev/null differ
diff --git a/docs/assets/mashup-sample.png b/docs/assets/mashup-sample.png
deleted file mode 100644
index 6a6b325a8..000000000
Binary files a/docs/assets/mashup-sample.png and /dev/null differ
diff --git a/docs/assets/nebula-overview.png b/docs/assets/nebula-overview.png
deleted file mode 100644
index 26fad2614..000000000
Binary files a/docs/assets/nebula-overview.png and /dev/null differ
diff --git a/docs/assets/selections-empty.png b/docs/assets/selections-empty.png
deleted file mode 100644
index 2af725ad0..000000000
Binary files a/docs/assets/selections-empty.png and /dev/null differ
diff --git a/docs/assets/selections-instant.gif b/docs/assets/selections-instant.gif
deleted file mode 100644
index 119742c12..000000000
Binary files a/docs/assets/selections-instant.gif and /dev/null differ
diff --git a/docs/assets/selections-modal.gif b/docs/assets/selections-modal.gif
deleted file mode 100644
index 8dd220224..000000000
Binary files a/docs/assets/selections-modal.gif and /dev/null differ
diff --git a/docs/assets/selections-multiple.gif b/docs/assets/selections-multiple.gif
deleted file mode 100644
index a848bb2d7..000000000
Binary files a/docs/assets/selections-multiple.gif and /dev/null differ
diff --git a/docs/assets/selections-update.gif b/docs/assets/selections-update.gif
deleted file mode 100644
index d9c5b1351..000000000
Binary files a/docs/assets/selections-update.gif and /dev/null differ
diff --git a/docs/assets/simple-vis-with-plugin.png b/docs/assets/simple-vis-with-plugin.png
deleted file mode 100644
index 178dd6e58..000000000
Binary files a/docs/assets/simple-vis-with-plugin.png and /dev/null differ
diff --git a/docs/assets/simple-vis.png b/docs/assets/simple-vis.png
deleted file mode 100644
index 7e438db56..000000000
Binary files a/docs/assets/simple-vis.png and /dev/null differ
diff --git a/docs/assets/supernova-barchart.png b/docs/assets/supernova-barchart.png
deleted file mode 100644
index 0ac28d594..000000000
Binary files a/docs/assets/supernova-barchart.png and /dev/null differ
diff --git a/docs/assets/supernova-incomplete.png b/docs/assets/supernova-incomplete.png
deleted file mode 100644
index dbe07a205..000000000
Binary files a/docs/assets/supernova-incomplete.png and /dev/null differ
diff --git a/docs/assets/theme-dark.png b/docs/assets/theme-dark.png
deleted file mode 100644
index f7a9e1fc0..000000000
Binary files a/docs/assets/theme-dark.png and /dev/null differ
diff --git a/docs/assets/theme-light.png b/docs/assets/theme-light.png
deleted file mode 100644
index d06a49a54..000000000
Binary files a/docs/assets/theme-light.png and /dev/null differ
diff --git a/docs/assets/theme-pinkish.png b/docs/assets/theme-pinkish.png
deleted file mode 100644
index 5c1881290..000000000
Binary files a/docs/assets/theme-pinkish.png and /dev/null differ
diff --git a/docs/assets/tutorial-data-targets.png b/docs/assets/tutorial-data-targets.png
deleted file mode 100644
index 27be34022..000000000
Binary files a/docs/assets/tutorial-data-targets.png and /dev/null differ
diff --git a/docs/assets/tutorial-table.png b/docs/assets/tutorial-table.png
deleted file mode 100644
index 4b8a89827..000000000
Binary files a/docs/assets/tutorial-table.png and /dev/null differ
diff --git a/docs/embed-configuration.md b/docs/embed-configuration.md
deleted file mode 100644
index fc2e2984a..000000000
--- a/docs/embed-configuration.md
+++ /dev/null
@@ -1,246 +0,0 @@
----
-id: embed-configuration
-title: Configuration
----
-
-When you are building a website, whether it's a company wide site or a small personal project, you most likely have your own design guidelines, UX patterns and requirements, and would want to apply those guidelines on the things you integrate with it; charts should use your color schemes, fonts, locale and respect any restrictions you may have on interactivty. You may also want to control how charts and themes are loaded based on whether your solution is online or offline.
-
-You can control most of these through the `Configuration` object.
-
-## Temporary config
-
-The `Configuration` object is an optional argument that you can provide when instantiating the `embed` instance:
-
-```js
-import { embed } from '@nebula.js/stardust';
-
-const n = embed(enigmaApp, {
- context: {
- theme: 'dark',
- },
- types: [
- /* types */
- ],
-});
-
-n.render(/* chart 1*/);
-n.render(/* chart 2*/);
-```
-
-## Reusable config
-
-If you are working with multiple apps, or want to have multiple different configurations it might be easier for you to create the configurations first and then reuse those.
-
-Create a `baseConfig` which does the heavy lifting of registering types and themes:
-
-```js
-const baseConfig = embed.createConfiguration({
- types: [
- /* register type once*/
- ],
- themes: [
- /* register themes once*/
- ],
-});
-```
-
-Create another configuration which inherits from the `baseConfig`, apply a `'dark'` theme and set a constraint to disallow selection:
-
-```js
-const noSelectionDark = baseConfig.createConfiguration({
- context: {
- theme: 'dark',
- constraints: { select: true },
- },
-});
-
-// render chart with dark theme with no selections allowed
-noSelectionDark(enigmaApp).render(/*chart config*/);
-noSelectionDark(anotherEnigmaApp).render(/*chart config*/);
-```
-
-You can also bind the config to an app directly:
-
-```js
-const swedishPink = baseConfig(enigmaApp, {
- context: {
- theme: 'pinkish',
- language: 'sv-SE',
- },
-});
-
-swedishPink.render(/* chart config */);
-```
-
-## Registering types
-
-Before rendering a visualization, its module needs to be loaded and registered. You can load the modules you know you will need from npm:
-
-```bash
-$ npm install @nebula.js/sn-bar-chart @nebula.js/sn-pie-chart
-```
-
-And then register each `type` individually:
-
-```js
-import barchart from '@nebula.js/sn-bar-chart';
-import piechart from '@nebula.js/sn-pie-chart';
-
-embed.createConfiguration({
- types: [
- {
- name: 'bar',
- load: () => Promise.resolve(barchart),
- },
- {
- name: 'pie',
- load: () => Promise.resolve(piechart),
- },
- ],
-});
-```
-
-### Loading on the fly
-
-If you don't know exactly which types you will need and want to avoid installing everything to reduce the size of your bundle, you could load the visualizations at runtime using a lighweight AMD loader like [d3-require](https://github.com/d3/d3-require).
-
-Start by installing the module:
-
-```bash
-npm install d3-require
-```
-
-and then configure it to load modules from a CDN like `https://unpkg.com`, as well as specify an alias to use the local version of `@nebula.js/stardust`:
-
-```js
-import { requireFrom } from 'd3-require';
-import * as stardust from '@nebula.js/stardust';
-
-const loadSnType = requireFrom((name) => `https://unpkg.com/@nebula.js/sn-${name}-chart`).alias({
- '@nebula.js/stardust': stardust,
-});
-```
-
-You can then configure all types you expect might be used:
-
-```js
-const types = ['bar', 'line', 'pie', 'sankey'].map((t) => ({
- name: t,
- load: () => loadSnType(t),
-}));
-const baseConfig = stardust.embed.createConfiguration({ types });
-```
-
-The type will be loaded from the remote url the first time you render it:
-
-```js
-baseConfig(enigmaApp).render({
- name: 'bar',
- fields: ['Product', '=sum(Sales)'],
-});
-```
-
-## Context
-
-When setting up the configuration you can apply a `context` which controls the language, theme and constraints in each visualization you render:
-
-```js
-embed.createConfiguration({
- context: {},
-});
-```
-
-### Constraints
-
-Constraints enables you to instruct a visualization to disable certain types of interactions and behaviour.
-
-There are three different constraints you can apply:
-
-- `passive`: disable interactions like tooltips.
-- `active`: disable interactions that affect the state of the visual representation like zoom, scroll, etc.
-- `select`: disable selections.
-
-```js
-{
- context: {
- constraints: {
- active: true,
- passive: true,
- select: true,
- },
- },
-};
-```
-
-`stardust` does not enforce these constraints in any way, instead it is up to the visualization developer to respect and implement them.
-
-### Language
-
-`stardust` supports 15 languages:
-
-- `'en-US'` - American English
-- `'sv-SE'` - Swedish
-- `'it-IT'` - Italian
-- `'zh-CN'` - Simplified Chinese
-- `'zh-TW'` - Traditional Chinese
-- `'ko-KR'` - Korean
-- `'de-DE'` - German
-- `'es-ES'` - Spanish
-- `'pt-BR'` - Brazilian Portuguese
-- `'ja-JP'` - Japanese
-- `'fr-FR'` - French
-- `'nl-NL'` - Dutch
-- `'tr-TR'` - Turkish
-- `'pl-PL'` - Polish
-- `'ru-RU'` - Russian
-
-```js
-{
- context: {
- language: 'sv-SE',
- },
-};
-```
-
-### Theme
-
-There are two main themes provided out of the box: `'light'` and `'dark'`.
-
-```js
-{
- context: {
- theme: 'dark',
- }
-};
-```
-
-| Light theme | Dark theme |
-| -------------------------------------- | ------------------------------------ |
-|  |  |
-
-You can also register custom themes and apply one of those on the context:
-
-```js
-{
- themes: [{
- id: 'pinkish',
- load: () => Promise.resolve({
- palettes: {
- data: [{
- scale: [
- '#fac6e5',
- '#ff95d6',
- '#e76eb1',
- '#b44772',
- ],
- }]
- }
- })
- }],
- context: {
- theme: 'pinkish'
- }
-};
-```
-
-
diff --git a/docs/embedding-visualizations.md b/docs/embedding-visualizations.md
deleted file mode 100644
index 0fe852f87..000000000
--- a/docs/embedding-visualizations.md
+++ /dev/null
@@ -1,72 +0,0 @@
----
-id: embedding-visualizations
-title: Embedding visualizations
----
-
-You can embed a visualization in two ways:
-
-1. On the fly
-1. From an existing object
-
-Rendering is done using the `render()` method on the instance returned by the `embed` function, which at minimum requires the `HTMLElement` you want to render into:
-
-```js
-import { embed } from '@nebula.js/stardust';
-
-const n = embed(enigmaApp);
-n.render({
- element,
- // rest of the config
-});
-```
-
-## Render on the fly
-
-When rendering a visualization on the fly you need to specify the `type` you want to render:
-
-```js
-n.render({
- element,
- type: 'barchart',
-});
-```
-
-Some visualizations have minimum requirements on the various properties and/or data it needs in order to render, in which case you might see something like this:
-
-
-
-To provide initial data to the visualization, add the data dimensions and measures into the `fields` property:
-
-```js
-n.render({
- element,
- type: 'barchart',
- fields: ['Region', '=sum(Sales)'],
-});
-```
-
-You can also modify the initial properties:
-
-```js
-n.render({
- element,
- type: 'barchart',
- fields: ['Product', '=sum(Sales)'],
- properties: {
- title: 'Sales by region',
- },
-});
-```
-
-
-
-## Render from existing objects
-
-If you already have created a generic object in your app and want to render it, you can do so by providing the object's `id`:
-
-```js
-n.render({
- element,
- id: '',
-});
-```
diff --git a/docs/installation.md b/docs/installation.md
deleted file mode 100644
index e99adb20d..000000000
--- a/docs/installation.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-id: installation
-title: Installation
----
-
-All `nebula.js` modules are available on the public npm registry as npm packages and can be installed through either npm or as a script import.
-
-`@nebula.js/stardust` is the primary module that you will be using and is required when integrating `nebula.js` on the web.
-
-## Script import
-
-The easiest way to load the module is from a CDN like `jsdelivr`:
-
-```html
-
-```
-
-When imported using the script tag, it will add the variable `stardust` to the global namespace.
-
-For production, it is recommended to use a specific version of the module to avoid surprises from newer or breaking versions of the APIs:
-
-```html
-
-```
-
-## Npm or yarn
-
-If you are building your own web project using Webpack, Rollup, Parcel or similar you can install the package with npm:
-
-```bash
-$ npm install @nebula.js/stardust
-```
-
-or yarn:
-
-```bash
-$ yarn add @nebula.js/stardust
-```
-
-and then import `{ embed }` wherever you intend to embed a visualization:
-
-```js
-import { embed } from '@nebula.js/stardust';
-```
-
-## CLI
-
-`nebula.js` provides a CLI for quickly getting started with a project and provides a development server to help you during the
-development phase.
-
-```bash
-$ npm install @nebula.js/cli
-```
-
-## Development builds
-
-Some modules are available as a development build which provide more errors and warnings when detecting potentially bad usage of the APIs.
-You should only use these during the development phase of your project, never in production.
-
-```html
-
-```
-
-## Linking nebula packages to your own repository
-
-When you use nebula.js as a dependency in your project, and you want to edit or debug the nebula.js source code, you can use either `npm link` or `yarn link` to accomplish this.
-
-### Linking nebula when using `nebula serve`
-
-With `npm`: Before using `nebula serve` to serve your project's files, you must run `npm link` in the folder: `nebula.js/commands/serve` and use it in your own repo by running `npm link @nebula.js/cli-serve` (run this in your own repo).
-To include source maps, so you can easier debug the nebula.js code, you should also run `yarn build:dev` in the `nebula.js/commands/serve` folder.
-
-With `yarn`: Same as for `npm` but replace `npm` with `yarn` in the commands above.
-
-In your browser's debugging tool you should now be able to see the nebula.js source code and to add breakpoints inside of the nebula.js files.
diff --git a/docs/plugins.md b/docs/plugins.md
deleted file mode 100644
index 3d64ee97c..000000000
--- a/docs/plugins.md
+++ /dev/null
@@ -1,103 +0,0 @@
----
-id: plugins
-title: Plugins
----
-
-Plugins can be used to add or modify a visualization. Nebula provides a way to pass in plugins (through the `render` function of an `embed` instance), and to access provided plugins (through the `usePlugins` hook in the chart implementation).
-
-## Render with plugins
-
-```js
-embed(app).render({
- element,
- type: 'my-chart',
- plugins: [plugin],
-});
-```
-
-## How to implement a plugin
-
-A plugin needs to be an object literal, including plugin info (`name`) and a function, `fn`, in which the plugin is implemented.
-
-```js
-const plugin = {
- info: {
- name: 'example-plugin',
- },
- fn: () => {
- // Plugin implementation goes here
- },
-};
-```
-
-The `info` object is a suitable place to add more meta information if needed. Input and return value of the `fn` function is up to the plugin implementation to decide based on its purpose.
-
-## Accessing plugins in chart implementation
-
-Plugins passed at rendering can be accessed through the `usePlugins` hook in the following way:
-
-```js
-import { usePlugins } from '@nebula.js/stardust';
-// ...
-const plugins = usePlugins();
-plugins.forEach((plugin) => {
- // Invoke plugin
- plugin.fn();
-});
-```
-
-## A simple example
-
-A visualization rendering a random value.
-
-```js
-import { useElement, useEffect, usePlugins } from '@nebula.js/stardust';
-
-export default function supernova() {
- return {
- component() {
- const element = useElement();
- const plugins = usePlugins();
- useEffect(() => {
- const randomValue = Math.random().toFixed(2) * 100;
- let valueHtml;
- if (plugins[0] && plugins[0].info.type === 'value-html') {
- valueHtml = plugins[0].fn(randomValue);
- } else {
- valueHtml = `${randomValue}`;
- }
-
- element.innerHTML = `Value: ${valueHtml}
`;
- }, []);
- },
- };
-}
-```
-
-The visualization looks for provided plugins with `type` set to "value-html", and if that is present it invokes the plugin to get html for the value element, which it inserts into the DOM.
-
-### Rendering with a simple plugin
-
-```js
-const pinkStylePlugin = {
- info: {
- name: 'styling-plugin',
- type: 'value-html',
- },
- fn(value) {
- return `${value}`;
- },
-};
-
-// ...
-embed(app).render({
- 'simple-vis',
- element: el,
- plugins: [pinkStylePlugin],
-});
-```
-
-| No plugin | With plugin |
-| :-----------------------------------: | :-------------------------------------------------: |
-|  |  |
diff --git a/docs/sn-component.md b/docs/sn-component.md
deleted file mode 100644
index fdb1587a7..000000000
--- a/docs/sn-component.md
+++ /dev/null
@@ -1,142 +0,0 @@
----
-id: sn-component
-title: Rendering
----
-
-The `component` portion of the definition is where all rendering takes place, it's just a function that does not return anything:
-
-```js
-export default function () {
- return {
- component() {
- // rendering logic goes here
- },
- };
-}
-```
-
-In order to render something you need to access the DOM element the visualization is assigned to, you can do so by importing the `useElement` function:
-
-```js
-import { useElement } from '@nebula.js/stardust';
-```
-
-This function returns a simple HTMLElement which is your entry point to the visual world:
-
-```js
-component() {
- const element = useElement();
- element.innerHTML = 'Hello!';
-}
-```
-
-`useElement` is one of many functions that provide you with the most common requirements when developing a visualization, they allow you to _hook_ into the resources provided by both `stardust` and Qlik's Associative Engine.
-
-## Hooks
-
-If you have been working with [React](https://reactjs.org/) you might recognize this as _hooks_. Hooks is a concept which emphasizes reusable composable functions rather than classical object oriented classes and inheritance. While our implementation is completely custom with our own hooks, the concept and rules are very similar, so much so that you can read the [React hooks documentation](https://reactjs.org/docs/hooks-intro.html) to understand how to use stardust's own hooks.
-
-### useElement
-
-You've already seen the `useElement` hook, it's only purpose is to provide the HTMLElement you need to attach your own elements to to make your content visible, in the following example the element's `innerHTML` is set to `Hello!`:
-
-```js
-component() {
- // get the element
- const element = useElement();
- // set element content
- element.innerHTML = 'Hello!';
-}
-```
-
-A static string won't accomplish much though, in most cases you will be updating the content based on data input, component state and user interactions.
-
-The `component()` function is executed every time something that might be connected to your rendering changes; theme, data model, data selections, component state etc. As such, adding and removing event listeners, updating DOM nodes and fetching data is not ideal and can be quite performance heavy if done every time `component()` is run. You should instead batch updates with `useEffect`.
-
-### useEffect
-
-`useEffect` is a hook that accepts a callback function which will be run only when the value you specify changes. This enables you to not only batch updates but to also implement your own form of lifecycle management in your component.
-
-```js
-import { useEffect } from '@nebula.js/stardust';
-// ...
-component() {
- const element = useElement();
-
- useEffect(() => {
- // run only once when the component is created
- console.log('created');
- }, []);
-}
-```
-
-Adding event listeners to the element is typically only done when the component is initiated, and then removed when the component is destroyed:
-
-```js
-component() {
- const element = useElement();
-
- useEffect(() => {
- const listener = () => {
- console.log('clicked');
- };
-
- element.addEventListener('click', listener);
-
- return () => {
- // clean-up
- element.removeEventListener('click', listener);
- };
- }, [element]);
-}
-```
-
-In the example above, `element` is provided as an observable value as the second argument so the effect will only run when `element` changes. However, since `element` never changes for the same component the callback will only run once when the component is created. So `listener` will only be instantiated once and only one `click` event listener will be added. The callback also returns a function in the end, it's a clean-up function that is executed when any of the observable values change, or when the component is destroyed. This is where you should clean-up any sideffects you added, in this case the event listener is removed to avoid a memory leak.
-
-### useState
-
-Since `component()` is a function and not a class or object instance, you can not use `this` to store instance values as you would otherwise. The way to store state is through `useState`:
-
-```js
-import { useState } from '@nebula.js/stardust';
-
-export default function () {
- return {
- component() {
- const [count, setCount] = useState(0);
- },
- };
-}
-```
-
-`useState` returns a tuple where the first item is the same as the initial value provided as argument to `useState`, while the second item is a setter function through which you can change the value.
-
-In the following example `count` is incremented by 1 when a user clicks on `element`:
-
-```js
-component() {
- const element = useElement();
- const [count, setCount] = useState(0);
-
- useEffect(() => {
- const listener = () => {
- setCount(count + 1);
- };
-
- element.addEventListener('click', listener);
-
- return () => {
- element.removeEventListener('click', listener);
- };
- }, [element]);
-}
-```
-
-To render the updated value you can add another `useEffect` that is run when `count` changes:
-
-```js
-const [count, setCount] = useState(0);
-useEffect(() => {
- element.innerHTML = `Count: ${count}`;
-}, [count]);
-```
diff --git a/docs/sn-configure-data.md b/docs/sn-configure-data.md
deleted file mode 100644
index 3a5f9945c..000000000
--- a/docs/sn-configure-data.md
+++ /dev/null
@@ -1,155 +0,0 @@
----
-id: sn-configure-data
-title: Configuring data
----
-
-The `qae` section of the definition is where you define the properties of the Generic Object and the shape of the data you expect to consume.
-
-```json
-{
- "qae": {
- "properties": {}
- }
-}
-```
-
-## Generic Object
-
-Every visualization is connected to the entire data model and Qlik's Associative Engine through a _Generic Object_. This is a JSON object containing _properties_ which result in a _layout_ that describe the state of the backend portion of the visualization.
-
-Every time someone wants to render your visualization, an instance of the generic object will be created in the data model. If the creator has the right permissions, they can choose to store and persist this object in their data model.
-
-### Properties
-
-What properties you set is entirely up to you, it must however be a valid JSON object. Most properties are just settings that you may want to persist over time. If you are developing a bar chart you might want to store a setting that indicates whether it should be stacked, or what color the bars should have:
-
-```json
-{
- "isStacked": true,
- "barColor": "red"
-}
-```
-
-These properties are _static_, what goes in comes out exactly the same. The true power of the Generic Object are the _dynamic_ properties you can set that enables you to leverage Qlik's Associative Engine and access the data inside it.
-
-Dynamic properties have a specific structure that enables the backend to differentiate between dynamic properties and static. They also have a naming convention: they all begin with a `q` followed by a capital letter, this makes it easy for both humans and machines to distinguish between the two property types.
-
-There are a lot of different [predefined](https://core.qlik.com/services/qix-engine/apis/qix/definitions/) dynamic properties for various purposes, you can for example use [ValueExpression](https://core.qlik.com/services/qix-engine/apis/qix/definitions/#valueexpression) to do simple calculations:
-
-```json
-{
- "simpleMath": {
- "qValueExpression": {
- "qExpr": "1+1"
- }
- }
-}
-```
-
-### Layout
-
-The _layout_ of the Generic Object is the result of the static and dynamic properties. The layout of the properties above will look like this:
-
-```json
-{
- "isStacked": true,
- "barColor": "red",
- "simpleMath": 2
-}
-```
-
-Notice that the static properties remain exactly the same, while the dynamic property `simpleMath` now contains the calculated result of the ValueExpression.
-
-Most dynamic properties have an input definition and a corresponding layout output; a [ListObjectDef](https://core.qlik.com/services/qix-engine/apis/qix/definitions/#listobjectdef) will result in a [ListObject](https://core.qlik.com/services/qix-engine/apis/qix/definitions/#listobject), a [SelectionObjectDef](https://core.qlik.com/services/qix-engine/apis/qix/definitions/#selectionobjectdef) will result in a [SelectionObject](https://core.qlik.com/services/qix-engine/apis/qix/definitions/#selectionobject), and so on.
-
-## Data
-
-The most common property definition you will be using is the [HyperCubeDef](https://core.qlik.com/services/qix-engine/apis/qix/definitions/#hypercubedef), this is the dynamic property that will provide you with data from the backend data model. You can place this in the root of the properties object, or on a deeper level, and you can have as many as you need:
-
-```json
-{
- "qHyperCubeDef": {},
- "anotherOne": {
- "qHyperCubeDef": {},
- "andAThird": {
- "qHyperCubeDef": {}
- }
- }
-}
-```
-
-The primary input to the HyperCubeDef are _dimensions_ and _measures_:
-
-```json
-{
- "qHyperCubeDef": {
- "qDimensions": [{ "qLibraryId": "hdg534" }],
- "qMeasures": [{ "qLibraryId": "gt5dgd" }]
- }
-}
-```
-
-In this case the dimensions and measures are hardcoded to a predefined value that might exist in a specific data model, which is rarely what you want. If you are developing a chart for others to use with any data model you need to make it possible to add those dynamically, you can do this be specifying _data targets_.
-
-### Data targets
-
-A data target is a way for you to define where the dynamic HyperCubeDefs are located in the Generic Object's properties. While `stardust` could traverse the properties and locate all usages of `qHyperCubeDef`, you may not want all of those to be dynamic, or you may generate them for internal use only.
-
-You specify data targets with the `data.targets` key in `qae`, each target must have a `path` key which indicates the JSON path of the HyperCubeDef from the root of the properties object:
-
-```js
-qae: {
- properties: {
- qHyperCubeDef: {},
- my: {
- nested: {
- qHyperCubeDef: {}
- },
- }
- },
- data: {
- targets: [
- { path: '/qHyperCubeDef' },
- { path: '/my/nested/qHyperCubeDef' },
- ];
- }
-}
-```
-
-You can for each data target specify additional details like the maximum/minimum amount of dimensions and measures, and make modifications when they are added.
-
-This is useful when you know the limitations of what a chart can render, a pie chart for example is mostly usable when it has exactly one dimension and one measure, but you might also be implementing support for a second measure. This also saves you some code logic since `stardust` won't attempt to render a chart whose limitations have not been fulfilled, and will instead show that some fields are missing.
-
-### Field limitations
-
-To specify limitations on dimensions or measures, add each respective field type as an object as part of the data target:
-
-```js
-targets: [
- {
- path: '/qHyperCubeDef',
- dimensions: {
- min: 1,
- max: 1,
- },
- measures: {
- min: 1,
- max: 2,
- },
- },
-];
-```
-
-### Field modifications
-
-You can also modify an added or removed field just before the change is applied and sent to the backend, this is useful for things like setting sorting when a dimension is added, or adding additional properties that you know you will always need.
-
-If you for example want to make sure that null values are suppressed since it's not something you can render or represent in a good way, you can set `qNullSuppression: true` when the dimension is added:
-
-```js
-dimensions: {
- added(dimension) {
- dimension.qNullSuppression = true;
- }
-}
-```
diff --git a/docs/sn-controller.md b/docs/sn-controller.md
deleted file mode 100644
index e79c954e0..000000000
--- a/docs/sn-controller.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-id: sn-controller
-title: Modify charts
----
-
-TODO
diff --git a/docs/sn-create.md b/docs/sn-create.md
deleted file mode 100644
index 349778541..000000000
--- a/docs/sn-create.md
+++ /dev/null
@@ -1,230 +0,0 @@
----
-id: sn-create
-title: Quick start
----
-
-This guide will walk you through creating a simple project that renders a table.
-
-It will include the following steps:
-
-1. Create a project
-1. Configure data structure
-1. Render data
-1. Select data
-
-and requires that you have:
-
-- Access to a Qlik Sense installation.
-- `node.js` `v10.0.0+` installed on your machine.
-- A decent IDE, we recommend [VSCode](https://code.visualstudio.com/).
-
-## Create a project
-
-The quickest way to get started is to use the `nebula.js` CLI:
-
-```bash
-$ npx @nebula.js/cli create hello --picasso none
-```
-
-The `--picasso none` option tells the command to not create a picasso visualization template, other options are `minimal` and `barchart`.
-
-The command will scaffold a project into the `hello` folder with the following structure:
-
-- `/src`
- - `index.js` - Main entry point of this visualization
- - `object-properties.js` - Object properties stored in the app
- - `data.js` - Data configuration
-- `/test` - Integration tests
-- `package.json`
-
-The folder contains some additional dotfiles that provides linting and formatting of code.
-
-### Start the development server
-
-Start the development server with:
-
-```bash
-$ cd hello
-$ npm run start
-```
-
-The command will start a local development server and open up http://localhost:8080 in your browser.
-
-
-
-The development server needs to connect to a Qlik Associative Engine running in any Qlik deployment. Enter the WebSocket URL that corresponds to the Qlik product you are using.
-
-Next, select an app to connect to.
-
-
-
-You will then be redirected to the main developer UI where you should see your visualization rendered:
-
-
-
-Any updates in `/src/index.js` that affects the output will automatically cause a refresh of the visualization and you will see the changes immediately.
-
-## Configure data structure
-
-A simple `Hello` message is not really that useful, time to add some data.
-
-Add a `qHyperCubeDef` definition in `object-properties.js`:
-
-```js
-const properties = {
- qHyperCubeDef: {
- qInitialDataFetch: [{ qWidth: 2, qHeight: 10 }],
- },
- // ...
-};
-```
-
-Then add that hypercube as a data target in `data.js`:
-
-```js
-export default {
- targets: [
- {
- path: '/qHyperCubeDef',
- },
- ],
-};
-```
-
-With only those changes you should now have the option to add data from the property panel on the right:
-
-
-
-Add a dimension by clicking on **Add dimension** and selecting a value in the menu that appears, do the same with measure.
-
-## Render data
-
-In order to render the data you first need to access it through the `useLayout` hook:
-
-```js
-import { useLayout, useElement, useEffect } from '@nebula.js/stardust';
-
-// ...
-component() {
- console.log(useLayout());
-}
-```
-
-You can then `useLayout` in combination with `useEffect` to render the headers and rows of data in `qHyperCube`:
-
-```js
-component() {
- const element = useElement();
- const layout = useLayout();
-
- useEffect(() => {
- if (layout.qSelectionInfo.qInSelections) {
- // skip rendering when in selection mode
- return;
- }
- const hc = layout.qHyperCube;
-
- // headers
- const columns = [...hc.qDimensionInfo, ...hc.qMeasureInfo].map((f) => f.qFallbackTitle);
- const header = `${columns.map((c) => `| ${c} | `).join('')}
`;
-
- // rows
- const rows = hc.qDataPages[0].qMatrix
- .map((row) => `${row.map((cell) => `| ${cell.qText} | `).join('')}
`)
- .join('');
-
- // table
- const table = ``;
-
- // output
- element.innerHTML = table;
-
- }, [element, layout])
-}
-```
-
-
-
-## Select data
-
-Before selecting data, we need to add some meta data on each row so that we know which one to select:
-
-```js
-// rows
-const rows = hc.qDataPages[0].qMatrix
- .map((row, rowIdx) => `${row.map((cell) => `| ${cell.qText} | `).join('')}
`)
- .join('');
-```
-
-And then add a `'click'` event handler on `element` which does the following:
-
-- Verifies that the clicked element is a `td`
-- Begins selections in `/qHyperCubeDef` if not already activated
-- Extracts the `data-row` index from `tr`
-- Updates `selectedRows` based on the click `data-row`
-
-```js
-const element = useElement();
-const selections = useSelections();
-const [selectedRows, setSelectedRows] = useState([]);
-
-useEffect(() => {
- const listener = (e) => {
- if (e.target.tagName === 'TD') {
- if (!selections.isActive()) {
- selections.begin('/qHyperCubeDef');
- }
- const row = +e.target.parentElement.getAttribute('data-row');
- setSelectedRows((prev) => {
- if (prev.includes(row)) {
- return prev.filter((v) => v !== row);
- }
- return [...prev, row];
- });
- }
- };
-
- element.addEventListener('click', listener);
-
- return () => {
- element.removeEventListener('click', listener);
- };
-}, [element]);
-```
-
-Next, update the styling of the selected rows in the table whenever they change:
-
-```js
-useEffect(() => {
- if (!layout.qSelectionInfo.qInSelections) {
- // no need to update when not in selection mode
- return;
- }
- element.querySelectorAll('tbody tr').forEach((tr) => {
- const idx = +tr.getAttribute('data-row');
- tr.style.backgroundColor = selectedRows.includes(idx) ? '#eee' : '';
- });
-}, [element, selectedRows, layout]);
-```
-
-Finally, apply the selected values through the `selections` API:
-
-```js
-useEffect(() => {
- if (selections.isActive()) {
- if (selectedRows.length) {
- selections.select({
- method: 'selectHyperCubeCells',
- params: ['/qHyperCubeDef', selectedRows, [0]],
- });
- } else {
- selections.select({
- method: 'resetMadeSelections',
- params: [],
- });
- }
- } else if (selectedRows.length) {
- setSelectedRows([]);
- }
-}, [selections.isActive(), selectedRows]);
-```
diff --git a/docs/sn-hypercube.md b/docs/sn-hypercube.md
deleted file mode 100644
index f504721a5..000000000
--- a/docs/sn-hypercube.md
+++ /dev/null
@@ -1,161 +0,0 @@
----
-id: sn-hypercube
-title: HyperCube introduction
----
-
-The `HyperCubeDef` is the fundamental structure which you configure before you are provided with the result in the form of a `HyperCube`. Don't let the name scare you, while it does contain a lot of properties and can be configured in many ways, in its most basic form it resembles a simple table with rows and columns.
-
-## HyperCubeDef configuration
-
-Not all properties are equally important, and there are a few key ones that you need to keep in mind when configuring the `HyperCubeDef`.
-
-### qMode
-
-While you may not need to set `qMode` explicitly since it defaults to the simplest mode `'S'`, it's important to know the impact it has on the data structure.
-
-`qMode: 'P'`, or _pivot mode_, will give you a structure suitable for presenting pivot tables with groups in both vertical and horizontal directions, as well as a group for all measures.
-
-`qMode: 'T'`, or _tree mode_, will give you a structure that resembles a tree and is suitable to use for rendering tree-like visualizations; treemap, circle packing, sunburst, dendrogram, trellising etc.
-
-`qMode: 'S'`, or _straight mode_, is the simplest of them all and will give you a data structure that looks like a simple table with rows and columns. For the sake of simplicity in explaining the rest of the hypercube let's assume you are using this one.
-
-### qDimensions and qMeasures
-
-`qDimensions` and `qMeasures` are the columns of your "table", there is no explicit limit on the number of these you can add, but there is often a limitation on the number of dimensions and measure a certain chart can handle, and you need to keep the number of these in mind when you specify `qInitialDataFetch`.
-
-### qInitialDataFetch
-
-Qlik's Associative Engine is a memory based solution, meaning the amount of the data it can handle is based entirely on the memory resources it has access to. A such, it can contain billions of data values and the number of rows in the hypercube can therefore potentially reach billions as well.
-
-To avoid cases where that huge amounts of data is transferred to the front end the hypercube by default does not include any rows at all. To control this you can set the number of rows and columns you want initially with `qInitialDataFetch`. This property allows you to set the _data pages_ you want to extract from the entire hypercube, so you can for example choose to get the first 50 rows:
-
-```js
-qHyperCubeDef: {
- qInitialDataFetch: [{ qLeft: 0, qTop: 0, qHeight: 50, qWidth: 4 }];
-}
-```
-
-If you think of the straight table as a grid from which you want to extract some data, then `qLeft` and `qTop` are the upper left of the subset you want to extract, while `qHeight` and `qWidth` are the number of rows and columns.
-
-There is however a maximum limit of 10 000 cells that you are allowed to fetch in one go, an amount larger than that will cause an error. You therefore need to keep track of the number of columns you may need to ensure the total does not exceed 10 000. If you for example know that you will never need more than 4 columns, then you can set `qHeight` to `10000/4`:
-
-```js
-qInitialDataFetch: [{ qLeft: 0, qTop: 0, qHeight: 2500, qWidth: 4 }];
-```
-
-The initial data fetch only specifies the largest possible subsection of the entire hypercube in the layout, if there are only 7 rows in the hypercube then you will not get more than 7. You can also dynamically fetch more data later on.
-
-## Consuming the HyperCube
-
-The output, or _layout_, of the `HyperCubeDef` is a [HyperCube](https://core.qlik.com/services/qix-engine/apis/qix/definitions/#hypercube). In the layout it's located in the same place as you defined it in your properties, but without the `Def`, e.g. the input:
-
-```js
-{
- properties: {
- qHyperCubeDef: {},
- another: {
- one: {
- qHyperCubeDef: {}
- }
- }
- }
-}
-```
-
-will result in the output:
-
-```js
-{
- layout: {
- qHyperCube: {},
- another: {
- one: {
- qHyperCube: {}
- }
- }
- }
-}
-```
-
-Next to the `qDimensionInfo` and `qMeasureInfo` properties which contain your dimensions and measures, the most important part of the hypercube are the _data pages_.
-
-### Data pages
-
-The data pages are where the actual data values of the hypercube are contained, where exactly and what structure they have depends on the `qMode` value you set earlier. For mode `'S'` that place is `qDataPages`, which in turn contains `qArea` and `qMatrix`.
-
-Assuming the hypercube contains one dimension, _Movie title_, and one measure, _Average rating_, the content might look like this:
-
-```js
-qDataPages: [
- {
- qMatrix: [
- [
- // first row
- { qText: '2 Fast 2 Furious', qNum: 'NaN', qElemNumber: 447, qState: 'O' }, // NxCell
- { qText: '6.2', qNum: 6.2, qElemNumber: 0, qState: 'L' },
- ],
- [
- // second
- { qText: '2 Guns', qNum: 'NaN', qElemNumber: 681, qState: 'O' },
- { qText: '6.6', qNum: 6.6, qElemNumber: 0, qState: 'L' },
- ],
- ],
- qArea: { qTop: 0, qLeft: 0, qWidth: 2, qHeight: 2 },
- },
-];
-```
-
-Besides the textual and numerical values, each [NxCell](https://core.qlik.com/services/qix-engine/apis/qix/definitions/#nxcell) contains a `qElemNumber` property known as the _rank_. The rank for a dimension cell can be seen as a property that uniquely identifies the textual value of it in its field, across the entire data model. You can leverage this property to provide consistent behaviour throughout your application, you can for example set persistent color of the dimension values in a field whenever and wherever they are used:
-
-```js
-// color scheme
-const colors = ['#26A0A7', '#79D69F', '#F9EC86', '#EC983D'];
-
-const cellColor = colors[cell.qElemNumber % colors.length];
-```
-
-This property is also something you need to keep track of when you want to make selections in your chart.
-
-### Getting more data
-
-Due to the limitation of the amount of data you can get in the initial layout, there will be situations when you need to get the rest of the data if you want to show more of it. You can do so by using the methods exposed on the _model_ of the Generic Object. Which method to use depends, again, on the `qMode` of the hypercube, for the `'S'` mode it's [GetHyperCubeData](https://core.qlik.com/services/qix-engine/apis/qix/genericobject/#gethypercubedata).
-
-When paging data in straight mode, you should begin by looking at the `qHyperCubeDef.qSize` property which contains information on the width and height of the full hypercube. You can from that calculate the number of pages you need to fetch:
-
-```js
-import { useModel, useLayout, useEffect } from '@nebula.js/stardust';
-
-const NUM_CELLS_PER_PAGE = 10000;
-const MAX_PAGES = 10;
-// ...
-component() {
- const model = useModel();
- const layout = useLayout();
-
- useEffect(() => {
- const Y = layout.qHyperCube.qSize.qcy;
- const X = layout.qHyperCube.qSize.qcx;
-
- const HEIGHT_PER_PAGE = Math.ceil(NUM_CELLS_PER_PAGE / X);
- const NUM_PAGES = Math.floor(MAX_PAGES, Math.ceil(Y / HEIGHT_PER_PAGE));
-
- const pagesToFetch = [];
- for (let i = 0; i < NUM_PAGES; i++) {
- pagesToFetch.push({ qLeft: 0, qTop: i * HEIGHT_PER_PAGE, qHeight: HEIGHT_PER_PAGE, qWidth: X });
- }
-
- Promise.all(pagesToFetch.map((page) => model.getHyperCubeData('/qHyperCubeDef', [page]))).then((pages) => {
- console.log(pages);
- });
- }, [layout]);
-
-}
-```
-
-You should however be **very** careful when dynamically fetching data like this, keep in mind that the size of the cube can be in the millions, fetching a data set that large could take time and create a very poor user experience. In the example above the number of pages is set to a maximum of 10 so that no more than 100 000 values are fetched in total.
-
-You can also leverage other techniques to avoid fetching all data at once. _Virtual scrolling_ in combination with throttling of each request can boost performance tremendously. You should also consider using a reduced dataset if you don't need the exact values:
-
-- [getHyperCubeBinnedData](https://core.qlik.com/services/qix-engine/apis/qix/genericobject/#gethypercubebinneddata) binns data points into groups and is great for heatmaps and 2d density plots.
-- [getHyperCubeContinousData](https://core.qlik.com/services/qix-engine/apis/qix/genericobject/#gethypercubecontinuousdata) reduces the number of points in a continuous dimension and is great for temporal data.
-- [getHyperCubeReducedData](https://core.qlik.com/services/qix-engine/apis/qix/genericobject/#gethypercubereduceddata) does some wavelet magic and is great for mini charts.
diff --git a/docs/sn-introduction.md b/docs/sn-introduction.md
deleted file mode 100644
index 50854bf8c..000000000
--- a/docs/sn-introduction.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-id: sn-introduction
-title: Introduction
----
-
-## What is a visualization?
-
-A visualization in the context of this API represents the visual output of some underlying data stored in Qlik's Associative Data Model. It could be almost anything you want it to be and is traditionally developed to show the data in the shape of a chart, table, kpi etc.
-
-## Composition
-
-A visualization has two main parts: a backend _Generic Object_ that describes the _properties_ of the visualization and is persisted in the data model, and a frontend visual part that renders the _layout_ of the _Generic Object_.
-
-## Definition
-
-The minimal visualization that doesn't contain any data nor renders anything looks like this:
-
-```js
-export default function () {
- return {
- qae: {
- /* */
- },
- component() {},
- };
-}
-```
-
-The `component()` is where you render the visual part, while `qae` is where you define the properties and data handled by Qlik's Associative Engine (QAE).
diff --git a/docs/sn-selections.md b/docs/sn-selections.md
deleted file mode 100644
index ca18482c4..000000000
--- a/docs/sn-selections.md
+++ /dev/null
@@ -1,92 +0,0 @@
----
-id: sn-selections
-title: Selecting data
----
-
-Selections is a fundamental part of Qlik's Associative Engine. All fields and the associations between them are contained within the Associative Model. When you apply a selection you are not only applying a filter in the data model, but also exposing the associations between your data sources.
-
-## Applying selections
-
-Selections can be applied with methods exposed on the model returned from the `useModel` hook.
-
-Since a generic object can hold multiple hypercubes, you always need to specify which hypercube you want to select in by providing the JSON path of it as the first argument:
-
-```js
-import { useModel, useEffect } from '@nebula.js/stardust';
-// ...
-component() {
- const model = useModel();
-
- useEffect(() => {
- model.selectHyperCubeCells('/qHyperCubeDef', [1], []);
- }, [model])
-}
-```
-
-## Selection patterns
-
-There are two different patterns of selections: instant and modal.
-
-### Instant selections
-
-As the name indicates, this type of pattern is immediate and will filter both the source of the selections and everything that is affected by it.
-
-In the following example, as soon as a value is selected in the bar chart, the filtering is applied instantaneously and both charts are immediately updated with the filtered data:
-
-
-
-### Modal selections
-
-When a modal selection is initiated, the source of the selection enters a form of modal state that allows a user to modify selections before confirming the changes.
-
-In the following example, the user first selects one value in the bar chart, at which point other charts are updated just as before. The bar chart however still has all the data available and allows the user to select another value, before confirming the changes and updating the bar chart itself:
-
-
-
-To implement this type of pattern you need to `useSelections` instead of
-`useModel` and follow a few simple steps:
-
-1. Enter the modal state by calling `beginSelections`.
-1. Select values.
-1. Provide visual feedback to the user of what has been selected by for example changing the opacity of selected values.
-1. Keep track of when the modal state has been exited in order to reset the visual feedback.
-
-```js
-import { useSelections, useElement } from '@nebula.js/stardust';
-// ...
-component() {
- const element = useElement();
- const selections = useSelections();
-
- useEffect(() => {
- const clicked = () => {
- const clickedOnRow = 1;
-
- // 1. enter modal state if not already in it
- if (!selections.isActive()) {
- selections.beginSelections(['/qHyperCubeDef']);
- }
- // 2. select the clicked row
- selections.select({
- method: "selectHyperCubeCells",
- params: ['/qHyperCubeDef', [clickedOnRow], [column]]
- });
- }
-
- element.addEventListener('click', clicked);
- return () => {
- element.removeEventListener('click', clicked);
- }
- }, [element, model, selections]);
-
- useEffect(() => {
- if (layout.qSelectionInfo.qInSelections) {
- // 3. update with visual feedback on active selections
- // YOUR CODE HERE
- } else {
- // 4. normal update
- // YOUR CODE HERE
- }
- }, [layout]);
-}
-```
diff --git a/docs/sn-using-data.md b/docs/sn-using-data.md
deleted file mode 100644
index f025f7cef..000000000
--- a/docs/sn-using-data.md
+++ /dev/null
@@ -1,137 +0,0 @@
----
-id: sn-using-data
-title: Consuming data
----
-
-## Access layout
-
-You can access the _layout_ of the Generic Object through a set of predefined hooks.
-
-### useLayout
-
-`useLayout` returns the evalutated layout of the Generic Object's properties:
-
-```js
-import { useLayout } from '@nebula.js/stardust';
-
-export default function () {
- return {
- qae: {
- properties: {
- qHyperCubeDef: {},
- simpleMath: {
- qValueExpression: {
- qExpr: '1+1',
- },
- },
- },
- },
- component() {
- const layout = useLayout();
- console.log(layout); // { qHyperCube: {/* HyperCube Layout */}, simpleMath: 2 }
- },
- };
-}
-```
-
-You should `useEffect` when observing changes on the `layout`:
-
-```js
-const layout = useLayout();
-
-useEffect(() => {
- // do some heavy update
-}, [layout]);
-```
-
-### useAppLayout
-
-`useAppLayout` returns the [NxAppLayout](https://core.qlik.com/services/qix-engine/apis/qix/definitions/#nxapplayout) you are currently connected to:
-
-```js
-import { useAppLayout } from '@nebula.js/stardust';
-
-export default function () {
- return {
- component() {
- const appLayout = useAppLayout();
- console.log(appLayout); // { qTitle: 'App title', qLocaleInfo: {/* */ } }
- },
- };
-}
-```
-
-The most common use case for the app layout is to access `qLocaleInfo` which contains locale details selected by the app owner and should be used to format numbers.
-
-## Models
-
-In addition to the layouts of the app and generic object, you have full access to the APIs generated by `enigma.js`. These APIs are generated from a JSON-RPC schema and unlocks the full power of Qlik's Associate Engine.
-
-### useModel
-
-`useModel` returns the generated API of the [Generic Object](https://core.qlik.com/services/qix-engine/apis/qix/genericobject/):
-
-```js
-import { useModel } from '@nebula.js/stardust';
-
-export default function () {
- return {
- component() {
- const model = useModel();
- model.getInfo().then((info) => {
- console.log(info);
- });
- },
- };
-}
-```
-
-Common operations in this API is to:
-
-- make selections with `beginSelections`, `selectHyperCubeValues` and `endSelections`
-- get more data with `getHyperCubeData`
-
-### useApp
-
-`useApp` returns the generated API of the [Doc](https://core.qlik.com/services/qix-engine/apis/qix/doc/):
-
-```js
-import { useApp } from '@nebula.js/stardust';
-
-export default function () {
- return {
- component() {
- const app = useApp();
- app.clearAll();
- },
- };
-}
-```
-
-Common operations in this API is to:
-
-- modify the selection stack with `clearAll`, `back`, `forward`
-- create and apply bookmarks with `createBookmark` and `applyBookmark`
-
-### useGlobal
-
-`useGlobal` returns the generated API of the [Global](https://core.qlik.com/services/qix-engine/apis/qix/global/):
-
-```js
-import { useGlobal } from '@nebula.js/stardust';
-
-export default function () {
- return {
- component() {
- const g = useGlobal();
- g.engineVersion().then((v) => {
- console.log(v);
- });
- },
- };
-}
-```
-
-Common operations in this API is to:
-
-- get a list of apps with `getDocList`
diff --git a/docs/web-integration.md b/docs/web-integration.md
deleted file mode 100644
index e1a5b784b..000000000
--- a/docs/web-integration.md
+++ /dev/null
@@ -1,149 +0,0 @@
----
-id: web-integration
-title: Quick start
----
-
-This guide will walk you through creating a simple mashup that connects to Qlik Sense and visualizes some data.
-
-It will include the following steps:
-
-1. Setup a Qlik Cloud Services account
-1. Create a simple web project
-1. Configure connection
-1. Visualize data
-
-and requires that you have:
-
-- `node.js` `v10.0.0+` installed on your machine
-- A decent IDE, we recommend [VSCode](https://code.visualstudio.com/).
-
-## Setup a Qlik Cloud Services account
-
-Though `nebula.js` works and can be integrated with all Qlik Sense products, this will guide you on how to integrate with Qlik Cloud Services.
-
-Perform the following steps:
-
-1. [Register for a subscription on Qlik Cloud Services](https://help.qlik.com/en-US/cloud-services/Subsystems/Hub/Content/Sense_Hub/Introduction/qcs-register.htm).
-1. [Configure your deployment](https://help.qlik.com/en-US/cloud-services/Subsystems/Hub/Content/Sense_Hub/Introduction/qcs-tenant-domain.htm).
-1. [Create a new web integration](https://help.qlik.com/en-US/cloud-services/Subsystems/Hub/Content/Sense_Hub/Admin/mc-adminster-web-integrations.htm) from the [Management console](https://help.qlik.com/en-US/cloud-services/Subsystems/Hub/Content/Sense_Hub/Admin/management-console.htm).
- 1. You will later on run the mashup from your local machine, to allow this connection to happen you should add `http://localhost:1234` to the whitelist of origins.
- 1. Once the web integration has been created an ID will be assigned to it, this is the `qlik-web-integration-id` you will need later on.
-1. [Upload an app](https://help.qlik.com/en-US/cloud-services/Subsystems/Hub/Content/Sense_Hub/Apps/create-app-cloud-hub.htm)
- 1. If you don't have an app or data already prepared, you can [download the movies dataset](https://github.com/qlik-oss/nebula.js/raw/master/data/apps/the_movies.qvf) from the github repository and upload it to the cloud.
-
-Each app on QCS has a global unique identifier (GUID) which you will need later on.
-The GUID can be extracted from the URL and is the part that follows `/app`. For example, if the URL is `https://qcs.us.qlikcloud.com/sense/app/7fc4d85c-0e07-4160-90a9-c2ca4a45fd81`, then the GUID of the app is `7fc4d85c-0e07-4160-90a9-c2ca4a45fd81`.
-
-## Create a simple web project
-
-The quickest way to create a web project is to use the `nebula.js` command line interface:
-
-```bash
-npx @nebula.js/cli create mashup hello-qcs
-```
-
-The command will scaffold a web project into the `hello-qcs` folder with the following structure:
-
-- `/src`
- - `configure.js` - Initial configuration of `nebula.js`
- - `connect.js` - Connection setup with `enigma.js`
- - `index.html` - A minimal html page
- - `index.js` - Connect and visualize
-
-`/src/index.js` is where you will need to make modifications later on to bring everything together.
-
-## Configure connection
-
-To configure the connection you will need:
-
-- The QCS tenant url.
-- The qlik-web-integration-id.
-- the GUID of the app you want to open.
-
-Open up `src/index.js` and update the `<>` placeholders with the correct values, for example:
-
-```js
-const app = await connect({
- url: 'https://qcs.us.qlikcloud.com',
- webIntegrationId: '8Ys9sBVyq6i2lxtclPWaaZhQr7OgwKaT',
- appId: '7fc4d85c-0e07-4160-90a9-c2ca4a45fd81',
-});
-```
-
-## Visualize data
-
-The movies dataset you uploaded earlier has a bar chart on the first sheet with the id `EAjjuyE`, you can render that same bar chart in your mashup by providing the id and an element to render the visualization into:
-
-```js
-n.render({
- element: document.querySelector('.object'),
- id: 'EAjjuyE',
-});
-```
-
-Start the web development server by executing the following in a terminal:
-
-```sh
-npm run start
-```
-
-The server will run on [http://localhost:1234](http://localhost:1234).
-
-When opening the page, you may be re-routed to your QCS tenant to login if the session timed out since you did the setup. Once logged in, you will be re-routed back to the develoment server where you should see the same bar chart:
-
-
-
-The visualization is fully interactive, any selections you make will be reflected in the current app selections toolbar at the top.
-
-## More visualizations
-
-### Render on the fly
-
-You can render a visualization without having to create it in the app by providing the `type` and some data `fields`:
-
-```js
-n.render({
- element: document.querySelector('.object'),
- type: 'barchart',
- fields: ['title', '=avg(rating')],
-});
-```
-
-### More types
-
-The core `stardust` module does not contain any visualizations, each visualization is its own separate module and needs to be loaded and registered before it can be used.
-
-Official visualizations from Qlik are published under the `@nebula.js` scope and are prefixed with `sn-`.
-
-The available visualizations are as follows:
-
-- Bar chart: `@nebula.js/sn-bar-chart`
-- Line chart: `@nebula.js/sn-line-chart`
-- Pie chart: `@nebula.js/sn-pie-chart`
-- Sankey chart: `@nebula.js/sn-sankey-chart`
-- Funnel chart: `@nebula.js/sn-funnel-chart`
-- Mekko chart: `@nebula.js/sn-mekko-chart`
-
-The template you created your mashup from only includes the `bar-chart` module, you can add more types by installing each one you want to use:
-
-```bash
-npm install @nebula.js/sn-pie-chart
-```
-
-Then modify `/src/configure.js` to include the new modules:
-
-```js
-import piechart from '@nebula.js/sn-pie-chart';
-//...
-
-embed.createConfiguration({
- // ...
- types: [
- // ...
- {
- name: 'piechart',
- load: () => Promise.resolve(piechart),
- },
- ],
-});
-```