From d9cbbcace7fa3e641b464e7ea2ca2aa410038997 Mon Sep 17 00:00:00 2001 From: kj Date: Fri, 17 Nov 2023 13:36:45 -0800 Subject: [PATCH 01/18] Adds entries for context and instanceID --- app/docs/md/elements/state/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/docs/md/elements/state/index.md b/app/docs/md/elements/state/index.md index dedcd464..bddc2629 100644 --- a/app/docs/md/elements/state/index.md +++ b/app/docs/md/elements/state/index.md @@ -38,10 +38,12 @@ export default function MyElement ({ html, state }) { -The state object contains two top level entries: +The state object contains four top level entries: - `attrs`, which contains all the key value pairs of attributes passed into your custom element’s instance - `store`, which contains the global state of your Enhance application +- `instanceID`, which is a unique ID per instance of Custom Element +- `context`, which is an Object that can be used to pass state to child elements to avoid prop drilling. These two different entries allow you to work with both basic and complex state in powerful ways without the need for complex abstractions or third party libraries. From 5dabccebe2139c4e863a7216236f43baba3ed567 Mon Sep 17 00:00:00 2001 From: kj Date: Fri, 17 Nov 2023 15:17:06 -0800 Subject: [PATCH 02/18] Adds context documentation --- app/docs/md/elements/state/context.md | 77 +++++++++++++++++++++++ app/docs/md/elements/state/instance-id.md | 5 ++ app/docs/nav-data.mjs | 10 ++- 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 app/docs/md/elements/state/context.md create mode 100644 app/docs/md/elements/state/instance-id.md diff --git a/app/docs/md/elements/state/context.md b/app/docs/md/elements/state/context.md new file mode 100644 index 00000000..07d2d941 --- /dev/null +++ b/app/docs/md/elements/state/context.md @@ -0,0 +1,77 @@ +--- +title: Context +--- + +The context object enables passing state to child elements without needing to resort to passing attributes down through multiple elements. + +## Update context + +The context object is passed as a key on the state object. Add data to the context object and it will be available to child elements. + +[Follow along by checking out the context demo from GitHub](https://github.com/enhance-dev/context-demo) + +Given this markup you can use the context object to pass state directly to a deeply nested child element. + + + +```html + + + + + + + + + +``` + + + + +Add a heading key to context in the parent element + + + +```javascript +export default function ContextParent({ html, state }) { + const { context } = state + context.heading = 'Heading set via context' + return html` + + + ` +} +``` + + + +Render the heading passed via context in the deeply nested child element + + +```javascript +export default function ContextHeading({ html, state }) { + const { context } = state + const { heading='Default heading' } = context + return html` + +

${heading}

+ ` +} +``` + +
+ + diff --git a/app/docs/md/elements/state/instance-id.md b/app/docs/md/elements/state/instance-id.md new file mode 100644 index 00000000..ec8d9b30 --- /dev/null +++ b/app/docs/md/elements/state/instance-id.md @@ -0,0 +1,5 @@ +--- +title: Instance ID +--- + + diff --git a/app/docs/nav-data.mjs b/app/docs/nav-data.mjs index f1f4adf1..0524d959 100644 --- a/app/docs/nav-data.mjs +++ b/app/docs/nav-data.mjs @@ -82,7 +82,15 @@ export const data = [ path: '/docs/elements/state/', label: 'State', hasChildren: true, - items: ['attributes', 'store'], + items: [ + 'attributes', + 'store', + { + slug: 'instance-id', + label: 'Instance ID', + }, + 'context', + ], }, ], }, From ab560d96899ddabd670ab8674667016c5aa9bc76 Mon Sep 17 00:00:00 2001 From: kj Date: Fri, 17 Nov 2023 15:20:42 -0800 Subject: [PATCH 03/18] Updates context doc --- app/docs/md/elements/state/context.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/docs/md/elements/state/context.md b/app/docs/md/elements/state/context.md index 07d2d941..130c0787 100644 --- a/app/docs/md/elements/state/context.md +++ b/app/docs/md/elements/state/context.md @@ -4,11 +4,11 @@ title: Context The context object enables passing state to child elements without needing to resort to passing attributes down through multiple elements. -## Update context +## Set parent context The context object is passed as a key on the state object. Add data to the context object and it will be available to child elements. -[Follow along by checking out the context demo from GitHub](https://github.com/enhance-dev/context-demo) +[Follow along by checking out the context demo from GitHub →](https://github.com/enhance-dev/context-demo) Given this markup you can use the context object to pass state directly to a deeply nested child element. From 153a99cc09b508dc8aa6d7904d35714f6d9fdecb Mon Sep 17 00:00:00 2001 From: kj Date: Fri, 17 Nov 2023 16:14:36 -0800 Subject: [PATCH 04/18] Adds instance ID --- app/docs/md/elements/state/instance-id.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/docs/md/elements/state/instance-id.md b/app/docs/md/elements/state/instance-id.md index ec8d9b30..2d2db9e0 100644 --- a/app/docs/md/elements/state/instance-id.md +++ b/app/docs/md/elements/state/instance-id.md @@ -2,4 +2,18 @@ title: Instance ID --- +`instanceID` is a unique identifier that is generated per Custom Element instance. This enables you to differentiate between multiple instances of the same element on a page. It can also be useful when using a string based diffing library like [Morphdom](https://github.com/patrick-steele-idem/morphdom) that require unique identifiers for DOM diffing. +```javascript +export default function MyCard({ html, state }) { + const { attrs={}, instanceID='' } = state + const { content='', heading='' } = attrs + + return html` +
+

