From 6abeca4b4d4f333e3db5523780f86d84f7e42a37 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Sat, 6 Jan 2024 13:39:49 -0500 Subject: [PATCH] bug/issue 128 fix shadow root rendering for JSX (#129) * fix shadow root rendering for JSX * output JSX DSD as a template element * JSX + DSD sandbox demo working * JSX + DSD + inferredObservability sandbox demo working * add random reset feature to counter sandbox demos * rename test to match feature being tested * refine test cases * constructor not a prerequiste for using inferredObservability anymore * runtime render refactoring * document DSD interop * misc clean and docs --- docs/pages/docs.md | 32 ++++++++- sandbox/components/card.js | 2 +- sandbox/components/card.jsx | 6 +- sandbox/components/counter-dsd.jsx | 10 +-- sandbox/components/counter.jsx | 2 +- sandbox/index.html | 49 +++++++++---- src/jsx-loader.js | 32 ++++++--- .../fixtures/attribute-changed-callback.txt | 0 .../fixtures/get-observed-attributes.txt | 0 .../jsx-inferred-obsevability.spec.js} | 2 +- .../src/counter.jsx | 0 .../jsx-shadow-dom/jsx-shadow-dom.spec.js | 71 +++++++++++++++++++ test/cases/jsx-shadow-dom/src/heading.jsx | 27 +++++++ 13 files changed, 190 insertions(+), 43 deletions(-) rename test/cases/{jsx-coarse-grained => jsx-inferred-observability}/fixtures/attribute-changed-callback.txt (100%) rename test/cases/{jsx-coarse-grained => jsx-inferred-observability}/fixtures/get-observed-attributes.txt (100%) rename test/cases/{jsx-coarse-grained/jsx-coarse-grained.spec.js => jsx-inferred-observability/jsx-inferred-obsevability.spec.js} (95%) rename test/cases/{jsx-coarse-grained => jsx-inferred-observability}/src/counter.jsx (100%) create mode 100644 test/cases/jsx-shadow-dom/jsx-shadow-dom.spec.js create mode 100644 test/cases/jsx-shadow-dom/src/heading.jsx diff --git a/docs/pages/docs.md b/docs/pages/docs.md index d040f2a..d4434b4 100644 --- a/docs/pages/docs.md +++ b/docs/pages/docs.md @@ -246,7 +246,7 @@ export default class Counter extends HTMLElement { } connectedCallback() { - this.render(); + this.render(); // this is required } increment() { @@ -289,6 +289,32 @@ There are of couple things you will need to do to use WCC with JSX: > _See our [example's page](/examples#jsx) for some usages of WCC + JSX._ 👀 +### Declarative Shadow DOM + +To opt-in to Declarative Shadow DOM with JSX, you will need to signal to the WCC compiler your intentions so it can accurately mount from a `shadowRoot` on the client side. To opt-in, simply make a call to `attachShadow` in your `connectedCallback` method. + +Using, the Counter example from above, we would amend it like so: + +```js +export default class Counter extends HTMLElement { + constructor() { + super(); + this.count = 0; + } + + connectedCallback() { + if (!this.shadowRoot) { + this.attachShadow({ mode: 'open' }); // this is required for DSD support + this.render(); + } + } + + // ... +} + +customElements.define('wcc-counter', Counter); +``` + ### (Inferred) Attribute Observability An optional feature supported by JSX based compilation is a feature called `inferredObservability`. With this enabled, WCC will read any `this` member references in your component's `render` function and map each member instance to @@ -322,6 +348,6 @@ And so now when the attribute is set on this component, the component will re-re ``` Some notes / limitations: -- Please be aware of the above linked discussion which is tracking known bugs / feature requests to all things WCC + JSX. +- Please be aware of the above linked discussion which is tracking known bugs / feature requests / open items related to all things WCC + JSX. - We consider the capability of this observability to be "coarse grained" at this time since WCC just re-runs the entire `render` function, replacing of the `innerHTML` for the host component. Thought it is still WIP, we are exploring a more ["fine grained" approach](https://github.com/ProjectEvergreen/wcc/issues/108) that will more efficient than blowing away all the HTML, a la in the style of [**lit-html**](https://lit.dev/docs/templates/overview/) or [**Solid**'s Signals](https://www.solidjs.com/tutorial/introduction_signals). -- This automatically _reflects properties used in the `render` function to attributes_, so YMMV. \ No newline at end of file +- This automatically _reflects properties used in the `render` function to attributes_, so YMMV. diff --git a/sandbox/components/card.js b/sandbox/components/card.js index 3d27a9b..d2c05ae 100644 --- a/sandbox/components/card.js +++ b/sandbox/components/card.js @@ -1,7 +1,7 @@ export default class Card extends HTMLElement { selectItem() { - alert(`selected item is => ${this.getAttribute('title')}!`); + alert(`selected item is => ${this.title}!`); } connectedCallback() { diff --git a/sandbox/components/card.jsx b/sandbox/components/card.jsx index 006ef9f..5aed1aa 100644 --- a/sandbox/components/card.jsx +++ b/sandbox/components/card.jsx @@ -19,12 +19,12 @@ const styles = ` export default class CardJsx extends HTMLElement { selectItem() { - alert(`selected item is => ${this.getAttribute('title')}!`); + alert(`selected item is => ${this.title}!`); } connectedCallback() { if (!this.shadowRoot) { - console.log('NO shadowRoot detected for card.jsx!'); + console.warn('NO shadowRoot detected for card.jsx!'); this.thumbnail = this.getAttribute('thumbnail'); this.title = this.getAttribute('title'); @@ -39,7 +39,7 @@ export default class CardJsx extends HTMLElement { const { thumbnail, title } = this; return ( -
+
diff --git a/sandbox/components/counter-dsd.jsx b/sandbox/components/counter-dsd.jsx index 40e5fb5..26c7a53 100644 --- a/sandbox/components/counter-dsd.jsx +++ b/sandbox/components/counter-dsd.jsx @@ -1,16 +1,10 @@ export const inferredObservability = true; export default class CounterDsdJsx extends HTMLElement { - // having a constructor is required for inferredObservability - constructor() { - super(); - this.count = 0; - } - connectedCallback() { if (!this.shadowRoot) { - console.log('NO shadowRoot detected for counter-dsd.jsx!'); - this.count = this.getAttribute('count'); + console.warn('NO shadowRoot detected for counter-dsd.jsx!'); + this.count = this.getAttribute('count') || 0; // having an attachShadow call is required for DSD this.attachShadow({ mode: 'open' }); diff --git a/sandbox/components/counter.jsx b/sandbox/components/counter.jsx index 41e5f87..e54fe24 100644 --- a/sandbox/components/counter.jsx +++ b/sandbox/components/counter.jsx @@ -1,13 +1,13 @@ export const inferredObservability = true; export default class CounterJsx extends HTMLElement { - // having a constructor is required for inferredObservability constructor() { super(); this.count = 0; } connectedCallback() { + this.count = parseInt(this.getAttribute('count'), 10) || this.count; this.render(); } diff --git a/sandbox/index.html b/sandbox/index.html index 339dd8b..8ca8030 100644 --- a/sandbox/index.html +++ b/sandbox/index.html @@ -19,8 +19,33 @@ margin: 0 auto; text-align: center; } + + button.reset { + display: block; + min-width: 5%; + margin: 0 auto; + } + +