0
# Utilities
1
2
DOM utilities and advanced component orchestration for working with Shadow DOM boundaries and managing view behaviors in complex component scenarios.
3
4
## Capabilities
5
6
### Composed DOM Navigation
7
8
Utilities for navigating DOM trees that span Shadow DOM boundaries, treating composed elements as a unified tree structure.
9
10
```typescript { .api }
11
/**
12
* Retrieves the "composed parent" element of a node, ignoring DOM tree boundaries
13
* When the parent of a node is a shadow-root, it will return the host element
14
* @param element - The element for which to retrieve the composed parent
15
* @returns The composed parent element or null
16
*/
17
function composedParent<T extends HTMLElement>(element: T): HTMLElement | null;
18
19
/**
20
* Determines if the reference element contains the test element in a "composed" DOM tree
21
* Returns true if the test element is a descendant of the reference, including through shadow DOM
22
* @param reference - The element to test for containment against
23
* @param test - The element being tested for containment
24
* @returns True if test is contained within reference's composed tree
25
*/
26
function composedContains(reference: HTMLElement, test: HTMLElement): boolean;
27
```
28
29
**Usage Examples:**
30
31
```typescript
32
import { composedParent, composedContains } from "@microsoft/fast-element/utilities.js";
33
34
// Navigate composed DOM tree
35
function findComposedAncestor(element: HTMLElement, selector: string): HTMLElement | null {
36
let current = composedParent(element);
37
38
while (current) {
39
if (current.matches(selector)) {
40
return current;
41
}
42
current = composedParent(current);
43
}
44
45
return null;
46
}
47
48
// Check composed containment
49
function isChildOfDialog(element: HTMLElement, dialog: HTMLElement): boolean {
50
return composedContains(dialog, element);
51
}
52
53
// Handle events across shadow boundaries
54
function handleComposedClick(event: Event) {
55
const target = event.target as HTMLElement;
56
const container = document.querySelector('.app-container') as HTMLElement;
57
58
if (composedContains(container, target)) {
59
console.log('Click occurred within app container (including shadow DOM)');
60
}
61
}
62
```
63
64
### Enhanced Mutation Observer
65
66
Extended MutationObserver that supports selective unobserving of specific nodes for more granular control over observation lifecycles.
67
68
```typescript { .api }
69
/**
70
* An extension of MutationObserver that supports unobserving specific nodes
71
*/
72
class UnobservableMutationObserver extends MutationObserver {
73
/**
74
* Creates an instance of UnobservableMutationObserver
75
* @param callback - The callback to invoke when observed nodes are changed
76
*/
77
constructor(callback: MutationCallback);
78
79
/**
80
* Observe a target node for changes
81
* @param target - The node to observe
82
* @param options - Mutation observer options
83
*/
84
observe(target: Node, options?: MutationObserverInit): void;
85
86
/**
87
* Stop observing a specific target node
88
* @param target - The node to stop observing
89
*/
90
unobserve(target: Node): void;
91
}
92
```
93
94
**Usage Examples:**
95
96
```typescript
97
import { UnobservableMutationObserver } from "@microsoft/fast-element/utilities.js";
98
99
// Create selective mutation observer
100
const observer = new UnobservableMutationObserver((mutations) => {
101
mutations.forEach(mutation => {
102
console.log('Mutation observed:', mutation.type, mutation.target);
103
});
104
});
105
106
// Observe multiple elements
107
const elements = document.querySelectorAll('.watched-element');
108
elements.forEach(element => {
109
observer.observe(element, {
110
childList: true,
111
attributes: true,
112
subtree: true
113
});
114
});
115
116
// Later, selectively stop observing some elements
117
function stopWatchingElement(element: Element) {
118
observer.unobserve(element);
119
console.log('Stopped watching element');
120
}
121
122
// The observer automatically disconnects when no nodes are being observed
123
```
124
125
### View Behavior Orchestrator
126
127
Advanced orchestration system for coordinating view behaviors with host behaviors, enabling complex component interaction patterns.
128
129
```typescript { .api }
130
/**
131
* Bridges between ViewBehaviors and HostBehaviors, enabling a host to control ViewBehaviors
132
*/
133
interface ViewBehaviorOrchestrator<TSource = any, TParent = any>
134
extends ViewController<TSource, TParent>, HostBehavior<TSource> {
135
136
/**
137
* Adds a target node with associated structural ID
138
* @param nodeId - The structural id of the DOM node
139
* @param target - The DOM node associated with the id
140
*/
141
addTarget(nodeId: string, target: Node): void;
142
143
/**
144
* Adds a behavior to be managed
145
* @param behavior - The behavior to add
146
*/
147
addBehavior(behavior: ViewBehavior): void;
148
149
/**
150
* Adds a behavior factory that will create behaviors for a target
151
* @param factory - The behavior factory to add
152
* @param target - The target the factory will create behaviors for
153
*/
154
addBehaviorFactory(factory: ViewBehaviorFactory, target: Node): void;
155
}
156
157
/**
158
* Factory for creating ViewBehaviorOrchestrator instances
159
*/
160
const ViewBehaviorOrchestrator: {
161
/**
162
* Creates a ViewBehaviorOrchestrator
163
* @param source - The source to associate behaviors with
164
* @returns A ViewBehaviorOrchestrator instance
165
*/
166
create<TSource = any, TParent = any>(source: TSource): ViewBehaviorOrchestrator<TSource, TParent>;
167
};
168
```
169
170
**Usage Examples:**
171
172
```typescript
173
import { ViewBehaviorOrchestrator } from "@microsoft/fast-element/utilities.js";
174
import { FASTElement, customElement, html, ViewBehavior } from "@microsoft/fast-element";
175
176
// Custom behavior that needs orchestration
177
class CustomHighlightBehavior implements ViewBehavior {
178
private element: HTMLElement;
179
180
constructor(private color: string) {}
181
182
bind(controller: ViewController): void {
183
this.element = controller.targets['highlight-target'] as HTMLElement;
184
this.element.style.backgroundColor = this.color;
185
}
186
187
unbind(): void {
188
if (this.element) {
189
this.element.style.backgroundColor = '';
190
}
191
}
192
}
193
194
@customElement("orchestrated-component")
195
export class OrchestratedComponent extends FASTElement {
196
private orchestrator: ViewBehaviorOrchestrator<this>;
197
198
connectedCallback() {
199
super.connectedCallback();
200
201
// Create orchestrator
202
this.orchestrator = ViewBehaviorOrchestrator.create(this);
203
204
// Add targets
205
const highlightTarget = this.shadowRoot!.querySelector('.highlight-area')!;
206
this.orchestrator.addTarget('highlight-target', highlightTarget);
207
208
// Add behaviors
209
this.orchestrator.addBehavior(new CustomHighlightBehavior('yellow'));
210
211
// Connect orchestrator
212
this.orchestrator.connectedCallback(this.$fastController);
213
}
214
215
disconnectedCallback() {
216
super.disconnectedCallback();
217
this.orchestrator?.disconnectedCallback(this.$fastController);
218
}
219
}
220
```
221
222
## Types
223
224
```typescript { .api }
225
interface ViewBehaviorOrchestrator<TSource = any, TParent = any> {
226
readonly source: TSource;
227
readonly context: ExecutionContext<TParent>;
228
readonly targets: ViewBehaviorTargets;
229
readonly isBound: boolean;
230
}
231
```