+import {kebabToCamel, camelToKebab} from "./text";
+
+/**
+ * A mapping of active components keyed by name, with values being arrays of component
+ * instances since there can be multiple components of the same type.
+ * @type {Object<String, Component[]>}
+ */
const components = {};
-const componentMap = {};
+
+/**
+ * A mapping of component class models, keyed by name.
+ * @type {Object<String, Constructor<Component>>}
+ */
+const componentModelMap = {};
+
+/**
+ * A mapping of active component maps, keyed by the element components are assigned to.
+ * @type {WeakMap<Element, Object<String, Component>>}
+ */
+const elementComponentMap = new WeakMap();
/**
* Initialize a component instance on the given dom element.
*/
function initComponent(name, element) {
/** @type {Function<Component>|undefined} **/
- const componentModel = componentMap[name];
+ const componentModel = componentModelMap[name];
if (componentModel === undefined) return;
// Create our component instance
}
components[name].push(instance);
- // Add to element listing
- if (typeof element.components === 'undefined') {
- element.components = {};
- }
- element.components[name] = instance;
+ // Add to element mapping
+ const elComponents = elementComponentMap.get(element) || {};
+ elComponents[name] = instance;
+ elementComponentMap.set(element, elComponents);
}
/**
return opts;
}
-/**
- * Convert a kebab-case string to camelCase
- * @param {String} kebab
- * @returns {string}
- */
-function kebabToCamel(kebab) {
- const ucFirst = (word) => word.slice(0,1).toUpperCase() + word.slice(1);
- const words = kebab.split('-');
- return words[0] + words.slice(1).map(ucFirst).join('');
-}
-
/**
* Initialize all components found within the given element.
* @param {Element|Document} parentElement
export function register(mapping) {
const keys = Object.keys(mapping);
for (const key of keys) {
- componentMap[camelToKebab(key)] = mapping[key];
+ componentModelMap[camelToKebab(key)] = mapping[key];
}
}
* @param {String} name
* @returns {Component[]}
*/
-export function get(name = '') {
+export function get(name) {
return components[name] || [];
}
-function camelToKebab(camelStr) {
- return camelStr.replace(/[A-Z]/g, (str, offset) => (offset > 0 ? '-' : '') + str.toLowerCase());
+/**
+ * Get the first component, of the given name, that's assigned to the given element.
+ * @param {Element} element
+ * @param {String} name
+ * @returns {Component|null}
+ */
+export function firstOnElement(element, name) {
+ const elComponents = elementComponentMap.get(element) || {};
+ return elComponents[name] || null;
}
\ No newline at end of file