implemented frontend including separate message system; started to implement backend
This commit is contained in:
437
yjs-poll/node_modules/lib0/dist/component.cjs
generated
vendored
Normal file
437
yjs-poll/node_modules/lib0/dist/component.cjs
generated
vendored
Normal file
@@ -0,0 +1,437 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
var dom = require('./dom-7e625b09.cjs');
|
||||
var diff = require('./diff-9d236524.cjs');
|
||||
var object = require('./object-c0c9435b.cjs');
|
||||
var json = require('./json-092190a1.cjs');
|
||||
var string = require('./string-fddc5f8b.cjs');
|
||||
var array = require('./array-78849c95.cjs');
|
||||
var number = require('./number-1fb57bba.cjs');
|
||||
var _function = require('./function-314580f7.cjs');
|
||||
require('./pair-ab022bc3.cjs');
|
||||
require('./map-24d263c0.cjs');
|
||||
require('./schema.cjs');
|
||||
require('./error-0c1f634f.cjs');
|
||||
require('./environment-1c97264d.cjs');
|
||||
require('./conditions-f5c0c102.cjs');
|
||||
require('./storage.cjs');
|
||||
require('./equality.cjs');
|
||||
require('./prng-37d48618.cjs');
|
||||
require('./binary-ac8e39e2.cjs');
|
||||
require('./math-96d5e8c4.cjs');
|
||||
require('./buffer-3e750729.cjs');
|
||||
require('./encoding-1a745c43.cjs');
|
||||
require('./decoding-76e75827.cjs');
|
||||
require('./set-5b47859e.cjs');
|
||||
|
||||
/* eslint-env browser */
|
||||
|
||||
/**
|
||||
* @type {CustomElementRegistry}
|
||||
*/
|
||||
const registry = customElements;
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {any} constr
|
||||
* @param {ElementDefinitionOptions} [opts]
|
||||
*/
|
||||
const define = (name, constr, opts) => registry.define(name, constr, opts);
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @return {Promise<CustomElementConstructor>}
|
||||
*/
|
||||
const whenDefined = name => registry.whenDefined(name);
|
||||
|
||||
const upgradedEventName = 'upgraded';
|
||||
const connectedEventName = 'connected';
|
||||
const disconnectedEventName = 'disconnected';
|
||||
|
||||
/**
|
||||
* @template S
|
||||
*/
|
||||
class Lib0Component extends HTMLElement {
|
||||
/**
|
||||
* @param {S} [state]
|
||||
*/
|
||||
constructor (state) {
|
||||
super();
|
||||
/**
|
||||
* @type {S|null}
|
||||
*/
|
||||
this.state = /** @type {any} */ (state);
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
this._internal = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {S} _state
|
||||
* @param {boolean} [_forceStateUpdate] Force that the state is rerendered even if state didn't change
|
||||
*/
|
||||
setState (_state, _forceStateUpdate = true) {}
|
||||
|
||||
/**
|
||||
* @param {any} _stateUpdate
|
||||
*/
|
||||
updateState (_stateUpdate) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} val
|
||||
* @param {"json"|"string"|"number"} type
|
||||
* @return {string}
|
||||
*/
|
||||
const encodeAttrVal = (val, type) => {
|
||||
if (type === 'json') {
|
||||
val = json.stringify(val);
|
||||
}
|
||||
return val + ''
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} val
|
||||
* @param {"json"|"string"|"number"|"bool"} type
|
||||
* @return {any}
|
||||
*/
|
||||
const parseAttrVal = (val, type) => {
|
||||
switch (type) {
|
||||
case 'json':
|
||||
return json.parse(val)
|
||||
case 'number':
|
||||
return Number.parseFloat(val)
|
||||
case 'string':
|
||||
return val
|
||||
case 'bool':
|
||||
return val != null
|
||||
default:
|
||||
return null
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @template S
|
||||
* @typedef {Object} CONF
|
||||
* @property {string?} [CONF.template] Template for the shadow dom.
|
||||
* @property {string} [CONF.style] shadow dom style. Is only used when
|
||||
* `CONF.template` is defined
|
||||
* @property {S} [CONF.state] Initial component state.
|
||||
* @property {function(S,S|null,Lib0Component<S>):void} [CONF.onStateChange] Called when
|
||||
* the state changes.
|
||||
* @property {Object<string,function(any, any):Object>} [CONF.childStates] maps from
|
||||
* CSS-selector to transformer function. The first element that matches the
|
||||
* CSS-selector receives state updates via the transformer function.
|
||||
* @property {Object<string,"json"|"number"|"string"|"bool">} [CONF.attrs]
|
||||
* attrs-keys and state-keys should be camelCase, but the DOM uses kebap-case. I.e.
|
||||
* `attrs = { myAttr: 4 }` is represeted as `<my-elem my-attr="4" />` in the DOM
|
||||
* @property {Object<string, function(CustomEvent, Lib0Component<any>):boolean|void>} [CONF.listeners] Maps from dom-event-name
|
||||
* to event listener.
|
||||
* @property {function(S, S, Lib0Component<S>):Object<string,string>} [CONF.slots] Fill slots
|
||||
* automatically when state changes. Maps from slot-name to slot-html.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {string} name
|
||||
* @param {CONF<T>} cnf
|
||||
* @return {typeof Lib0Component}
|
||||
*/
|
||||
const createComponent = (name, { template, style = '', state: defaultState, onStateChange = () => {}, childStates = { }, attrs = {}, listeners = {}, slots = () => ({}) }) => {
|
||||
/**
|
||||
* Maps from camelCase attribute name to kebap-case attribute name.
|
||||
* @type {Object<string,string>}
|
||||
*/
|
||||
const normalizedAttrs = {};
|
||||
for (const key in attrs) {
|
||||
normalizedAttrs[string.fromCamelCase(key, '-')] = key;
|
||||
}
|
||||
const templateElement = template
|
||||
? /** @type {HTMLTemplateElement} */ (dom.parseElement(`
|
||||
<template>
|
||||
<style>${style}</style>
|
||||
${template}
|
||||
</template>
|
||||
`))
|
||||
: null;
|
||||
|
||||
class _Lib0Component extends HTMLElement {
|
||||
/**
|
||||
* @param {T} [state]
|
||||
*/
|
||||
constructor (state) {
|
||||
super();
|
||||
/**
|
||||
* @type {Array<{d:Lib0Component<T>, s:function(any, any):Object}>}
|
||||
*/
|
||||
this._childStates = [];
|
||||
/**
|
||||
* @type {Object<string,string>}
|
||||
*/
|
||||
this._slots = {};
|
||||
this._init = false;
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
this._internal = {};
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
this.state = state || null;
|
||||
this.connected = false;
|
||||
// init shadow dom
|
||||
if (templateElement) {
|
||||
const shadow = /** @type {ShadowRoot} */ (this.attachShadow({ mode: 'open' }));
|
||||
shadow.appendChild(templateElement.content.cloneNode(true));
|
||||
// fill child states
|
||||
for (const key in childStates) {
|
||||
this._childStates.push({
|
||||
d: /** @type {Lib0Component<T>} */ (dom.querySelector(/** @type {any} */ (shadow), key)),
|
||||
s: childStates[key]
|
||||
});
|
||||
}
|
||||
}
|
||||
dom.emitCustomEvent(this, upgradedEventName, { bubbles: true });
|
||||
}
|
||||
|
||||
connectedCallback () {
|
||||
this.connected = true;
|
||||
if (!this._init) {
|
||||
this._init = true;
|
||||
const shadow = this.shadowRoot;
|
||||
if (shadow) {
|
||||
dom.addEventListener(shadow, upgradedEventName, event => {
|
||||
this.setState(this.state, true);
|
||||
event.stopPropagation();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @type {Object<string, any>}
|
||||
*/
|
||||
const startState = this.state || object.assign({}, defaultState);
|
||||
if (attrs) {
|
||||
for (const key in attrs) {
|
||||
const normalizedKey = string.fromCamelCase(key, '-');
|
||||
const val = parseAttrVal(this.getAttribute(normalizedKey), attrs[key]);
|
||||
if (val) {
|
||||
startState[key] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
// add event listeners
|
||||
for (const key in listeners) {
|
||||
dom.addEventListener(shadow || this, key, event => {
|
||||
if (listeners[key](/** @type {CustomEvent} */ (event), this) !== false) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
return false
|
||||
}
|
||||
});
|
||||
}
|
||||
// first setState call
|
||||
this.state = null;
|
||||
this.setState(startState);
|
||||
}
|
||||
dom.emitCustomEvent(/** @type {any} */ (this.shadowRoot || this), connectedEventName, { bubbles: true });
|
||||
}
|
||||
|
||||
disconnectedCallback () {
|
||||
this.connected = false;
|
||||
dom.emitCustomEvent(/** @type {any} */ (this.shadowRoot || this), disconnectedEventName, { bubbles: true });
|
||||
this.setState(null);
|
||||
}
|
||||
|
||||
static get observedAttributes () {
|
||||
return object.keys(normalizedAttrs)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {string} oldVal
|
||||
* @param {string} newVal
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
attributeChangedCallback (name, oldVal, newVal) {
|
||||
const curState = /** @type {any} */ (this.state);
|
||||
const camelAttrName = normalizedAttrs[name];
|
||||
const type = attrs[camelAttrName];
|
||||
const parsedVal = parseAttrVal(newVal, type);
|
||||
if (curState && (type !== 'json' || json.stringify(curState[camelAttrName]) !== newVal) && curState[camelAttrName] !== parsedVal && !number.isNaN(parsedVal)) {
|
||||
this.updateState({ [camelAttrName]: parsedVal });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} stateUpdate
|
||||
*/
|
||||
updateState (stateUpdate) {
|
||||
this.setState(object.assign({}, this.state, stateUpdate));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} state
|
||||
*/
|
||||
setState (state, forceStateUpdates = false) {
|
||||
const prevState = this.state;
|
||||
this.state = state;
|
||||
if (this._init && (!_function.equalityFlat(state, prevState) || forceStateUpdates)) {
|
||||
// fill slots
|
||||
if (state) {
|
||||
const slotElems = slots(state, prevState, this);
|
||||
for (const key in slotElems) {
|
||||
const slotContent = slotElems[key];
|
||||
if (this._slots[key] !== slotContent) {
|
||||
this._slots[key] = slotContent;
|
||||
const currentSlots = /** @type {Array<any>} */ (key !== 'default' ? array.from(dom.querySelectorAll(this, `[slot="${key}"]`)) : array.from(this.childNodes).filter(/** @param {any} child */ child => !dom.checkNodeType(child, dom.ELEMENT_NODE) || !child.hasAttribute('slot')));
|
||||
currentSlots.slice(1).map(dom.remove);
|
||||
const nextSlot = dom.parseFragment(slotContent);
|
||||
if (key !== 'default') {
|
||||
array.from(nextSlot.children).forEach(c => c.setAttribute('slot', key));
|
||||
}
|
||||
if (currentSlots.length > 0) {
|
||||
dom.replaceWith(currentSlots[0], nextSlot);
|
||||
} else {
|
||||
dom.appendChild(this, nextSlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onStateChange(state, prevState, this);
|
||||
if (state != null) {
|
||||
this._childStates.forEach(cnf => {
|
||||
const d = cnf.d;
|
||||
if (d.updateState) {
|
||||
d.updateState(cnf.s(state, this));
|
||||
}
|
||||
});
|
||||
}
|
||||
for (const key in attrs) {
|
||||
const normalizedKey = string.fromCamelCase(key, '-');
|
||||
if (state == null) {
|
||||
this.removeAttribute(normalizedKey);
|
||||
} else {
|
||||
const stateVal = state[key];
|
||||
const attrsType = attrs[key];
|
||||
if (!prevState || prevState[key] !== stateVal) {
|
||||
if (attrsType === 'bool') {
|
||||
if (stateVal) {
|
||||
this.setAttribute(normalizedKey, '');
|
||||
} else {
|
||||
this.removeAttribute(normalizedKey);
|
||||
}
|
||||
} else if (stateVal == null && (attrsType === 'string' || attrsType === 'number')) {
|
||||
this.removeAttribute(normalizedKey);
|
||||
} else {
|
||||
this.setAttribute(normalizedKey, encodeAttrVal(stateVal, attrsType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
define(name, _Lib0Component);
|
||||
// @ts-ignore
|
||||
return _Lib0Component
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {function} definer function that defines a component when executed
|
||||
*/
|
||||
const createComponentDefiner = definer => {
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
let defined = null;
|
||||
return () => {
|
||||
if (!defined) {
|
||||
defined = definer();
|
||||
}
|
||||
return defined
|
||||
}
|
||||
};
|
||||
|
||||
const defineListComponent = createComponentDefiner(() => {
|
||||
const ListItem = createComponent('lib0-list-item', {
|
||||
template: '<slot name="content"></slot>',
|
||||
slots: state => ({
|
||||
content: `<div>${state}</div>`
|
||||
})
|
||||
});
|
||||
return createComponent('lib0-list', {
|
||||
state: { list: /** @type {Array<string>} */ ([]), Item: ListItem },
|
||||
onStateChange: (state, prevState, component) => {
|
||||
if (state == null) {
|
||||
return
|
||||
}
|
||||
const { list = /** @type {Array<any>} */ ([]), Item = ListItem } = state;
|
||||
// @todo deep compare here by providing another parameter to simpleDiffArray
|
||||
let { index, remove, insert } = diff.simpleDiffArray(prevState ? prevState.list : [], list, _function.equalityFlat);
|
||||
if (remove === 0 && insert.length === 0) {
|
||||
return
|
||||
}
|
||||
let child = /** @type {Lib0Component<any>} */ (component.firstChild);
|
||||
while (index-- > 0) {
|
||||
child = /** @type {Lib0Component<any>} */ (child.nextElementSibling);
|
||||
}
|
||||
let insertStart = 0;
|
||||
while (insertStart < insert.length && remove-- > 0) {
|
||||
// update existing state
|
||||
child.setState(insert[insertStart++]);
|
||||
child = /** @type {Lib0Component<any>} */ (child.nextElementSibling);
|
||||
}
|
||||
while (remove-- > 0) {
|
||||
// remove remaining
|
||||
const prevChild = child;
|
||||
child = /** @type {Lib0Component<any>} */ (child.nextElementSibling);
|
||||
component.removeChild(prevChild);
|
||||
}
|
||||
// insert remaining
|
||||
component.insertBefore(dom.fragment(insert.slice(insertStart).map(/** @param {any} insState */ insState => {
|
||||
const el = new Item();
|
||||
el.setState(insState);
|
||||
return el
|
||||
})), child);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const defineLazyLoadingComponent = createComponentDefiner(() => createComponent('lib0-lazy', {
|
||||
state: /** @type {{component:null|String,import:null|function():Promise<any>,state:null|object}} */ ({
|
||||
component: null, import: null, state: null
|
||||
}),
|
||||
attrs: {
|
||||
component: 'string'
|
||||
},
|
||||
onStateChange: ({ component, state, import: getImport }, prevState, componentEl) => {
|
||||
if (component !== null) {
|
||||
if (getImport) {
|
||||
getImport();
|
||||
}
|
||||
if (!prevState || component !== prevState.component) {
|
||||
const el = /** @type {any} */ (dom.createElement(component));
|
||||
componentEl.innerHTML = '';
|
||||
componentEl.insertBefore(el, null);
|
||||
}
|
||||
const el = /** @type {any} */ (componentEl.firstElementChild);
|
||||
// @todo generalize setting state and check if setState is defined
|
||||
if (el.setState) {
|
||||
el.setState(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
exports.Lib0Component = Lib0Component;
|
||||
exports.createComponent = createComponent;
|
||||
exports.createComponentDefiner = createComponentDefiner;
|
||||
exports.define = define;
|
||||
exports.defineLazyLoadingComponent = defineLazyLoadingComponent;
|
||||
exports.defineListComponent = defineListComponent;
|
||||
exports.registry = registry;
|
||||
exports.whenDefined = whenDefined;
|
||||
//# sourceMappingURL=component.cjs.map
|
||||
Reference in New Issue
Block a user