Skip to content

Commit 6db540b

Browse files
committed
fix(core): html now works
1 parent 3c9e6ce commit 6db540b

File tree

4 files changed

+105
-77
lines changed

4 files changed

+105
-77
lines changed

libs/core/src/lib/renderer/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const NGT_INTERNAL_SET_PARENT_COMMENT_FLAG = '__ngt_renderer_set_parent_c
88
export const NGT_MANUAL_INJECTED_STORE = '__ngt_manual_injected_store__';
99
export const NGT_GET_NODE_ATTRIBUTE_FLAG = '__ngt_get_node_attribute__';
1010
export const NGT_DOM_PARENT_FLAG = '__ngt_dom_parent__';
11+
export const NGT_DELEGATE_RENDERER_DESTROY_NODE_PATCHED_FLAG = '__ngt_delegate_renderer_destroy_node_patched__';
1112

1213
export const NGT_HTML_FLAG = '__ngt_html__';
1314

libs/core/src/lib/renderer/renderer.ts

Lines changed: 23 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,15 @@ import { NgtArgs } from '../directives/args';
1414
import { NgtCommonDirective } from '../directives/common';
1515
import { NgtParent } from '../directives/parent';
1616
import { getInstanceState, prepare } from '../instance';
17-
import {
18-
NgtAnyRecord,
19-
NgtConstructorRepresentation,
20-
NgtEventHandlers,
21-
NgtInstanceNode,
22-
NgtInstanceState,
23-
} from '../types';
17+
import { NgtConstructorRepresentation, NgtEventHandlers, NgtInstanceNode, NgtInstanceState } from '../types';
2418
import { applyProps } from '../utils/apply-props';
2519
import { is } from '../utils/is';
2620
import { injectCatalogue } from './catalogue';
2721
import {
2822
NGT_CANVAS_CONTENT_FLAG,
23+
NGT_DELEGATE_RENDERER_DESTROY_NODE_PATCHED_FLAG,
2924
NGT_DOM_PARENT_FLAG,
30-
NGT_GET_NODE_ATTRIBUTE_FLAG,
25+
NGT_HTML_FLAG,
3126
NGT_INTERNAL_ADD_COMMENT_FLAG,
3227
NGT_INTERNAL_SET_PARENT_COMMENT_FLAG,
3328
NGT_PORTAL_CONTENT_FLAG,
@@ -41,7 +36,7 @@ import {
4136
NgtRendererNode,
4237
setRendererParentNode,
4338
} from './state';
44-
import { attachThreeNodes, kebabToPascal, NgtRendererClassId, removeThreeChild } from './utils';
39+
import { attachThreeNodes, internalDestroyNode, kebabToPascal, NgtRendererClassId, removeThreeChild } from './utils';
4540

4641
@Injectable()
4742
export class NgtRendererFactory2 implements RendererFactory2 {
@@ -59,13 +54,30 @@ export class NgtRendererFactory2 implements RendererFactory2 {
5954
if (!type) return delegateRenderer;
6055

6156
let renderer = this.rendererMap.get(type.id);
62-
6357
if (renderer) return renderer;
6458

6559
if (hostElement && !isRendererNode(hostElement)) {
6660
createRendererNode('platform', hostElement, this.document);
6761
}
6862

63+
if (Reflect.get(type, 'type')?.[NGT_HTML_FLAG]) {
64+
this.rendererMap.set(type.id, delegateRenderer);
65+
66+
// patch delegate destroyNode so we can destroy this HTML node
67+
// TODO: make sure we really need to do this
68+
const originalDestroyNode = delegateRenderer.destroyNode?.bind(delegateRenderer);
69+
if (!originalDestroyNode || !(NGT_DELEGATE_RENDERER_DESTROY_NODE_PATCHED_FLAG in originalDestroyNode)) {
70+
delegateRenderer.destroyNode = (node) => {
71+
originalDestroyNode?.(node);
72+
if (node !== hostElement) return;
73+
internalDestroyNode(node, null);
74+
};
75+
Object.assign(delegateRenderer.destroyNode, { [NGT_DELEGATE_RENDERER_DESTROY_NODE_PATCHED_FLAG]: true });
76+
}
77+
78+
return delegateRenderer;
79+
}
80+
6981
this.rendererMap.set(type.id, (renderer = new NgtRenderer2(delegateRenderer, this.catalogue, this.document)));
7082
return renderer;
7183

@@ -292,71 +304,7 @@ export class NgtRenderer2 implements Renderer2 {
292304
}
293305

294306
destroyNode: (node: NgtRendererNode) => void = (node) => {
295-
const rS = node.__ngt_renderer__;
296-
if (!rS || rS[NgtRendererClassId.destroyed]) return;
297-
298-
for (const child of rS[NgtRendererClassId.children].slice()) {
299-
this.removeChild(node, child);
300-
this.destroyNode(child);
301-
}
302-
303-
// clear out parent if haven't
304-
rS[NgtRendererClassId.parent] = undefined;
305-
// clear out children
306-
rS[NgtRendererClassId.children].length = 0;
307-
308-
// clear out NgtInstanceState
309-
const iS = getInstanceState(node);
310-
if (iS) {
311-
const temp = iS as NgtAnyRecord;
312-
313-
iS.removeInteraction?.(iS.store);
314-
315-
delete temp['onAttach'];
316-
delete temp['onUpdate'];
317-
delete temp['object'];
318-
delete temp['objects'];
319-
delete temp['nonObjects'];
320-
delete temp['parent'];
321-
delete temp['add'];
322-
delete temp['remove'];
323-
delete temp['updateGeometryStamp'];
324-
delete temp['setParent'];
325-
delete temp['store'];
326-
delete temp['handlers'];
327-
delete temp['hierarchyStore'];
328-
delete temp['previousAttach'];
329-
delete temp['setPointerEvent'];
330-
delete temp['addInteraction'];
331-
delete temp['removeInteraction'];
332-
333-
if (iS.type !== 'ngt-primitive') {
334-
delete node['__ngt__'];
335-
}
336-
}
337-
338-
// clear our debugNode
339-
rS[NgtRendererClassId.injector] = undefined;
340-
341-
if (rS[NgtRendererClassId.type] === 'comment') {
342-
delete node[NGT_INTERNAL_ADD_COMMENT_FLAG];
343-
delete node[NGT_INTERNAL_SET_PARENT_COMMENT_FLAG];
344-
delete node[NGT_CANVAS_CONTENT_FLAG];
345-
delete node[NGT_PORTAL_CONTENT_FLAG];
346-
delete node[NGT_DOM_PARENT_FLAG];
347-
}
348-
349-
// clear getAttribute if exist
350-
if (
351-
'getAttribute' in node &&
352-
typeof node['getAttribute'] === 'function' &&
353-
node['getAttribute'][NGT_GET_NODE_ATTRIBUTE_FLAG]
354-
) {
355-
delete node['getAttribute'];
356-
}
357-
358-
// mark node as destroyed
359-
rS[NgtRendererClassId.destroyed] = true;
307+
internalDestroyNode(node, this.removeChild.bind(this));
360308
};
361309

362310
appendChild(parent: NgtRendererNode, newChild: NgtRendererNode, refChild?: NgtRendererNode, isMove?: boolean): void {

libs/core/src/lib/renderer/utils.ts

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,17 @@ import { untracked } from '@angular/core';
22
import * as THREE from 'three';
33
import { removeInteractivity } from '../events';
44
import { getInstanceState, invalidateInstance } from '../instance';
5-
import { NgtInstanceNode } from '../types';
5+
import { NgtAnyRecord, NgtInstanceNode } from '../types';
66
import { attach, detach } from '../utils/attach';
77
import { is } from '../utils/is';
8+
import {
9+
NGT_CANVAS_CONTENT_FLAG,
10+
NGT_DOM_PARENT_FLAG,
11+
NGT_GET_NODE_ATTRIBUTE_FLAG,
12+
NGT_INTERNAL_ADD_COMMENT_FLAG,
13+
NGT_INTERNAL_SET_PARENT_COMMENT_FLAG,
14+
NGT_PORTAL_CONTENT_FLAG,
15+
} from './constants';
816
import { NgtRendererNode } from './state';
917

1018
// @internal
@@ -180,3 +188,74 @@ export function removeThreeChild(child: NgtInstanceNode, parent: NgtInstanceNode
180188

181189
invalidateInstance(parent);
182190
}
191+
192+
export function internalDestroyNode(
193+
node: NgtRendererNode,
194+
removeChild: null | ((node: NgtRendererNode, child: NgtRendererNode) => void),
195+
) {
196+
const rS = node.__ngt_renderer__;
197+
if (!rS || rS[NgtRendererClassId.destroyed]) return;
198+
199+
for (const child of rS[NgtRendererClassId.children].slice()) {
200+
removeChild?.(node, child);
201+
internalDestroyNode(child, removeChild);
202+
}
203+
204+
// clear out parent if haven't
205+
rS[NgtRendererClassId.parent] = undefined;
206+
// clear out children
207+
rS[NgtRendererClassId.children].length = 0;
208+
209+
// clear out NgtInstanceState
210+
const iS = getInstanceState(node);
211+
if (iS) {
212+
const temp = iS as NgtAnyRecord;
213+
214+
iS.removeInteraction?.(iS.store);
215+
216+
delete temp['onAttach'];
217+
delete temp['onUpdate'];
218+
delete temp['object'];
219+
delete temp['objects'];
220+
delete temp['nonObjects'];
221+
delete temp['parent'];
222+
delete temp['add'];
223+
delete temp['remove'];
224+
delete temp['updateGeometryStamp'];
225+
delete temp['setParent'];
226+
delete temp['store'];
227+
delete temp['handlers'];
228+
delete temp['hierarchyStore'];
229+
delete temp['previousAttach'];
230+
delete temp['setPointerEvent'];
231+
delete temp['addInteraction'];
232+
delete temp['removeInteraction'];
233+
234+
if (iS.type !== 'ngt-primitive') {
235+
delete node['__ngt__'];
236+
}
237+
}
238+
239+
// clear our debugNode
240+
rS[NgtRendererClassId.injector] = undefined;
241+
242+
if (rS[NgtRendererClassId.type] === 'comment') {
243+
delete node[NGT_INTERNAL_ADD_COMMENT_FLAG];
244+
delete node[NGT_INTERNAL_SET_PARENT_COMMENT_FLAG];
245+
delete node[NGT_CANVAS_CONTENT_FLAG];
246+
delete node[NGT_PORTAL_CONTENT_FLAG];
247+
delete node[NGT_DOM_PARENT_FLAG];
248+
}
249+
250+
// clear getAttribute if exist
251+
if (
252+
'getAttribute' in node &&
253+
typeof node['getAttribute'] === 'function' &&
254+
node['getAttribute'][NGT_GET_NODE_ATTRIBUTE_FLAG]
255+
) {
256+
delete node['getAttribute'];
257+
}
258+
259+
// mark node as destroyed
260+
rS[NgtRendererClassId.destroyed] = true;
261+
}

libs/soba/misc/src/lib/html/html-content.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ const defaultHtmlContentOptions: NgtsHTMLContentOptions = {
7070
};
7171

7272
@Component({
73-
selector: '[htmlContent]',
73+
selector: 'div[htmlContent]',
7474
template: `
7575
@if (html.transform()) {
7676
<div

0 commit comments

Comments
 (0)