Skip to content

Commit 8cc6785

Browse files
Cris WardCris Ward
Cris Ward
authored and
Cris Ward
committed
[WIP] sveltejs#1748 - Custom elements light dom, open / closed
1 parent efe8ab9 commit 8cc6785

File tree

6 files changed

+32
-10
lines changed

6 files changed

+32
-10
lines changed

src/compiler/compile/Component.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import Stylesheet from './css/Stylesheet';
1414
import { test } from '../config';
1515
import Fragment from './nodes/Fragment';
1616
import internal_exports from './internal_exports';
17-
import { Ast, CompileOptions, Var, Warning, CssResult } from '../interfaces';
17+
import { Ast, CompileOptions, Var, Warning, CssResult, ShadowDomMode } from '../interfaces';
1818
import error from '../utils/error';
1919
import get_code_frame from '../utils/get_code_frame';
2020
import flatten_reference from './utils/flatten_reference';
@@ -30,6 +30,7 @@ import check_graph_for_cycles from './utils/check_graph_for_cycles';
3030
import { print, x, b } from 'code-red';
3131

3232
interface ComponentOptions {
33+
shadowdom?: ShadowDomMode;
3334
namespace?: string;
3435
tag?: string;
3536
immutable?: boolean;
@@ -158,6 +159,7 @@ export default class Component {
158159
});
159160
}
160161
this.tag = this.component_options.tag || compile_options.tag;
162+
this.compile_options.shadowDom = this.component_options.shadowdom || "open";
161163
} else {
162164
this.tag = this.name.name;
163165
}
@@ -170,7 +172,7 @@ export default class Component {
170172

171173
this.walk_instance_js_post_template();
172174

173-
if (!compile_options.customElement) this.stylesheet.reify();
175+
if (!compile_options.customElement || compile_options.shadowDom=="none") this.stylesheet.reify();
174176

175177
this.stylesheet.warn_on_unused_selectors(this);
176178
}
@@ -1414,7 +1416,16 @@ function process_component_options(component: Component, nodes) {
14141416
component_options[name] = value;
14151417
break;
14161418
}
1419+
case 'shadowdom':{
1420+
const code = 'invalid-shadowdom-attribute';
1421+
const message = `'shadowdom' must be set to 'open', 'closed or 'none'`;
1422+
const value = get_value(attribute, code, message)
1423+
if(value != "open" && value != "none" && value != "closed")
1424+
component.error(attribute, { code, message });
14171425

1426+
component_options[name] = value;
1427+
break;
1428+
}
14181429
default:
14191430
component.error(attribute, {
14201431
code: `invalid-options-attribute`,

src/compiler/compile/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const valid_options = [
2222
'hydratable',
2323
'legacy',
2424
'customElement',
25+
'shadowDom',
2526
'tag',
2627
'css',
2728
'loopGuardTimeout',

src/compiler/compile/render_dom/index.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default function dom(
2020
block.has_outro_method = true;
2121

2222
// prevent fragment being created twice (#1063)
23-
if (options.customElement) block.chunks.create.push(b`this.c = @noop;`);
23+
if (options.customElement && options.shadowDom !== "none") block.chunks.create.push(b`this.c = @noop;`);
2424

2525
const body = [];
2626

@@ -29,17 +29,17 @@ export default function dom(
2929
body.push(b`const ${renderer.file_var} = ${file};`);
3030
}
3131

32-
const css = component.stylesheet.render(options.filename, !options.customElement);
32+
const css = component.stylesheet.render(options.filename, (!options.customElement || options.shadowDom === "none"));
3333
const styles = component.stylesheet.has_styles && options.dev
3434
? `${css.code}\n/*# sourceMappingURL=${css.map.toUrl()} */`
3535
: css.code;
3636

3737
const add_css = component.get_unique_name('add_css');
3838

3939
const should_add_css = (
40-
!options.customElement &&
40+
(!options.customElement &&
4141
!!styles &&
42-
options.css !== false
42+
options.css !== false ) || options.shadowDom === "none"
4343
);
4444

4545
if (should_add_css) {
@@ -437,14 +437,19 @@ export default function dom(
437437
}
438438

439439
if (options.customElement) {
440+
const lightDom = options.shadowDom === 'none';
440441
const declaration = b`
441442
class ${name} extends @SvelteElement {
442443
constructor(options) {
443444
super();
445+
${!lightDom && b`
446+
this._root =this.attachShadow({ mode: '${options.shadowDom}' });
447+
`}
444448
445-
${css.code && b`this.shadowRoot.innerHTML = \`<style>${css.code.replace(/\\/g, '\\\\')}${options.dev ? `\n/*# sourceMappingURL=${css.map.toUrl()} */` : ''}</style>\`;`}
449+
${css.code && !lightDom && b`this._root.innerHTML = \`<style>${css.code.replace(/\\/g, '\\\\')}${options.dev ? `\n/*# sourceMappingURL=${css.map.toUrl()} */` : ''}</style>\`;`}
450+
${should_add_css && lightDom && b`if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`}
446451
447-
@init(this, { target: this.shadowRoot }, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
452+
@init(this, { target: ${lightDom ? 'this' : 'this._root'} }, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
448453
449454
${dev_props_check}
450455

src/compiler/interfaces.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export interface CompileOptions {
120120
hydratable?: boolean;
121121
legacy?: boolean;
122122
customElement?: boolean;
123+
shadowDom?: ShadowDomMode;
123124
tag?: string;
124125
css?: boolean;
125126
loopGuardTimeout?: number;
@@ -166,4 +167,8 @@ export interface Var {
166167
export interface CssResult {
167168
code: string;
168169
map: SourceMap;
169-
}
170+
}
171+
172+
export type ShadowDomMode = 'none'
173+
| 'open'
174+
| 'closed'

src/runtime/internal/Component.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,6 @@ if (typeof HTMLElement === 'function') {
167167
$$: T$$;
168168
constructor() {
169169
super();
170-
this.attachShadow({ mode: 'open' });
171170
}
172171

173172
connectedCallback() {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ function create_fragment(ctx) {
3333
class Component extends SvelteElement {
3434
constructor(options) {
3535
super();
36+
this.attachShadow({ mode: "open" });
3637
this.shadowRoot.innerHTML = `<style>div{animation:foo 1s}@keyframes foo{0%{opacity:0}100%{opacity:1}}</style>`;
3738
init(this, { target: this.shadowRoot }, null, create_fragment, safe_not_equal, {});
3839

0 commit comments

Comments
 (0)