exadel-inc / esl

Lightweight and flexible UI component library based on web components technology for creating basic UX modules
https://esl-ui.com
MIT License
58 stars 9 forks source link

[πŸš€esl-utils]: add attribute inheritance option for `@attr` decorator #2218

Closed ala-n closed 4 months ago

ala-n commented 6 months ago

As an ESL consumer, I want to have utilities to support common ESL component mechanics with an attribute property DOM-based inheritance.

It is proposed to extend @attr decorator with ability to declare inherit (named according discussion `1) attribute to inherit value:

  1. Setter behavior does not affected, so $el.myAttr = 'hi' leads to own attribute mutation ignoring any inheritance logic.

  2. Getter behavior should be updated according following cases: 2.1. closest/inheritance feature is disabled initially, so no changes in existing @attr behavior

    2.2. if the element have a declared own attribute the closest/inheritance logic does not affect getter value. In other words, one's own attribute has a priority over resolved by inheritance logic.

    2.3. when the inherit prop is declared with a boolean true value, the value is expected to be inherited from the closest parent attribute with the same name as current attribute declared.

    • @attr({ inherit: true }) public ignore; - finds ignore attr on this element or closest parent with attribute ignore
    • @attr({ inherit: true, dataAttr: true }) public ignore; - finds data-ignore attr on this element or closest parent with data-ignore attribute

    2.4. when the inherit prop is declared as a string, it is interpreted as an inherited attribute name to find the closest parent.

    • @attr({ inherit: 'alt-ignore' }) public ignore; - uses ignore attr on this element or closest parent with alt-ignore attribute
    • @attr({ inherit: 'alt-ignore', dataAttr: true }) public ignore; - uses data-ignore attr on this element or closest parent with alt-ignore attribute
ala-n commented 6 months ago

Note/Question 1: the name of the attribute

Igea: suffix 'closestAttr'

CC: @NastaLeo , @exadel-inc/esl-core-maintainers

ala-n commented 6 months ago

Note / Question 2: the logic is designed to use closed attribute finding, which includes the current element as a first target element.

   @attr({ closest: 'alt-ignore' }) public ignore;
  <div alt-ignore="nope">
    <cust-el alt-ignore="hi"> // $0
  </div>

$0.ignore // hi

CC: @NastaLeo , @exadel-inc/esl-core-maintainers

ala-n commented 6 months ago

To summarize the question above according to the final discussions/votings:

  1. We use inherit as the name of the option. Reason: such a kind of mechanic is usually named inheritance - the adoption/usage of a parent's characteristics. Similar naming is used in CSS cascading and in a list of other frameworks as well.
  2. We allow the use of "closest behavior" to start fallback search starting from the element itself. It could help to make non-risky standardization in the future.
ala-n commented 6 months ago

Tast cases:

    // 1. Inherit does not affect own attribute resolution
    // 1.1. Own attribute getter returns own value (independently of parent DOM structure)
    // 1.2. Own attribute setter changes the own value
    // 2. Inherit searches for the closest element with explicitly declared name (inherit: string) in DOM to find the value
    // 2.1. The value resoles from the closest element in DOM if there is no own value
    // 2.2. The value can be resolved from own custom attribute (has own attribute declared by inherit)
    // 2.3. `dataAttr` parameter does not affect the search of the closest element in DOM
    // 3. Inherit searches for the closest element with the same attribute name in DOM to find the value (inherit: true)
    // 3.1. The value resoles from the closest element in DOM if there is no own value
    // 3.2. `dataAttr` parameter affects both own attribute and the search of the closest element in DOM
    // 4. If there is no closest element with declared attribute name in DOM, the getter returns default value
ala-n commented 5 months ago

:tada: This issue has been resolved in version 5.0.0-beta.11 :tada:

The release is available on:

Your semantic-release bot :package::rocket: