@@ -21,7 +21,7 @@ const portalSelectors = [
2121 '[data-slot="tooltip-content"]' ,
2222 '[data-slot="dropdown-menu-content"]' ,
2323 '[data-slot="context-menu-content"]' ,
24- '[data-slot="menubar-content"]'
24+ '[data-slot="menubar-content"]' ,
2525]
2626
2727// Global set to track experiment portal triggers
@@ -32,22 +32,22 @@ const isInExperimentContext = (element) => {
3232 // Check if the element or its ancestors have experiment-related selectors
3333 const experimentSelectors = [
3434 '#main-app' ,
35- '.device-container' ,
35+ '.device-container' ,
3636 '.fullscreen-container' ,
3737 '.dev-color-mode .device-wrapper' ,
38- '[data-experiment-scope]' // We can add this attribute to experiment containers
38+ '[data-experiment-scope]' , // We can add this attribute to experiment containers
3939 ]
40-
41- return experimentSelectors . some ( selector => {
40+
41+ return experimentSelectors . some ( ( selector ) => {
4242 const container = document . querySelector ( selector )
4343 return container && container . contains ( element )
4444 } )
4545}
4646
4747// Function to apply color mode to experiment-scoped portaled elements only
4848const applyColorModeToExperimentPortals = ( mode ) => {
49- portalSelectors . forEach ( selector => {
50- document . querySelectorAll ( selector ) . forEach ( el => {
49+ portalSelectors . forEach ( ( selector ) => {
50+ document . querySelectorAll ( selector ) . forEach ( ( el ) => {
5151 // Only apply to portaled elements that have a data attribute marking them as experiment-scoped
5252 if ( el . hasAttribute ( 'data-experiment-portal' ) ) {
5353 el . classList . remove ( 'light' , 'dark' )
@@ -62,34 +62,37 @@ const applyColorModeToExperimentPortals = (mode) => {
6262// Set up MutationObserver for dynamically created portaled elements
6363const setupPortalObserver = ( ) => {
6464 if ( portalObserver || typeof window === 'undefined' ) return
65-
65+
6666 portalObserver = new MutationObserver ( ( mutations ) => {
6767 mutations . forEach ( ( mutation ) => {
6868 mutation . addedNodes . forEach ( ( node ) => {
6969 if ( node . nodeType === Node . ELEMENT_NODE ) {
7070 // Check if the added node or any of its descendants match our portal selectors
71- portalSelectors . forEach ( selector => {
71+ portalSelectors . forEach ( ( selector ) => {
7272 const matchingElements = [ ]
73-
73+
7474 if ( node . matches && node . matches ( selector ) ) {
7575 matchingElements . push ( node )
7676 }
7777 // Also check descendants
7878 if ( node . querySelectorAll ) {
7979 matchingElements . push ( ...node . querySelectorAll ( selector ) )
8080 }
81-
82- matchingElements . forEach ( el => {
81+
82+ matchingElements . forEach ( ( el ) => {
8383 // Check if this portal element should be treated as experiment-scoped
8484 // We'll look for triggers within experiment containers
8585 if ( shouldBeExperimentPortal ( el ) ) {
8686 el . setAttribute ( 'data-experiment-portal' , 'true' )
87-
87+
8888 // Apply current experiment color mode
89- const currentMode = experimentColorMode . value === 'auto'
90- ? ( usePreferredDark ( ) . value ? 'dark' : 'light' )
91- : experimentColorMode . value
92-
89+ const currentMode =
90+ experimentColorMode . value === 'auto'
91+ ? usePreferredDark ( ) . value
92+ ? 'dark'
93+ : 'light'
94+ : experimentColorMode . value
95+
9396 el . classList . remove ( 'light' , 'dark' )
9497 if ( currentMode === 'dark' || currentMode === 'light' ) {
9598 el . classList . add ( currentMode )
@@ -101,10 +104,10 @@ const setupPortalObserver = () => {
101104 } )
102105 } )
103106 } )
104-
107+
105108 portalObserver . observe ( document . body , {
106109 childList : true ,
107- subtree : true
110+ subtree : true ,
108111 } )
109112}
110113
@@ -113,7 +116,7 @@ const shouldBeExperimentPortal = (portalElement) => {
113116 // Simple approach: check if any experiment containers exist and have focus/active elements
114117 const experimentContainer = document . querySelector ( '[data-experiment-scope]' )
115118 if ( ! experimentContainer ) return false
116-
119+
117120 // Check if there are any open popover/select triggers within the experiment container
118121 const openTriggers = experimentContainer . querySelectorAll ( '[data-state="open"], [aria-expanded="true"]' )
119122 return openTriggers . length > 0
@@ -122,21 +125,25 @@ const shouldBeExperimentPortal = (portalElement) => {
122125// Setup click tracking to identify experiment-originating portals
123126const setupExperimentPortalTracking = ( ) => {
124127 if ( typeof window === 'undefined' ) return
125-
126- document . addEventListener ( 'click' , ( event ) => {
127- const target = event . target
128- const experimentScope = target . closest ( '[data-experiment-scope]' )
129-
130- if ( experimentScope ) {
131- // Mark this as a potential experiment portal trigger
132- experimentPortalTriggers . add ( target )
133-
134- // Clean up old triggers after a delay
135- setTimeout ( ( ) => {
136- experimentPortalTriggers . delete ( target )
137- } , 1000 )
138- }
139- } , true ) // Use capture phase to catch before portal creation
128+
129+ document . addEventListener (
130+ 'click' ,
131+ ( event ) => {
132+ const target = event . target
133+ const experimentScope = target . closest ( '[data-experiment-scope]' )
134+
135+ if ( experimentScope ) {
136+ // Mark this as a potential experiment portal trigger
137+ experimentPortalTriggers . add ( target )
138+
139+ // Clean up old triggers after a delay
140+ setTimeout ( ( ) => {
141+ experimentPortalTriggers . delete ( target )
142+ } , 1000 )
143+ }
144+ } ,
145+ true
146+ ) // Use capture phase to catch before portal creation
140147}
141148
142149/**
@@ -147,69 +154,77 @@ const setupExperimentPortalTracking = () => {
147154 */
148155export function useSmileColorMode ( scope = 'experiment' , options = { } ) {
149156 const preferredDark = usePreferredDark ( )
150-
157+
151158 // Determine which mode ref to use based on scope
152159 const modeRef = scope === 'global' ? globalColorMode : experimentColorMode
153-
160+
154161 // System computed value
155- const system = computed ( ( ) => preferredDark . value ? 'dark' : 'light' )
156-
162+ const system = computed ( ( ) => ( preferredDark . value ? 'dark' : 'light' ) )
163+
157164 // Actual resolved state (auto -> system preference)
158- const state = computed ( ( ) =>
159- modeRef . value === 'auto' ? system . value : modeRef . value
160- )
161-
165+ const state = computed ( ( ) => ( modeRef . value === 'auto' ? system . value : modeRef . value ) )
166+
162167 // Function to apply color mode to specific selector
163168 const applyColorMode = ( selector , mode ) => {
164169 const el = document . querySelector ( selector )
165170 if ( ! el ) return
166-
171+
167172 // Remove existing mode classes
168173 el . classList . remove ( 'light' , 'dark' )
169-
174+
170175 // Add the new mode class
171176 if ( mode === 'dark' || mode === 'light' ) {
172177 el . classList . add ( mode )
173178 }
174179 }
175-
180+
176181 // Watch for changes and apply to appropriate selectors
177- watch ( state , ( newMode ) => {
178- nextTick ( ( ) => {
179- if ( scope === 'global' ) {
180- // Apply to html element for global theming
181- applyColorMode ( 'html' , newMode )
182- } else if ( scope === 'experiment' ) {
183- // Apply to experiment containers only
184- applyColorMode ( '#main-app' , newMode )
185- applyColorMode ( '.device-container' , newMode )
186- applyColorMode ( '.fullscreen-container' , newMode )
187- applyColorMode ( '.dev-color-mode' , newMode )
188- applyColorMode ( '.device-wrapper' , newMode )
189-
190- // Apply to experiment-scoped portaled UI components and set up observer for new ones
191- applyColorModeToExperimentPortals ( newMode )
192- setupPortalObserver ( )
193- setupExperimentPortalTracking ( )
194- }
195- } )
196- } , { immediate : true } )
197-
182+ watch (
183+ state ,
184+ ( newMode ) => {
185+ nextTick ( ( ) => {
186+ if ( scope === 'global' ) {
187+ // Apply to html element for global theming
188+ applyColorMode ( 'html' , newMode )
189+ } else if ( scope === 'experiment' ) {
190+ // Apply to experiment containers only
191+ applyColorMode ( '#main-app' , newMode )
192+ applyColorMode ( '.device-container' , newMode )
193+ applyColorMode ( '.fullscreen-container' , newMode )
194+ applyColorMode ( '.dev-color-mode' , newMode )
195+ applyColorMode ( '.device-wrapper' , newMode )
196+
197+ // Apply to experiment-scoped portaled UI components and set up observer for new ones
198+ applyColorModeToExperimentPortals ( newMode )
199+ setupPortalObserver ( )
200+ setupExperimentPortalTracking ( )
201+ }
202+ } )
203+ } ,
204+ { immediate : true }
205+ )
206+
198207 return {
199208 // Reactive color mode value (can be 'auto', 'light', or 'dark')
200209 mode : modeRef ,
201-
210+
202211 // System preference
203212 system,
204-
213+
205214 // Resolved state (never 'auto', always 'light' or 'dark')
206215 state,
207-
216+
208217 // Convenience setter functions
209- setLight : ( ) => { modeRef . value = 'light' } ,
210- setDark : ( ) => { modeRef . value = 'dark' } ,
211- setAuto : ( ) => { modeRef . value = 'auto' } ,
212-
218+ setLight : ( ) => {
219+ modeRef . value = 'light'
220+ } ,
221+ setDark : ( ) => {
222+ modeRef . value = 'dark'
223+ } ,
224+ setAuto : ( ) => {
225+ modeRef . value = 'auto'
226+ } ,
227+
213228 // Toggle function
214229 toggle : ( ) => {
215230 if ( modeRef . value === 'auto' ) {
@@ -219,7 +234,7 @@ export function useSmileColorMode(scope = 'experiment', options = {}) {
219234 } else {
220235 modeRef . value = 'auto'
221236 }
222- }
237+ } ,
223238 }
224239}
225240
@@ -243,4 +258,4 @@ export function setColorMode(scope, mode) {
243258 } else {
244259 experimentColorMode . value = mode
245260 }
246- }
261+ }
0 commit comments