Skip to content

Commit

Permalink
feat(esl-utils): extend attr decorator with inherit option to take …
Browse files Browse the repository at this point in the history
…over the value of declared attribute
  • Loading branch information
NastaLeo committed Feb 12, 2024
1 parent 39e7dca commit b29acde
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 5 deletions.
17 changes: 12 additions & 5 deletions src/modules/esl-utils/decorators/attr.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {identity, resolveProperty} from '../misc/functions';
import {parseString, toKebabCase} from '../misc/format';
import {getAttr, setAttr} from '../dom/attr';
import {getAttr, getClosestAttr, setAttr} from '../dom/attr';

import type {PropertyProvider} from '../misc/functions';
import type {ESLAttributeDecorator} from '../dom/attr';
Expand All @@ -15,6 +15,13 @@ type AttrDescriptor<T = string> = {
name?: string;
/** Create getter only */
readonly?: boolean;
/** Find value to inherit across closest elements in DOM tree based on declared attribute name (in case of string format)
* or same attribute name of current element (boolean value).
* Example, attribute 'ignore' with configuration:
* inherit: 'alt-ignore' - searches ignore or data-ignore attr (in case of dataAttr: true) on this element or alt-ignore attribute on closest parent
* inherit: true - searches ignore or data-ignore attr (in case of dataAttr: true) on this element or on closest parent
*/
inherit?: boolean | string;
/** Use data-* attribute */
dataAttr?: boolean;
/** Default property value. Used if no attribute is present on the element. Empty string by default. Supports provider function. */
Expand All @@ -36,14 +43,14 @@ const buildAttrName =
export const attr = <T = string>(config: AttrDescriptor<T> = {}): ESLAttributeDecorator => {
return (target: ESLDomElementTarget, propName: string): any => {
const attrName = buildAttrName(config.name || propName, !!config.dataAttr);
const closestAttrName = typeof config.inherit === 'string' ? config.inherit : attrName;

function get(): T | null {
const val = getAttr(this, attrName);
if (val === null && 'defaultValue' in config) {
return resolveProperty(config.defaultValue, this) as T;
}
const val = config.inherit ? getClosestAttr(this, closestAttrName) || getAttr(this, attrName) : getAttr(this, attrName);
if (val === null && 'defaultValue' in config) return resolveProperty(config.defaultValue, this) as T;
return (config.parser || parseString as AttrParser<any>)(val);
}

function set(value: T): void {
setAttr(this, attrName, (config.serializer as AttrSerializer<any> || identity)(value));
}
Expand Down
7 changes: 7 additions & 0 deletions src/modules/esl-utils/dom/attr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,10 @@ export function setAttr($el: ESLAttributeTarget, name: string, value: undefined
$el.setAttribute(name, value === true ? '' : value);
}
}

/** Gets attribute value from the closest element with group behavior settings */
export function getClosestAttr($el: ESLAttributeTarget, attrName: string): string | null {
if (!($el = resolveDomTarget($el))) return null;
const $closest = $el.closest(`[${attrName}]`);
return $closest ? $closest.getAttribute(attrName) : null;
}

0 comments on commit b29acde

Please sign in to comment.