From 02417d893c34121a7e29ab3a04b1c5328ece38bf Mon Sep 17 00:00:00 2001
From: infogulch
Date: Wed, 4 Oct 2023 14:12:36 -0500
Subject: [PATCH 1/4] Twiddle regex; only support me; attr-based scoping
---
script.js | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/script.js b/script.js
index 89b0ceb..2f7bceb 100644
--- a/script.js
+++ b/script.js
@@ -1,15 +1,14 @@
// 🌘 CSS Scope Inline (https://github.com/gnat/css-scope-inline)
-window.cssScopeCount ??= 1 // Let extra copies share the scope count.
+window.cssScopeCount ??= 1 // Let other scripts read the scope count.
window.cssScope ??= new MutationObserver(mutations => { // Allow 1 observer.
- document?.body?.querySelectorAll('style:not([ready])').forEach(node => { // Faster than walking MutationObserver results when recieving subtree (DOM swap, htmx, ajax, jquery).
- var scope = 'me__'+(window.cssScopeCount++) // Ready. Make unique scope, example: .me__1234
- node.parentNode.classList.add(scope)
+ document?.body?.querySelectorAll('style:not([scoped-to])').forEach(node => { // Faster than walking MutationObserver results when recieving subtree (DOM swap, htmx, ajax, jquery).
+ node.parentNode.dataset.cssScope ??= (window.cssScopeCount++)
node.textContent = node.textContent
- .replace(/(?:^|\.|(\s|[^a-zA-Z0-9\-\_]))(me|this|self)(?![a-zA-Z])/g, '$1.'+scope) // Can use: me this self
- .replace(/((@keyframes|animation:|animation-name:)[^{};]*)\.me__/g, '$1me__') // Optional. Removes need to escape names using \
- .replace(/(?:@media)\s(xs-|sm-|md-|lg-|xl-|sm|md|lg|xl|xx)/g, // Optional. Responsive design. Mobile First (above breakpoint): 🟢 None sm md lg xl xx 🏁 Desktop First (below breakpoint): 🏁 xs- sm- md- lg- xl- None 🟢 *- matches must be first!
+ .replace(/(^|[^-\w])me(?![-\w])/g, `$1[data-css-scope='${node.parentNode.dataset.cssScope}']`)
+ .replace(/((@keyframes\s|animation:|animation-name:)[^{};]*)\bme(?![A-Za-z])/g, `$1css-scope-${node.parentNode.dataset.cssScope}`)
+ .replace(/(?:@media)\s+(xs-|sm-|md-|lg-|xl-|sm|md|lg|xl|xx)(?![-\w])/g, // Optional responsive design shorthand for @media breakpoints. Mobile First (above breakpoint): 🟢 None sm md lg xl xx 🏁 Desktop First (below breakpoint): 🏁 xs- sm- md- lg- xl- None 🟢
(match, part1) => { return '@media '+({'sm':'(min-width: 640px)','md':'(min-width: 768px)', 'lg':'(min-width: 1024px)', 'xl':'(min-width: 1280px)', 'xx':'(min-width: 1536px)', 'xs-':'(max-width: 639px)', 'sm-':'(max-width: 767px)', 'md-':'(max-width: 1023px)', 'lg-':'(max-width: 1279px)', 'xl-':'(max-width: 1535px)'}[part1]) }
)
- node.setAttribute('ready', '')
+ node.setAttribute('scoped-to', node.parentNode.dataset.cssScope)
})
}).observe(document.documentElement, {childList: true, subtree: true})
From c25450172ded3270e41ad2b9e9cf46351a5a0da0 Mon Sep 17 00:00:00 2001
From: infogulch
Date: Wed, 4 Oct 2023 14:12:55 -0500
Subject: [PATCH 2/4] Adjust replace order
---
script.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/script.js b/script.js
index 2f7bceb..7700737 100644
--- a/script.js
+++ b/script.js
@@ -4,8 +4,8 @@ window.cssScope ??= new MutationObserver(mutations => { // Allow 1 observer.
document?.body?.querySelectorAll('style:not([scoped-to])').forEach(node => { // Faster than walking MutationObserver results when recieving subtree (DOM swap, htmx, ajax, jquery).
node.parentNode.dataset.cssScope ??= (window.cssScopeCount++)
node.textContent = node.textContent
- .replace(/(^|[^-\w])me(?![-\w])/g, `$1[data-css-scope='${node.parentNode.dataset.cssScope}']`)
.replace(/((@keyframes\s|animation:|animation-name:)[^{};]*)\bme(?![A-Za-z])/g, `$1css-scope-${node.parentNode.dataset.cssScope}`)
+ .replace(/(^|[^-\w])me(?![-\w])/g, `$1[data-css-scope='${node.parentNode.dataset.cssScope}']`)
.replace(/(?:@media)\s+(xs-|sm-|md-|lg-|xl-|sm|md|lg|xl|xx)(?![-\w])/g, // Optional responsive design shorthand for @media breakpoints. Mobile First (above breakpoint): 🟢 None sm md lg xl xx 🏁 Desktop First (below breakpoint): 🏁 xs- sm- md- lg- xl- None 🟢
(match, part1) => { return '@media '+({'sm':'(min-width: 640px)','md':'(min-width: 768px)', 'lg':'(min-width: 1024px)', 'xl':'(min-width: 1280px)', 'xx':'(min-width: 1536px)', 'xs-':'(max-width: 639px)', 'sm-':'(max-width: 767px)', 'md-':'(max-width: 1023px)', 'lg-':'(max-width: 1279px)', 'xl-':'(max-width: 1535px)'}[part1]) }
)
From 8049ee2b62725a8ae26353d638f295a800e767b0 Mon Sep 17 00:00:00 2001
From: infogulch
Date: Wed, 4 Oct 2023 14:25:41 -0500
Subject: [PATCH 3/4] Combine child and parent css scope attribute assignments
---
script.js | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/script.js b/script.js
index 7700737..b2c52c7 100644
--- a/script.js
+++ b/script.js
@@ -1,14 +1,13 @@
// 🌘 CSS Scope Inline (https://github.com/gnat/css-scope-inline)
window.cssScopeCount ??= 1 // Let other scripts read the scope count.
window.cssScope ??= new MutationObserver(mutations => { // Allow 1 observer.
- document?.body?.querySelectorAll('style:not([scoped-to])').forEach(node => { // Faster than walking MutationObserver results when recieving subtree (DOM swap, htmx, ajax, jquery).
- node.parentNode.dataset.cssScope ??= (window.cssScopeCount++)
+ document?.body?.querySelectorAll('style:not([data-css-scope])').forEach(node => { // Faster than walking MutationObserver results when recieving subtree (DOM swap, htmx, ajax, jquery).
+ node.dataset.cssScope = node.parentNode.dataset.cssScope ??= (window.cssScopeCount++)
node.textContent = node.textContent
.replace(/((@keyframes\s|animation:|animation-name:)[^{};]*)\bme(?![A-Za-z])/g, `$1css-scope-${node.parentNode.dataset.cssScope}`)
.replace(/(^|[^-\w])me(?![-\w])/g, `$1[data-css-scope='${node.parentNode.dataset.cssScope}']`)
.replace(/(?:@media)\s+(xs-|sm-|md-|lg-|xl-|sm|md|lg|xl|xx)(?![-\w])/g, // Optional responsive design shorthand for @media breakpoints. Mobile First (above breakpoint): 🟢 None sm md lg xl xx 🏁 Desktop First (below breakpoint): 🏁 xs- sm- md- lg- xl- None 🟢
(match, part1) => { return '@media '+({'sm':'(min-width: 640px)','md':'(min-width: 768px)', 'lg':'(min-width: 1024px)', 'xl':'(min-width: 1280px)', 'xx':'(min-width: 1536px)', 'xs-':'(max-width: 639px)', 'sm-':'(max-width: 767px)', 'md-':'(max-width: 1023px)', 'lg-':'(max-width: 1279px)', 'xl-':'(max-width: 1535px)'}[part1]) }
)
- node.setAttribute('scoped-to', node.parentNode.dataset.cssScope)
})
}).observe(document.documentElement, {childList: true, subtree: true})
From 2060ca7008a620dbcb3141a4d61b0c0fbf47ab77 Mon Sep 17 00:00:00 2001
From: infogulch
Date: Wed, 4 Oct 2023 20:16:25 -0500
Subject: [PATCH 4/4] Give style node a different dataset node to avoid styles
applying to itself
---
example.html | 4 ++--
script.js | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/example.html b/example.html
index 7b71fce..3680840 100644
--- a/example.html
+++ b/example.html
@@ -2,8 +2,8 @@
🌘 CSS Scope Inline Test Page
-
-
+
+
*,*::before,*::after { margin: 0; box-sizing: border-box; } /* Reset */
diff --git a/script.js b/script.js
index b2c52c7..c29ecfa 100644
--- a/script.js
+++ b/script.js
@@ -1,8 +1,8 @@
// 🌘 CSS Scope Inline (https://github.com/gnat/css-scope-inline)
window.cssScopeCount ??= 1 // Let other scripts read the scope count.
window.cssScope ??= new MutationObserver(mutations => { // Allow 1 observer.
- document?.body?.querySelectorAll('style:not([data-css-scope])').forEach(node => { // Faster than walking MutationObserver results when recieving subtree (DOM swap, htmx, ajax, jquery).
- node.dataset.cssScope = node.parentNode.dataset.cssScope ??= (window.cssScopeCount++)
+ document?.body?.querySelectorAll('style:not([data-css-scoped])').forEach(node => { // Faster than walking MutationObserver results when recieving subtree (DOM swap, htmx, ajax, jquery).
+ node.dataset.cssScoped = node.parentNode.dataset.cssScope ??= (window.cssScopeCount++)
node.textContent = node.textContent
.replace(/((@keyframes\s|animation:|animation-name:)[^{};]*)\bme(?![A-Za-z])/g, `$1css-scope-${node.parentNode.dataset.cssScope}`)
.replace(/(^|[^-\w])me(?![-\w])/g, `$1[data-css-scope='${node.parentNode.dataset.cssScope}']`)