UNPKG

@v4fire/client

Version:

V4Fire client core library

227 lines (182 loc) 4.46 kB
/*! * V4Fire Client Core * https://github.com/V4Fire/Client * * Released under the MIT license * https://github.com/V4Fire/Client/blob/master/LICENSE */ /** * [[include:super/i-block/modules/mods/README.md]] * @packageDocumentation */ import type iBlock from 'super/i-block/i-block'; import type { ModsTable, ModsNTable } from 'super/i-block/modules/mods/interface'; export * from 'super/i-block/modules/mods/interface'; /** * Merges old component modifiers with new modifiers * (for functional components) * * @param component * @param oldComponent * @param key - field key * @param link - link key */ export function mergeMods( component: iBlock, oldComponent: iBlock, key: string, link?: string ): void { if (link == null) { return; } const ctx = component.unsafe, cache = ctx.$syncLinkCache.get(link); if (!cache) { return; } const l = cache[key]; if (!l) { return; } const getFullModsProp = (o) => { const declMods = o.meta.component.mods, res = {...o.$props[link]}; for (let attrs = o.$attrs, keys = Object.keys(attrs), i = 0; i < keys.length; i++) { const key = keys[i]; if (key in declMods) { const attrVal = attrs[key]; if (attrVal != null) { res[key] = attrVal; } } } return res; }; const modsProp = getFullModsProp(ctx), mods = {...oldComponent.mods}; for (let keys = Object.keys(mods), i = 0; i < keys.length; i++) { const key = keys[i]; if (ctx.sync.syncModCache[key]) { delete mods[key]; } } if (Object.fastCompare(modsProp, getFullModsProp(oldComponent))) { l.sync(mods); } else { l.sync(Object.assign(mods, modsProp)); } } /** * Initializes the component modifiers * @param component */ export function initMods(component: iBlock): ModsNTable { const ctx = component.unsafe, declMods = ctx.meta.component.mods; const attrMods = <string[][]>[], modVal = (val) => val != null ? String(val) : undefined; for (let attrs = ctx.$attrs, keys = Object.keys(attrs), i = 0; i < keys.length; i++) { const key = keys[i], modKey = key.camelize(false); if (modKey in declMods) { const attrVal = attrs[key]; attrs[key] = undefined; ctx.watch(`$attrs.${key}`, (val: Dictionary = {}) => { ctx.$el?.removeAttribute(key); void ctx.setMod(modKey, modVal(val[key])); }); if (attrVal == null) { continue; } attrMods.push([modKey, attrVal]); } } function link(propMods: CanUndef<ModsTable>): ModsNTable { const mods = Object.isDictionary(ctx.mods) ? ctx.mods : {...declMods}; if (propMods != null) { for (let keys = Object.keys(propMods), i = 0; i < keys.length; i++) { const key = keys[i], val = propMods[key]; if (val != null || mods[key] == null) { mods[key] = modVal(val); } } } for (let i = 0; i < attrMods.length; i++) { const [key, val] = attrMods[i]; mods[key] = val; } const {experiments} = ctx.r.remoteState; if (Object.isArray(experiments)) { for (let i = 0; i < experiments.length; i++) { const el = experiments[i], experimentMods = el.meta?.mods; if (experimentMods) { for (let keys = Object.keys(experimentMods), i = 0; i < keys.length; i++) { const key = keys[i], val = experimentMods[key]; if (val != null || mods[key] == null) { mods[key] = modVal(val); } } } } } for (let keys = Object.keys(mods), i = 0; i < keys.length; i++) { const key = keys[i], val = modVal(mods[key]); mods[key] = val; if (ctx.hook !== 'beforeDataCreate') { void ctx.setMod(key, val); } } return mods; } return Object.cast(ctx.sync.link(link)); } /** * Returns a dictionary with watchable modifiers * @param component */ export function getWatchableMods(component: iBlock): Readonly<ModsNTable> { const watchMods = {}, watchers = component.field.get<ModsNTable>('watchModsStore')!, systemMods = component.mods; for (let keys = Object.keys(systemMods), i = 0; i < keys.length; i++) { const key = keys[i]; if (key in watchers) { watchMods[key] = systemMods[key]; } else { Object.defineProperty(watchMods, key, { configurable: true, enumerable: true, get: () => { if (!(key in watchers)) { Object.getPrototypeOf(watchers)[key] = systemMods[key]; } return watchers[key]; } }); } } return Object.freeze(watchMods); }