1 | import BaseComponent, { Args } from '../addon/-private/component';
|
2 | export interface Bounds {
|
3 | firstNode: Node;
|
4 | lastNode: Node;
|
5 | }
|
6 | export default class Component<S = unknown> extends BaseComponent<S> {
|
7 | args: Readonly<Args<S>>;
|
8 | /**
|
9 | * Development-mode only name of the component, useful for debugging.
|
10 | */
|
11 | readonly debugName: string;
|
12 | /**
|
13 | * Called when the component has been inserted into the DOM.
|
14 | * Override this function to do any set up that requires an element in the document body.
|
15 | */
|
16 | didInsertElement(): void;
|
17 | /**
|
18 | * Called when the component has updated and rerendered itself.
|
19 | * Called only during a rerender, not during an initial render.
|
20 | */
|
21 | didUpdate(): void;
|
22 | /**
|
23 | * Contains the first and last DOM nodes of a component's rendered template.
|
24 | * These nodes can be used to traverse all of the DOM nodes that belong to a
|
25 | * particular component.
|
26 | *
|
27 | * Note that a component's first and last nodes *can* change over time, if the
|
28 | * beginning or ending of the template is dynamic. You should always access
|
29 | * `bounds` directly at the time a node is needed to ensure you are acting on
|
30 | * up-to-date nodes.
|
31 | *
|
32 | * ### Examples
|
33 | *
|
34 | * For components with a single root element, `this.bounds.firstNode` and
|
35 | * `this.bounds.lastNode` are the same.
|
36 | *
|
37 | * ```hbs
|
38 | * <div class="user-profile">
|
39 | * <Avatar @user={{user}} />
|
40 | * </div>
|
41 | * ```
|
42 | *
|
43 | * ```ts
|
44 | * export default class extends Component {
|
45 | * didInsertElement() {
|
46 | * let { firstNode, lastNode } = this.bounds;
|
47 | * console.log(firstNode === lastNode); // true
|
48 | * console.log(firstNode.className); // "user-profile"
|
49 | * }
|
50 | * }
|
51 | * ```
|
52 | *
|
53 | * For components with multiple root nodes, `this.bounds.firstNode` refers to
|
54 | * the first node in the template and `this.bounds.lastNode` refers to the
|
55 | * last:
|
56 | *
|
57 | * ```hbs
|
58 | * Welcome to Glimmer.js!
|
59 | * <span>Let's build some components!</span>
|
60 | * <img src="logo.png">
|
61 | * ```
|
62 | *
|
63 | * ```ts
|
64 | * export default class extends Component {
|
65 | * didInsertElement() {
|
66 | * let { firstNode, lastNode } = this.bounds;
|
67 | *
|
68 | * // Walk all of the DOM siblings from the
|
69 | * // firstNode to the lastNode and push their
|
70 | * // nodeName into an array.
|
71 | * let node = firstNode;
|
72 | * let names = [firstNode.nodeName];
|
73 | * do {
|
74 | * node = node.nextSibling;
|
75 | * names.push(node.nodeName);
|
76 | * } while (node !== lastNode);
|
77 | *
|
78 | * console.log(names);
|
79 | * // ["#text", "SPAN", "IMG"]
|
80 | * }
|
81 | * }
|
82 | * ```
|
83 | *
|
84 | * The bounds can change if the template has dynamic content at the beginning
|
85 | * or the end:
|
86 | *
|
87 | * ```hbs
|
88 | * {{#if user.isAdmin}}
|
89 | * <span class="warning">Admin</span>
|
90 | * {{else}}
|
91 | * Normal User
|
92 | * {{/if}}
|
93 | * ```
|
94 | *
|
95 | * In this example, the `firstNode` will change between a `span` element and a
|
96 | * `TextNode` as the `user.isAdmin` property changes.
|
97 | */
|
98 | bounds: Bounds;
|
99 | /**
|
100 | * The element corresponding to the main element of the component's template.
|
101 | * The main element is the element in the template that has `...attributes` set on it:
|
102 | *
|
103 | * ```hbs
|
104 | * <h1>Modal</h1>
|
105 | * <div class="contents" ...attributes>
|
106 | * {{yield}}
|
107 | * </div>
|
108 | * ```
|
109 | *
|
110 | * In this example, `this.element` would be the `div` with the class `contents`.
|
111 | *
|
112 | * You should not try to access this property until after the component's `didInsertElement()`
|
113 | * lifecycle hook is called.
|
114 | */
|
115 | readonly element: HTMLElement;
|
116 | }
|