be-linked
TypeScript icon, indicating that this package has built-in type declarations

0.0.92 • Public • Published

be-linked [WIP]

Playwright Tests How big is this package in your project? NPM version

Connect HTML (web) components and custom enhancements together with readable syntax.

be-linked is a one-stop shop for all needs as far as inline binding. It uses grammatically correct English statements as much as possible. The opening word of each statement is quite important, as it serves to "categorize" the type of statement. Some of these are "generalized" opening words that insist on very precise, but somewhat lengthy statements. These statements are quite flexible in that they can cover quite a few scenarios. Examples are "Link" and "On".

Others are "specialized" opening words, designed to keep the statement short for common use cases ("Toggle", "Pass" for example), but make many assumptions. These assumptions impose many constraints as far as what they can do.

Opening word Specialized? (link) Purpose Notes
Link No Relate properties of any two components together centered around the enhanced element. Covers large use cases, but requires lengthy statements in many cases.
On No Attach event handlers and do actions relative to the enhanced element. Can also reference script elements.
When No
Elevate Yes Pass property of enhanced element up to some upstream element on a click or other event. Supports marker properties, discussed below.
Share Yes Share values from host or other element towards the top of the hierarchy, to child elements, usually based on microdata attributes. Can also share via name and id attributes.
Join Yes
Invoke Yes
Compute Yes

Part I Downstream linkage

Property setter subscription scenarios

Simplest scenario.

host-element container has boolean property "readOnly". Inner element wants to match the value with the same property name.

<host-element>
    #shadow
    <input be-linked='
        Link read only props.
    '>
</host-element>

which is shorthand for one of two lingo's:

Hemingway Notation
<host-element>
    #shadow
    <input be-linked='
        Link read only property of host to read only property of $0.
    '>
</host-element>
JavaScriptObjectNotation
<host-element>
    #shadow
    <input be-linked='
        "links":[{
            "downstreamPropPath": "readOnly",
            "target": "local",
            "upstreamCamelQry": "host",
            "upstreamPropPath": "readOnly",
            "passDirection": "towards"
        }]
    '>
</host-element>

For more compact and flexible options with similar functionality, see companion enhancements be-entrusting and be-observant.

Special notation for hooking up custom enhancements

<input type=search> 

<div be-linked='
    On input event of previous element sibling pass value property to $0+beSearching:forText.
'>
<div>
    supercalifragilisticexpialidocious
</div>

Negation scenario

host-element container has property "readOnly". Inner element wants to set dataset.isEditable to the opposite.

<host-element>
    #shadow
    <input be-linked='
        Negate read only property of host to dataset:isEditable property of $0.
    '>
</host-element>

Other opening words [Untested]

In place of "Negate" above, we can use the following verbs:

Key Meaning Notes
Clone Do a structured clone of the value before passing it. Makes it almost impossible to experience unexpected side effects from passing an object from one component to another.
Refer Pass weak reference of the property.

Translate scenario

<paul-mccartney age=64>
    #shadow
    <daughter-heather enh-by-be-linked='
        Link age property of host - 20 to age property of $0.
    '></daughter-heather>
</paul-mccartney>

as number (or other data formats)

<input type=number value=37>

<paul-mccartney enh-by-be-linked='
    Link value property of previous element sibling as number to age property of $0.
'></paul-mccartney>

Options: as number, as date, as object, as string, as reg exp, as url.

Using JavaScript for more complex scenarios
Named handler
<host-element>
    #shadow
    <script nomodule>
        export const readOnlyHandler = ({remoteInstance, $0}) => ({
            checked: remoteInstance.readOnly ? 'on' : 'off',
        });
    </script>
    <toggle-element enh-be-linked='
        When read only property of host changes assign result of read only handler to $0. 
    '></toggle-element>
    <be-hive></be-hive>
</host-element>

For more compact options, and for more flexibility, consider adopting companion enhancement be-computed. It shares much common code with be-linked, so the additional footprint should be quite small.

Counting Scenario

