Created
June 18, 2024 21:56
-
-
Save theacodes/c156b0402605183e67557a875ee2b344 to your computer and use it in GitHub Desktop.
Lit attachController directive
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2024 Opulo, Inc | |
* Published under the Mozilla Public License | |
* Full text available at: https://www.mozilla.org/en-US/MPL/ | |
*/ | |
import { isFunction } from "@glimmer/common/types"; | |
import { | |
AsyncDirective, | |
LitElement, | |
PartType, | |
directive, | |
noChange, | |
type ElementPart, | |
type PartInfo, | |
type ReactiveController, | |
} from "./aliases"; | |
type ReactiveControllerFactory = (host: LitElement) => ReactiveController; | |
/** | |
* A directive that adds a ReactiveController to the given element. | |
* | |
* This is based on a pattern observed in some Lit directives, such as @lit-labs/animate, where the directive is | |
* also a controller. This is a generalization of that. | |
* | |
* @example | |
* ```ts | |
* html`<div ${attachController((host) => { new MyController(host) })}></div> | |
* ``` | |
* | |
* Note that the argument can either be a factory function or a `ReactiveController` instance. If it's an instance, it | |
* will automatically be added to host. If not, it expects that the factory function or controller constructor will | |
* call `host.addController`. | |
*/ | |
export const attachController = directive( | |
class ControllerDirective extends AsyncDirective { | |
part?: ElementPart; | |
host?: LitElement | null; | |
controller?: ReactiveController | null; | |
constructor(partInfo: PartInfo) { | |
super(partInfo); | |
if (partInfo.type != PartType.ELEMENT) { | |
throw new Error("The `attachController` directive must be used inside the element"); | |
} | |
} | |
render(_controller: ReactiveController | ReactiveControllerFactory) { | |
return noChange; | |
} | |
override update(part: ElementPart, [controller]: Parameters<this["render"]>) { | |
if (this.part === undefined) { | |
this.part = part; | |
} | |
this._attach(controller); | |
this.render(controller); | |
} | |
_attach(controller: ReactiveController | ReactiveControllerFactory) { | |
if (this.part && !this.host) { | |
this.host = this.part.element as LitElement; | |
} | |
if (this.host && !this.controller) { | |
if (isFunction(controller)) { | |
this.controller = controller(this.host); | |
} else { | |
this.controller = controller; | |
this.host.addController(this.controller); | |
} | |
} | |
} | |
override disconnected() { | |
this.host = null; | |
this.controller = null; | |
} | |
override reconnected() {} | |
}, | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment