Skip to content

Commit 840a7be

Browse files
committed
implement shadowdom option
1 parent 96e9768 commit 840a7be

File tree

10 files changed

+61
-10
lines changed

10 files changed

+61
-10
lines changed

src/compiler/compile/Component.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ interface ComponentOptions {
4646
accessors?: boolean;
4747
preserveWhitespace?: boolean;
4848
ceProps?: Record<string, { reflect?: boolean; type?: 'String' | 'Boolean' | 'Number' | 'Array' | 'Object', attribute?: string }>;
49+
shadowdom?: 'open' | 'none';
4950
}
5051

5152
const regex_leading_directory_separator = /^[/\\]/;
@@ -1574,6 +1575,17 @@ function process_component_options(component: Component, nodes) {
15741575
break;
15751576
}
15761577

1578+
case 'shadowdom': {
1579+
const shadowdom = get_value(attribute, compiler_errors.invalid_shadowdom_attribute);
1580+
1581+
if (shadowdom !== 'open' && shadowdom !== 'none') {
1582+
return component.error(attribute, compiler_errors.invalid_shadowdom_attribute);
1583+
}
1584+
1585+
component_options.shadowdom = shadowdom;
1586+
break;
1587+
}
1588+
15771589
case 'ceProps': {
15781590
const error = () => component.error(attribute, compiler_errors.invalid_ceProps_attribute);
15791591
const { value } = attribute;

src/compiler/compile/compiler_errors.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ export default {
206206
code: 'invalid-tag-attribute',
207207
message: "'tag' must be a string literal"
208208
},
209+
invalid_shadowdom_attribute: {
210+
code: 'invalid-shadowdom-attribute',
211+
message: "'shadowdom' must be either 'open' or 'none'"
212+
},
209213
invalid_ceProps_attribute: {
210214
code: 'invalid-ceProps-attribute',
211215
message: "'ceProps' must be a statically analyzable object literal of the form " +

src/compiler/compile/render_dom/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,9 +555,10 @@ export default function dom(
555555
.filter(accessor => !writable_props.some(prop => prop.export_name === accessor.key.name))
556556
.map(accessor => `"${accessor.key.name}"`)
557557
.join(',');
558+
const use_shadow_dom = component.component_options.shadowdom !== 'none' ? 'true' : 'false';
558559

559560
body.push(
560-
b`@_customElements.define("${component.tag}", @create_custom_element(${name}, ${JSON.stringify(props_str)}, [${slots_str}], [${accessors_str}]));`
561+
b`@_customElements.define("${component.tag}", @create_custom_element(${name}, ${JSON.stringify(props_str)}, [${slots_str}], [${accessors_str}], ${use_shadow_dom}));`
561562
);
562563
}
563564

src/runtime/internal/Component.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,13 @@ if (typeof HTMLElement === 'function') {
157157

158158
constructor(
159159
private $$componentCtor: ComponentType,
160-
private $$slots: string[]
160+
private $$slots: string[],
161+
use_shadow_dom: boolean
161162
) {
162163
super();
163-
this.attachShadow({ mode: 'open' });
164+
if (use_shadow_dom) {
165+
this.attachShadow({ mode: 'open' });
166+
}
164167
}
165168

166169
addEventListener(type: string, listener: any, options?: any): void {
@@ -237,7 +240,7 @@ if (typeof HTMLElement === 'function') {
237240
}
238241

239242
this.$$component = new this.$$componentCtor({
240-
target: this.shadowRoot!,
243+
target: this.shadowRoot || this,
241244
props: {
242245
...this.$$data,
243246
$$slots,
@@ -330,17 +333,19 @@ interface CustomElementPropDefinition {
330333
* @param props_definition The props to observe
331334
* @param slots The slots to create
332335
* @param accessors Other accessors besides the ones for props the component has
336+
* @param use_shadow_dom Whether to use shadow DOM
333337
* @returns A custom element class
334338
*/
335339
export function create_custom_element(
336340
Component: ComponentType,
337341
props_definition: Record<string, CustomElementPropDefinition>,
338342
slots: string[],
339-
accessors: string[]
343+
accessors: string[],
344+
use_shadow_dom: boolean
340345
) {
341346
const Class = class extends SvelteElement {
342347
constructor() {
343-
super(Component, slots);
348+
super(Component, slots, use_shadow_dom);
344349
this.$$props_definition = props_definition;
345350
}
346351

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<svelte:options tag="custom-element" shadowdom="none" />
2+
3+
<script>
4+
export let name;
5+
</script>
6+
7+
<h1>Hello {name}!</h1>
8+
9+
<style>
10+
h1 {
11+
color: red;
12+
}
13+
</style>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import * as assert from 'assert';
2+
import { tick } from 'svelte';
3+
import './main.svelte';
4+
5+
export default async function (target) {
6+
target.innerHTML = '<custom-element name="world"></custom-element>';
7+
await tick();
8+
9+
const el = target.querySelector('custom-element');
10+
const h1 = el.querySelector('h1');
11+
12+
assert.equal(el.name, 'world');
13+
assert.equal(el.shadowRoot, null);
14+
assert.equal(h1.innerHTML, 'Hello world!');
15+
assert.equal(getComputedStyle(h1).color, 'rgb(255, 0, 0)');
16+
}

test/custom-elements/samples/no-svelte-options/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import CustomElement from './main.svelte';
44
import { create_custom_element } from 'svelte/internal';
55

66
export default async function (target) {
7-
customElements.define('no-tag', create_custom_element(CustomElement, {name: {}}, [], []));
7+
customElements.define('no-tag', create_custom_element(CustomElement, {name: {}}, [], [], true));
88
target.innerHTML = '<no-tag name="world"></no-tag>';
99
await tick();
1010

test/custom-elements/samples/no-tag-warning/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import CustomElement from './main.svelte';
44
import { create_custom_element } from 'svelte/internal';
55

66
export default async function (target) {
7-
customElements.define('no-tag', create_custom_element(CustomElement, { name: {}}, [], []));
7+
customElements.define('no-tag', create_custom_element(CustomElement, { name: {}}, [], [], true));
88
target.innerHTML = '<no-tag name="world"></no-tag>';
99
await tick();
1010

test/custom-elements/samples/no-tag/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import CustomElement from './main.svelte';
44
import { create_custom_element } from 'svelte/internal';
55

66
export default async function (target) {
7-
customElements.define('no-tag', create_custom_element(CustomElement, { name: {} }, [], []));
7+
customElements.define('no-tag', create_custom_element(CustomElement, { name: {} }, [], [], true));
88
target.innerHTML = '<no-tag name="world"></no-tag>';
99
await tick();
1010

test/js/samples/css-shadow-dom-keyframes/expected.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,5 @@ class Component extends SvelteComponent {
4444
}
4545
}
4646

47-
customElements.define("custom-element", create_custom_element(Component, {}, [], []));
47+
customElements.define("custom-element", create_custom_element(Component, {}, [], [], true));
4848
export default Component;

0 commit comments

Comments
 (0)