<my-light-weight-container>
        <my-time-ticker-service></my-time-ticker-service>
        <my-counter enh-by-be-linked='
            When value property of previous element sibling changes increment count property of $0.
        '></my-counter>
</my-light-weight-container>

Traditional Element Events

<my-light-weight-container>
    <number-generator></number-generator>
    <metric-units enh-be-linked='
        On value changed event of previous element sibling pass value property to cm property of $0
        where we enable debugging
        and we fire changed event
        and we nudge previous element
        and we skip initialization. 
    '></metric-units>
</my-light-weight-container

See companion enhancement be-listening for more compact / specialized ways of doing this.

Upstream linking

Suppose we want to pass information in the opposite direction -- from the adorned element to an upstream element like the host container element? If we are not careful, this can easily result in infinite loops. To help prevent this, no support for property changes ("setter subscribing") is supported. Only events. The developer should lean heavily on the practice of only allowing data to flow in this direction when it is triggered (directly or indirectly) by user initiated actions.

<host-element>
    #shadow
        <input be-linked='
            On input event of $0 pass value property to greeting property of host.
        '>
</host-element>

See be-elevating for a companion enhancement which specializes in this functionality, with more compact notation, special support for microdata, and other features.

Upstream scripting

<host-element>
    #shadow
        <script nomodule>
            export const myHandler = ({remoteInstance, $0}) => ({

            })
        </script>
        <input be-linked='
            On input event of $0 assign result of my handler to host.
        '>
</host-element>

If host-element has method "doSomething": [Untested]

<host-element>
    #shadow
        <input be-linked='
            On input event of $0 invoke method do something of host.
        '>
</host-element>

See be-invoking.

Shorthand for invoking [TODO]

A special key word is used for invoking methods on the host:

<host-element>
    #shadow
        <input be-linked='
            Invoke do something.
        '>
</host-element>

Because this is a form element, by default invokes the method on the change event. If it's the form, invokes on submit.

For everything else, invokes on click.

To specify the event:

<host-element>
    #shadow
        <input be-linked='
            Invoke do something on click.
        '>
</host-element>

As far as finding the host, the following is used:

  1. Searches for the closest element with attribute itemscope.
  2. If dash in the name of the element, does an await customElements.whenDefined
  3. Checks if method exists on custom element.
  4. If not found, continues to searching for the next closest element with attribute itemscope.
  5. Lastly, tries getRootNode().host
  6. If that fails, throws an error.

Method can be nested path (using : delimiter).

Shorthand for linking

be-linked also supports statements that are optimized for a common use case: Sharing data from a DOM node to descendent elements contained inside (within its "scope"), with special attention given to microdata attributes. This functionality has it's own enhancement, be-sharing that specializes in this scenario, and leverages code from be-linking -- statements that begin with the word Share.

Sidewise linking [Untested]

It is possible to employ either downstream or upstream syntax, if targeting a peer element of the adorned element, within the Shadow DOM realm, wherever it may exist. That can be done by specifying the id (but other css matches can be used instead. The one restriction is we can only target one element with each statement, the first element that matches the instructions):

<host-element>
    #shadow
        <input type=number be-linked='
            On input event of $0 
            pass value property as number 
            to slide index property 
            of slide show id 
            within root node.
        '>
        ...
        <my-carousel id=slide-show></my-carousel>
</host-element>

If the user enters something in the input field before the my-carousel element has streamed to the browser, tough luck!

To avoid this possibility maybe it would make more sense to add a be-linked attribute to my-carousel?

See be-passing

Running locally

  1. Do a git clone or a git fork of repository https://github.com/bahrus/be-linked
  2. Install node.js
  3. Run "npm install" from location of folder created in step 1.
  4. Run npm run serve. Open browser to http://localhost:3030/demo/

Using from ESM Module:

import 'be-linked/be-linked.js';

Using from CDN:

<script type=module crossorigin=anonymous>
    import 'https://esm.run/be-linked';
</script>

Package Sidebar

Install

npm i be-linked

Weekly Downloads

18

Version

0.0.92

License

MIT

Unpacked Size

90.6 kB

Total Files

42

Last publish

Collaborators

  • bahrus