${heading}

+

${content}

+
+ ` +} +``` From 929529b21611e26f4a2f902b0b36ed21e99750fd Mon Sep 17 00:00:00 2001 From: kj Date: Fri, 17 Nov 2023 16:21:01 -0800 Subject: [PATCH 05/18] Updates intance id doc --- app/docs/md/elements/state/instance-id.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/docs/md/elements/state/instance-id.md b/app/docs/md/elements/state/instance-id.md index 2d2db9e0..e7732fff 100644 --- a/app/docs/md/elements/state/instance-id.md +++ b/app/docs/md/elements/state/instance-id.md @@ -2,7 +2,7 @@ title: Instance ID --- -`instanceID` is a unique identifier that is generated per Custom Element instance. This enables you to differentiate between multiple instances of the same element on a page. It can also be useful when using a string based diffing library like [Morphdom](https://github.com/patrick-steele-idem/morphdom) that require unique identifiers for DOM diffing. +`instanceID` is a unique identifier that is generated per Custom Element instance. This enables you to differentiate between multiple instances of the same element on a page. It can also be useful when using a string based diffing library like [Morphdom](https://github.com/patrick-steele-idem/morphdom) which keys on unique identifiers to know when to update versus replace an element. ```javascript export default function MyCard({ html, state }) { @@ -17,3 +17,7 @@ export default function MyCard({ html, state }) { ` } ``` + + + Pro tip: As in the example above, prefix the id with the element name in order to use the id with multiple child elements. + From 05f769473ab791779c9f99dade8f21586363646e Mon Sep 17 00:00:00 2001 From: kj Date: Fri, 17 Nov 2023 16:23:18 -0800 Subject: [PATCH 06/18] Updates spellcheck to include Morphdom --- scripts/dictionary.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/dictionary.txt b/scripts/dictionary.txt index 526fdf88..d057fae7 100644 --- a/scripts/dictionary.txt +++ b/scripts/dictionary.txt @@ -48,6 +48,7 @@ lowercas(e|ed) MDN MDN's mixi(n|ns) +Morphdom natively Netlify polyfills From db01c1d29a2d2e3c1bc4c94b0ae4b2b743185631 Mon Sep 17 00:00:00 2001 From: kj Date: Mon, 20 Nov 2023 14:02:25 -0800 Subject: [PATCH 07/18] Update app/docs/md/elements/state/context.md Co-authored-by: Cole Peters --- app/docs/md/elements/state/context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/docs/md/elements/state/context.md b/app/docs/md/elements/state/context.md index 130c0787..90bb03a8 100644 --- a/app/docs/md/elements/state/context.md +++ b/app/docs/md/elements/state/context.md @@ -10,7 +10,7 @@ The context object is passed as a key on the state object. Add data to the conte [Follow along by checking out the context demo from GitHub →](https://github.com/enhance-dev/context-demo) -Given this markup you can use the context object to pass state directly to a deeply nested child element. +Given this markup you can use the context object to pass state directly to a deeply nested child element. Consider the page structure in the example below: From 35857758e3ae20ae5698454eb51015c32b4343c2 Mon Sep 17 00:00:00 2001 From: kj Date: Mon, 20 Nov 2023 14:02:42 -0800 Subject: [PATCH 08/18] Update app/docs/md/elements/state/context.md Co-authored-by: Cole Peters --- app/docs/md/elements/state/context.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/docs/md/elements/state/context.md b/app/docs/md/elements/state/context.md index 90bb03a8..ae39690d 100644 --- a/app/docs/md/elements/state/context.md +++ b/app/docs/md/elements/state/context.md @@ -17,8 +17,8 @@ Given this markup you can use the context object to pass state directly to a dee ```html - - + + From fe322b58bcb99effa86da4dce8cd36b235949904 Mon Sep 17 00:00:00 2001 From: kj Date: Mon, 20 Nov 2023 14:03:08 -0800 Subject: [PATCH 09/18] Update app/docs/md/elements/state/context.md Co-authored-by: Cole Peters --- app/docs/md/elements/state/context.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/docs/md/elements/state/context.md b/app/docs/md/elements/state/context.md index ae39690d..f1f05bde 100644 --- a/app/docs/md/elements/state/context.md +++ b/app/docs/md/elements/state/context.md @@ -20,8 +20,8 @@ Given this markup you can use the context object to pass state directly to a dee - - + + ``` From fb8e29d41a82a8748e5f1b3cbefbe9e59b8e37a6 Mon Sep 17 00:00:00 2001 From: kj Date: Mon, 20 Nov 2023 14:03:30 -0800 Subject: [PATCH 10/18] Update app/docs/md/elements/state/context.md Co-authored-by: Cole Peters --- app/docs/md/elements/state/context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/docs/md/elements/state/context.md b/app/docs/md/elements/state/context.md index f1f05bde..6997a7f1 100644 --- a/app/docs/md/elements/state/context.md +++ b/app/docs/md/elements/state/context.md @@ -29,7 +29,7 @@ Given this markup you can use the context object to pass state directly to a dee -Add a heading key to context in the parent element +Add a heading key to the context object in the parent element: From 898fc5598fee1fe36472d1ce6b835de088329e9b Mon Sep 17 00:00:00 2001 From: kj Date: Mon, 20 Nov 2023 14:03:46 -0800 Subject: [PATCH 11/18] Update app/docs/md/elements/state/context.md Co-authored-by: Cole Peters --- app/docs/md/elements/state/context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/docs/md/elements/state/context.md b/app/docs/md/elements/state/context.md index 6997a7f1..ed1d7150 100644 --- a/app/docs/md/elements/state/context.md +++ b/app/docs/md/elements/state/context.md @@ -54,7 +54,7 @@ export default function ContextParent({ html, state }) { -Render the heading passed via context in the deeply nested child element +Render the heading passed via context in the deeply nested child element: ```javascript From 122fd2ebe39e6688669d9e87413a826553eeff64 Mon Sep 17 00:00:00 2001 From: kj Date: Fri, 17 Nov 2023 16:33:51 -0800 Subject: [PATCH 12/18] closes #171 --- app/docs/md/conventions/browser.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/docs/md/conventions/browser.md b/app/docs/md/conventions/browser.md index af64617d..e4414a1a 100644 --- a/app/docs/md/conventions/browser.md +++ b/app/docs/md/conventions/browser.md @@ -77,7 +77,7 @@ Write a pure function for returning the HTML markup for the `my-message.mjs` cus ```javascript export default function MyMessage({ html, state }) { - const { attrs=[] } = state + const { attrs={} } = state const { message='' } = attrs return html`

${ message }

` @@ -117,12 +117,7 @@ class MyMessageElement extends HTMLElement { } html(strings, ...values) { - const collect = [] - for (let i = 0; i < strings.length - 1; i++) { - collect.push(strings[i], values[i]) - } - collect.push(strings[strings.length - 1]) - return collect.join('') + return String.raw({ raw: strings }, ...values) } static get observedAttributes() { From 4993e54f093062d127ea2d80965ae26915d43eac Mon Sep 17 00:00:00 2001 From: Cole Peters Date: Mon, 20 Nov 2023 10:26:25 -0600 Subject: [PATCH 13/18] Use classes for theme toggle querySelectors --- app/elements/docs/theme-toggle.mjs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/elements/docs/theme-toggle.mjs b/app/elements/docs/theme-toggle.mjs index ecba35d8..99bea43e 100644 --- a/app/elements/docs/theme-toggle.mjs +++ b/app/elements/docs/theme-toggle.mjs @@ -43,8 +43,7 @@ export default function DocsThemeToggle({ html }) {