UNPKG

@studiometa/js-toolkit

Version:

A set of useful little bits of JavaScript to boost your project! 🚀

171 lines (170 loc) • 5.05 kB
import deepmerge from "deepmerge"; import { AbstractManager } from "./AbstractManager.js"; import { isDev, isFunction, isDefined, isBoolean, isArray, isObject, memo } from "../../utils/index.js"; import { features } from "../features.js"; const types = /* @__PURE__ */ new Set([String, Number, Boolean, Array, Object]); const __defaultValues = { String: "", Number: 0, Boolean: false, Array: () => [], Object: () => ({}) }; const UPPERCASE_REGEX = /([A-Z])/g; const __getPropertyName = memo(function __getPropertyName2(name, prefix = "", optionAttribute = features.get("attributes").option) { return `${optionAttribute}${prefix ? `-${prefix}` : ""}-${name.replaceAll(UPPERCASE_REGEX, "-$1")}`; }); class OptionsManager extends AbstractManager { /** * An object to store Array and Object values for reference. * * @private */ __values = {}; /** * Default props. */ __props = { name: "Base", debug: false, log: false }; /** * Class constructor. */ constructor(base) { super(base); const schema = this.__config.options || {}; this.props.name = this.__config.name; schema.debug = { type: Boolean, default: this.__config.debug ?? false }; schema.log = { type: Boolean, default: this.__config.log ?? false }; for (const [name, config] of Object.entries(schema)) { this.__register( name, types.has(config) ? { type: config } : config ); } } /** * Get an option value. */ get(name, config) { const { type } = config; const defaultValue = isFunction(config.default) ? config.default(this.__base) : config.default; const attributes = features.get("attributes"); const propertyName = __getPropertyName(name, "", attributes.option); const hasProperty = this.__element.hasAttribute(propertyName); if (type === Boolean) { if (defaultValue) { const negatedPropertyName = __getPropertyName(name, "no", attributes.option); const hasNegatedProperty = this.__element.hasAttribute(negatedPropertyName); return !hasNegatedProperty; } return hasProperty || defaultValue; } const value = this.__element.getAttribute(propertyName); if (type === Number) { return hasProperty ? Number(value) : defaultValue; } if (type === Array || type === Object) { config = type === Array ? config : config; if (!this.__values[name]) { let val = hasProperty ? JSON.parse(value) : defaultValue; if (isDefined(config.merge)) { val = isBoolean(config.merge) ? deepmerge(defaultValue, val) : deepmerge(defaultValue, val, config.merge); } this.__values[name] = val; } return this.__values[name]; } return hasProperty ? value : defaultValue; } /** * Set an option value. */ set(name, value, config) { const { type, default: defaultValue } = config; const attributes = features.get("attributes"); const propertyName = __getPropertyName(name, "", attributes.option); if (value.constructor.name !== type.name) { if (isDev) { const val = isArray(value) || isObject(value) ? JSON.stringify(value) : value; throw new TypeError( `The "${val}" value for the "${name}" option must be of type "${type.name}"` ); } return; } switch (type) { case Boolean: if (defaultValue) { const negatedPropertyName = __getPropertyName(name, "no", attributes.option); if (value) { this.__element.removeAttribute(negatedPropertyName); } else { this.__element.setAttribute(negatedPropertyName, ""); } } else if (value) { this.__element.setAttribute(propertyName, ""); } else { this.__element.removeAttribute(propertyName); } break; case Array: case Object: this.__values[name] = value; break; default: this.__element.setAttribute(propertyName, value); } } /** * Register an option. * @private */ __register(name, config) { if (!types.has(config.type)) { if (isDev) { throw new Error( `The "${name}" option has an invalid type. The allowed types are: String, Number, Boolean, Array and Object.` ); } return; } config.default = config.default ?? __defaultValues[config.type.name]; if ((config.type === Array || config.type === Object) && !isFunction(config.default)) { if (isDev) { throw new Error( `The default value for options of type "${config.type.name}" must be returned by a function.` ); } return; } Object.defineProperty(this.props, name, { get: () => this.get(name, config), set: (value) => { this.set(name, value, config); }, enumerable: true }); } } export { OptionsManager, __getPropertyName }; //# sourceMappingURL=OptionsManager.js.map