import Cetra from '../../lib/lib.js'; /** * Represents a base component class. */ export default class BaseComponent { #data = new Map([ ['type', 'BaseComponent'], ['selector', 'cetra-component'], ['variables', new Map()], ['cetraId', ''], ]); /** * Constructs a new instance of the BaseComponent class. * @param {Map} data - The initial data for the component. */ constructor(data = new Map()) { for (const key of this.#data.keys()) { if ( !data.has(key) || typeof data.get(key) != typeof this.#data.get(key) ) continue; this.#data.set(key, data.get(key)); } this.#data = data; } /** * Retrieves the value associated with the specified key from the data map. * @param {string} key - The key to retrieve the value for. * @returns {*} - The value associated with the key. */ get(key) { return this.#data.get(key); } /** * Sets a key-value pair in the component's data. * @param {string} key - The key to set. * @param {*} value - The value to set. * @returns {BaseComponent} - The updated component instance. */ set(key, value) { this.#data.set(key, value); return this; } /** * Retrieves the value of a variable by its name. * * @param {string} varName - The name of the variable. * @returns {*} - The value of the variable, or null if the variable is not found. * @throws {Error} - If no Cetra instance is found. */ getValue(varName) { if (typeof varName != 'string') return null; if (varName.startsWith('$')) varName = varName.slice(1); if (!this.get('variables').has(varName)) return null; const frameWork = Cetra.getInstance(this.get('cetraId')); if (!frameWork) throw new Error('no cetra instance found'); const varValue = frameWork.convertValue( this.get('variables').get(varName).get('type'), this.getVarNodes(varName).shift().textContent ); return varValue; } /** * Retrieves the value of a variable. * @param {string} varName - The name of the variable. * @returns {*} - The value of the variable. */ getVal(varName) { return this.getValue(varName); } /** * Retrieves the value of a variable by its name. * * @param {string} varName - The name of the variable. * @returns {*} - The value of the variable. */ getVar(varName) { return this.get('variables').get(varName); } /** * Retrieves the DOM node associated with the component. * @returns {HTMLElement} The DOM node. * @throws {Error} If no node is found. */ getNode() { let node = document.querySelector(this.get('selector')); if (!node) node = document.getElementById(this.get('id')); if (!node) throw new Error('no node found'); return node; } /** * Retrieves all DOM nodes that have a data attribute matching the specified variable name. * @param {string} varName - The name of the variable to search for. * @returns {Array} - An array of DOM nodes matching the variable name. * @throws {Error} - Throws an error if no cetra instance is found. */ getVarNodes(varName) { const frameWork = Cetra.getInstance(this.get('cetraId')); if (!frameWork) throw new Error('no cetra instance found'); const varNodeSelector = `[data-${frameWork.getOption( 'selector' )}-var^="${varName}"]`; return [...this.getNode().querySelectorAll(varNodeSelector)]; } /** * Updates the component with the given deltas. * @param {Array} deltas - An array of deltas to apply. * @throws {TypeError} If deltas is not an array. * @throws {Error} If no cetra instance is found. */ update(deltas) { if (!Array.isArray(deltas)) throw new TypeError('deltas must be an array'); const frameWork = Cetra.getInstance(this.get('cetraId')); if (!frameWork) throw new Error('no cetra instance found'); for (const delta of deltas) { const { new: value, old: oldValue, varName } = delta; if (!this.get('variables').has(varName)) continue; const variable = this.get('variables').get(varName); this.getVarNodes(varName).forEach((el) => { el.textContent = value ?? variable.get('default'); }); } } }