feat(elements): enable Shadow DOM v1 and slots (#24861)
When using ViewEncapsulation.ShadowDom, Angular will not remove the child nodes of the DOM node a root Component is bootstrapped into. This enables developers building Angular Elements to use the `<slot>` element to do native content projection. PR Close #24861
This commit is contained in:

committed by
Misko Hevery

parent
4815b92495
commit
c9844a2f01
@ -6,19 +6,14 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, ComponentFactoryResolver, EventEmitter, Injector, Input, NgModule, Output, ViewEncapsulation, destroyPlatform} from '@angular/core';
|
||||
import {Component, ComponentFactoryResolver, EventEmitter, Input, NgModule, Output, ViewEncapsulation, destroyPlatform} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
|
||||
import {Subject} from 'rxjs';
|
||||
|
||||
import {NgElement, NgElementConstructor, createCustomElement} from '../src/create-custom-element';
|
||||
import {NgElementStrategy, NgElementStrategyEvent, NgElementStrategyFactory} from '../src/element-strategy';
|
||||
import {NgElement, createCustomElement} from '../src/create-custom-element';
|
||||
|
||||
|
||||
type WithFooBar = {
|
||||
fooFoo: string,
|
||||
barBar: string
|
||||
};
|
||||
// we only run these tests in browsers that support Shadom DOM slots natively
|
||||
if (browserDetection.supportsCustomElements && browserDetection.supportsShadowDom) {
|
||||
describe('slots', () => {
|
||||
@ -55,7 +50,7 @@ if (browserDetection.supportsCustomElements && browserDetection.supportsShadowDo
|
||||
const content = testContainer.querySelector('span.projected') !;
|
||||
const slot = testEl.shadowRoot !.querySelector('slot') !;
|
||||
const assignedNodes = slot.assignedNodes();
|
||||
expect(assignedNodes[0]).toEqual(content);
|
||||
expect(assignedNodes[0]).toBe(content);
|
||||
});
|
||||
|
||||
it('should use a named slot to project content', () => {
|
||||
@ -65,7 +60,7 @@ if (browserDetection.supportsCustomElements && browserDetection.supportsShadowDo
|
||||
const content = testContainer.querySelector('span.projected') !;
|
||||
const slot = testEl.shadowRoot !.querySelector('slot[name=header]') as HTMLSlotElement;
|
||||
const assignedNodes = slot.assignedNodes();
|
||||
expect(assignedNodes[0]).toEqual(content);
|
||||
expect(assignedNodes[0]).toBe(content);
|
||||
});
|
||||
|
||||
it('should use named slots to project content', () => {
|
||||
@ -81,8 +76,8 @@ if (browserDetection.supportsCustomElements && browserDetection.supportsShadowDo
|
||||
const headerSlot = testEl.shadowRoot !.querySelector('slot[name=header]') as HTMLSlotElement;
|
||||
const bodySlot = testEl.shadowRoot !.querySelector('slot[name=body]') as HTMLSlotElement;
|
||||
|
||||
expect(headerContent.assignedSlot).toEqual(headerSlot);
|
||||
expect(bodyContent.assignedSlot).toEqual(bodySlot);
|
||||
expect(headerContent.assignedSlot).toBe(headerSlot);
|
||||
expect(bodyContent.assignedSlot).toBe(bodySlot);
|
||||
});
|
||||
|
||||
it('should listen to slotchange events', (done) => {
|
||||
@ -94,7 +89,6 @@ if (browserDetection.supportsCustomElements && browserDetection.supportsShadowDo
|
||||
templateEl.innerHTML = tpl;
|
||||
const template = templateEl.content.cloneNode(true) as DocumentFragment;
|
||||
const testEl = template.querySelector('slot-events-el') !as NgElement & SlotEventsComponent;
|
||||
const content = template.querySelector('span.projected');
|
||||
testEl.addEventListener('slotEventsChange', e => {
|
||||
expect(testEl.slotEvents.length).toEqual(1);
|
||||
done();
|
||||
@ -133,15 +127,6 @@ class NamedSlotsComponent {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'default-slots-el',
|
||||
template: '<div class="slotparent"><slot name="header"></slot><slot name="body"></slot></div>',
|
||||
encapsulation: ViewEncapsulation.ShadowDom
|
||||
})
|
||||
class DefaultSlotsComponent {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'slot-events-el',
|
||||
template: '<slot (slotchange)="onSlotChange($event)"></slot>',
|
||||
@ -157,10 +142,8 @@ class SlotEventsComponent {
|
||||
}
|
||||
}
|
||||
|
||||
const testElements = [
|
||||
DefaultSlotComponent, NamedSlotComponent, NamedSlotsComponent, DefaultSlotsComponent,
|
||||
SlotEventsComponent
|
||||
];
|
||||
const testElements =
|
||||
[DefaultSlotComponent, NamedSlotComponent, NamedSlotsComponent, SlotEventsComponent];
|
||||
|
||||
@NgModule({imports: [BrowserModule], declarations: testElements, entryComponents: testElements})
|
||||
class TestModule {
|
||||
|
Reference in New Issue
Block a user