You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Refactor DarkModeToggle class to extend Component<P> from the component-lifecycle library, delegating lifecycle management (initialization, attachment, disposal, destruction) to the library's state machine. This replaces the manual _destroyed flag with a deterministic, observable lifecycle while preserving the existing public API surface and event system.
Current behavior:DarkModeToggle manages lifecycle via a boolean flag (_destroyed) and explicit destroy() method. Construction immediately initializes and attaches the component.
Target behavior:DarkModeToggle extends Component<"darkmode"> where the constructor calls super(element), then internally invokes this.init() and this.attach(). Lifecycle hooks (doInit(), doAttach(), doDispose(), doDestroy()) encapsulate setup/teardown logic.
Expected Benefits
Standardized lifecycle: Deterministic state machine (idle → initialized → attached ↔ disposed → destroyed) with validation
Observability: Automatic emission of typed lifecycle events (darkmode:initialized, darkmode:attached, darkmode:disposed, darkmode:destroyed) without manual dispatch
Resource management: Clear separation of concerns via hooks ensures proper cleanup and prevents memory leaks
Introspection: Built-in state query methods (isAttached(), isDestroyed(), etc.) replace manual flag checks
Zero regression: Existing public API (toggle(), light(), dark(), setStorageType(), destroy()) unchanged; existing darkmode:change events continue to work alongside new lifecycle events
Acceptance Criteria
DarkModeToggle extends Component<"darkmode"> from component-lifecycle
Static readonly PREFIX property set to "darkmode"
Constructor calls super(element) as first statement, then this.init() and this.attach() internally
doInit() hook contains: StorageManager creation, applyPreferredScheme() (state restoration), and initial state calculation
Short Description of the Feature
Refactor
DarkModeToggleclass to extendComponent<P>from thecomponent-lifecyclelibrary, delegating lifecycle management (initialization, attachment, disposal, destruction) to the library's state machine. This replaces the manual_destroyedflag with a deterministic, observable lifecycle while preserving the existing public API surface and event system.Current behavior:
DarkModeTogglemanages lifecycle via a boolean flag (_destroyed) and explicitdestroy()method. Construction immediately initializes and attaches the component.Target behavior:
DarkModeToggle extends Component<"darkmode">where the constructor callssuper(element), then internally invokesthis.init()andthis.attach(). Lifecycle hooks (doInit(),doAttach(),doDispose(),doDestroy()) encapsulate setup/teardown logic.Expected Benefits
idle→initialized→attached↔disposed→destroyed) with validationdarkmode:initialized,darkmode:attached,darkmode:disposed,darkmode:destroyed) without manual dispatchisAttached(),isDestroyed(), etc.) replace manual flag checkstoggle(),light(),dark(),setStorageType(),destroy()) unchanged; existingdarkmode:changeevents continue to work alongside new lifecycle eventsAcceptance Criteria
DarkModeToggleextendsComponent<"darkmode">fromcomponent-lifecyclePREFIXproperty set to"darkmode"super(element)as first statement, thenthis.init()andthis.attach()internallydoInit()hook contains:StorageManagercreation,applyPreferredScheme()(state restoration), and initial state calculationdoAttach()hook contains:DomManagercreation,EventManagercreation,setupCrossInstanceSync()(global event listener registration), and initialsyncState()doDispose()hook removes global event listeners (handleExternalThemeChange)doDestroy()hook contains currentdestroy()logic:dom.destroy(), property deletion, and any final cleanup_destroyedflag andensureNotDestroyed()method are removed; replaced withisDestroyed()from base classtoggle,light,dark,setStorageType,destroy) continue to work without signature changesdarkmode:changeevents are still dispatched viaEventManager.dispatch()in addition to new lifecycle events[data-plugin="bs-darkmode-toggle"]continues to work (constructor handlesinit()/attach()internally)Documentation
Event Emission Flow
Lifecycle events (automatic from base class):
darkmode:initialized→ emitted afterdoInit()completesdarkmode:attached→ emitted afterdoAttach()completesdarkmode:disposed→ emitted afterdoDispose()completesdarkmode:destroyed→ emitted afterdoDestroy()completesDomain events (preserved existing behavior):
darkmode:change→ still dispatched viaEventManager.dispatch()when theme changes (triggered by user interaction or programmatic methods)Backward compatibility: Existing listeners for
"change"(legacy) and"darkmode:change"continue to work unchanged.See component-lifecycle events doc
State Query Methods (New Capabilities)
These methods from
Componentbecome available without additional implementation:isAttached()isDestroyed()_destroyedflag +ensureNotDestroyed()isDisposed()isInitialized()isIdle()state(getter)LifecycleStateenumSee component-lifecycle lifecycle doc
Public API Compatibility Matrix
toggle(silent?)state.do())light(silent?)dark(silent?)setStorageType(type)destroy()_destroyed=truesuper.destroy()→doDestroy()component-lifecycle API
See component-lifecycle API doc
Additional Comments
Risks & Mitigations
this.init()andthis.attach()inside constructor beforethisis fully initializedcomponent-lifecyclebase class is designed for this pattern; hooks are called after construction completesinit()/attach()manually if exposedcomponent-lifecyclecheck is the transition can be performed,init(),attach(),dispose(),destroy()are idempotentdarkmode:attachedvsdarkmode:change); no overlaphandleExternalThemeChangeregistered indoAttach(), removed indoDispose()_destroyedflag existsisDestroyed()or remove flag assertions; no functional changes requiredDependencies
component-lifecycle(version as specified in user's links)Out of Scope
darkmode:changeevent behavior or payloadFeature Request Checklist