naM ,sevitcepsreP weN

    ember-ref-bucket

    5.0.0 • Public • Published

    ember-ref-bucket

    This addon was created as a rethinking of ember-ref-modifier, with a more simplified API and without some of the downsides of the previous implementation.

    The addon allows users to get access to DOM nodes inside components, including accessing wrapping/destroying logic.

    A simple use case:

    • applying ref modifier with passed name to an element.
    <div {{create-ref "FavouriteNode"}}>hello</div>
    • gain access to it inside the component class as a decorated property
    import Component from '@glimmer/component';
    import { ref } from 'ember-ref-bucket';
    
    export default class MyComponent extends Component {
      @ref("FavouriteNode") node; 
      // this.node === "<div>hello</div>"
    }

    API differences, comparing to ember-ref-modifier:

    In ember-ref-modifier ref modifier accept 2 positional arguments {{ref this "property"}}:

    1. context to set path (this)
    2. path to set on context ("property")

    In ember-ref-bucket ref modifier accept 1 positional argument {{create-ref "field"}}:

    1. reference name ("field")

    reference name should be passed as an argument to the @ref("field") decorator, to allow it to find the reference by name.

    Compatibility

    • Ember.js v3.20 or above
    • Ember CLI v3.20 or above
    • Node.js v14 or above

    Installation

    ember install ember-ref-bucket
    

    Usage

    Examples

    Simple player

    <audio {{create-ref "player"}} src="music.mp3"></audio>
    <button {{on "click" this.onPlay}}>Play</button>
    import Component from '@glimmer/component';
    import { ref } from 'ember-ref-bucket';
    import { action } from '@ember/object';
    
    export class Player extends Component {
      @ref('player') audioNode;
      @action onPlay() {
        this.audioNode.play()
      }
    }

    Link div to node property.

    <div {{create-ref "field"}} ></div>
    import Component from '@glimmer/component';
    import { ref } from 'ember-ref-bucket';
    
    export default class MyComponent extends Component {
      @ref("field") node = null;
    }

    Dynamically show div content updates

    <div {{create-tracked-ref "field"}}>hello</div>
    
    {{get (tracked-ref-to "field") "textContent"}}
    

    Use div as component argument

    <div {{create-ref "field"}}>hello</div>
    
    <SecondComponent @helloNode={{ref-to "field"}} />

    Use registerNodeDestructor

    This method is very useful if you want to wrap the node and control its lifecycle.

    <div {{create-ref "field"}}>
    import Component from '@glimmer/component';
    import { ref, registerNodeDestructor } from 'ember-ref-bucket';
    
    class NodeWrapper {
      constructor(node) {
        this.node = node;
      }
      destroy() {
        this.node = null;
      }
      value() {
        return this.node.textContent;
      }
    }
    
    export default class WrappedNodeComponent extends Component {
      @ref('field', (node) => {
        const instance = new NodeWrapper(node);
        registerNodeDestructor(node, () => instance.destroy());
        return instance;
      }) node = null;
      get value() {
        return this.node?.value();
      }
    }

    Available decorators:

    import { ref, globalRef, trackedRef, trackedGlobalRef } from 'ember-ref-bucket';
    
    /*
      ref - usage: @ref('foo', nodeWrapFn?), ref to bucket with current component context
      globalRef - usage: @globalRef('foo', nodeWrapFn?), ref to global context (app)
      trackedRef - usage: @trackedRef('foo', nodeWrapFn?), tracked ref to local context
      trackedGlobalRef - usage: @trackedGlobalRef('foo', nodeWrapFn?), tracked ref to global context (app)
    
    */

    Available methods:

    import { registerNodeDestructor, unregisterNodeDestructor } from 'ember-ref-bucket';
    
    /*
      registerNodeDestructor(node, fn) - to assign any ref-node destructor
      unregisterNodeDestructor(node, fn) - to remove assigned ref-node destructor 
    
      usage will be like:
    
      @ref('field', (node) => {
        const item = new InputMask(node);
        registerNodeDestructor(node, () => item.destroy());
        return item;
      });
    */
    /* 
      nodeFor - functional low-level primitive to get node access
    */
    
    import { nodeFor } from 'ember-ref-bucket';
    
    const domNode = nodeFor(this, 'field');

    Definition of @trackedRef decorators

    • If you use dom node in @tracked chain calculations, you should use trackedRef.

    • If you don't need to rerun the tracked chain (for example, you use ref only for some event-based dom access), you should not use trackedRef.

    Definition of {{create-tracked-ref}} modifiers

    • If you need to watch for node changes (resize, content, attributes), you can use the create-tracked-ref modifier. It can add observe resizing and mutations for the associated element and will mark it as "dirty" for any mutation.

    Options:

    • resize - default: false, if truthy observes the resizing of the DOM element.
    • attributes - default: false, if truthy observes the changing of any attribute on the DOM element.
    • characterdata - default: false, if truthy observes the change of the innerText of the DOM element. Note that setting innerText can change the childlist or the characterdata depending on the current content of the element.
    • childlist - default: false, if truthy observes changes to the list of direct children of the DOM element.
    • subtree - default: false, if truthy observes the above options on the entire DOM subtree, not just the element decorated by the modifier.

    Definition of {{tracked-ref-to}} helpers

    • If you need to recalculate helper if some dom node changes (size, children, attributes), you need to use tracked-ref-to helper.
    • If you don't need it (you need to just have ref to dom node), you should choose ref-to helper.

    Template-only components

    • create-ref modifier and ref-to helpers will not work in template-only components (because of no context). You should use create-global-ref and global-ref-to instead. You can also provide a bucket param to the create-ref modifier / helper.

    The addon provide only 1 modifier (create-ref) and 1 helper (ref-to). Other derivatives will be transformed, and are described below:

    Modifiers will be transformed according to this table:

    Invocation Will be transformed to
    {{create-ref "foo"}} {{create-ref "foo" bucket=this}}
    {{create-tracked-ref "foo"}} {{create-ref "foo" bucket=this tracked=true}}
    {{create-global-ref "foo"}} {{create-ref "foo" bucket=undefined}}
    {{create-tracked-global-ref "foo"}} {{create-ref "foo" bucket=undefined tracked=true}}

    Helpers will be transformed according to this table:

    Invocation Will be transformed to
    {{ref-to "foo"}} {{ref-to "foo" bucket=this}}
    {{tracked-ref-to "foo"}} {{ref-to "foo" bucket=this tracked=true}}
    {{global-ref-to "foo"}} {{ref-to "foo" bucket=undefined}}
    {{tracked-global-ref-to "foo"}} {{ref-to "foo" bucket=undefined tracked=true}}

    Contributing

    See the Contributing guide for details.

    Version matrix:

    Ember-Modifier 4 - v5; Ember 3.28 - v4; Ember 3.24 - v3

    License

    This project is licensed under the MIT License.

    Install

    npm i ember-ref-bucket

    DownloadsWeekly Downloads

    9,069

    Version

    5.0.0

    License

    MIT

    Unpacked Size

    29 kB

    Total Files

    14

    Last publish

    Collaborators

    • lifeart