or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

attributes.mdcontext-system.mdcss-styling.mddata-binding.mddependency-injection.mdhtml-templates.mdindex.mdobservable-system.mdssr-hydration.mdstate-management.mdtemplate-directives.mdtesting-utilities.mdutilities.mdweb-components.md

utilities.mddocs/

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

```