Last active
November 11, 2021 20:26
-
-
Save hunterloftis/07e74dcd5caffe3a78eb3e5814d49f08 to your computer and use it in GitHub Desktop.
This file contains 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
import { ReactiveController, LitElement } from 'Lit'; | |
/* | |
class Component extends LitElement { | |
bounds = new BoundsControllerBasic(this); | |
render() { | |
// use this.bounds.width, this.bounds.height | |
} | |
updated(changedProps) { | |
// no way to know whether or not dimensions were changed in this update; | |
// the controller reduces component-author flexibility relative to states and properties. | |
} | |
} | |
*/ | |
export class BoundsControllerBasic implements ReactiveController { | |
public width = 0; | |
public height = 0; | |
protected host: LitElement; | |
protected observer: ResizeObserver; | |
constructor(host: LitElement) { | |
this.host = host; | |
this.observer = new ResizeObserver(() => this.updateDimensions()); | |
host.addController(this); | |
} | |
public hostConnected(): void { | |
this.observer.observe(this.host); | |
} | |
public hostDisconnected(): void { | |
this.observer.unobserve(this.host); | |
} | |
protected updateDimensions(): void { | |
const { width, height } = this.host.getBoundingClientRect(); | |
this.width = width; | |
this.height = height; | |
this.host.requestUpdate(); | |
} | |
} | |
/* | |
class Component extends LitElement { | |
bounds = new BoundsControllerCallback(this, () => this.onResize); | |
render() { | |
// use this.bounds.width, this.bounds.height | |
} | |
onResize() { | |
// we know a resize happened | |
// but we're adding extra lifecycle callbacks alongside built-in Lit stuff | |
// and it doesn't seem idiomatic. | |
// In order to re-render we must either set a state/property or call requestUpdate() | |
} | |
} | |
*/ | |
export class BoundsControllerCallback implements ReactiveController { | |
public width = 0; | |
public height = 0; | |
protected host: LitElement; | |
protected observer: ResizeObserver; | |
protected callback: Function; | |
constructor(host: LitElement, callback: Function) { | |
this.host = host; | |
this.observer = new ResizeObserver(() => this.updateDimensions()); | |
this.callback = callback ?? host.requestUpdate; | |
host.addController(this); | |
} | |
public hostConnected(): void { | |
this.observer.observe(this.host); | |
} | |
public hostDisconnected(): void { | |
this.observer.unobserve(this.host); | |
} | |
protected updateDimensions(): void { | |
const { width, height } = this.host.getBoundingClientRect(); | |
this.width = width; | |
this.height = height; | |
this.callback(); | |
} | |
} | |
/* | |
class Component extends LitElement { | |
bounds = new BoundsControllerEvents(this); | |
constructor() { | |
super(); | |
this.bounds.addEventListener('resize', () => this.onResize()); | |
} | |
render() { | |
// use this.bounds.width, this.bounds.height | |
} | |
onResize() { | |
// we know a resize happened | |
// but we're adding boilerplate to listen to the resize event | |
// and it doesn't seem idiomatic. | |
// In order to re-render we must either set a state/property or call requestUpdate() | |
} | |
} | |
*/ | |
export class BoundsControllerEvents | |
extends EventTarget | |
implements ReactiveController { | |
public width = 0; | |
public height = 0; | |
protected host: LitElement; | |
protected observer: ResizeObserver; | |
constructor(host: LitElement) { | |
super(); | |
this.host = host; | |
this.observer = new ResizeObserver(() => this.updateDimensions()); | |
host.addController(this); | |
} | |
public hostConnected(): void { | |
this.observer.observe(this.host); | |
} | |
public hostDisconnected(): void { | |
this.observer.unobserve(this.host); | |
} | |
protected updateDimensions(): void { | |
const { width, height } = this.host.getBoundingClientRect(); | |
this.width = width; | |
this.height = height; | |
this.dispatchEvent(new CustomEvent('resize')); | |
} | |
} | |
/* | |
class Component extends LitElement { | |
bounds = new BoundsControllerString(this, 'bounds'); | |
render() { | |
// use this.bounds.width, this.bounds.height | |
} | |
updated(changedProps) { | |
if (changedProps.has(this.bounds.key)) { | |
// we can respond specifically to BoundsController changes now, | |
// in a way that feels aligned with property and state changes. | |
// but we're pushing responsiblity for choosing a unique key onto the user. | |
} | |
} | |
} | |
*/ | |
export class BoundsControllerString implements ReactiveController { | |
public width = 0; | |
public height = 0; | |
public key: string; | |
protected host: LitElement; | |
protected observer: ResizeObserver; | |
constructor(host: LitElement, key: string) { | |
this.host = host; | |
this.key = key; | |
this.observer = new ResizeObserver(() => this.updateDimensions()); | |
host.addController(this); | |
} | |
public hostConnected(): void { | |
this.observer.observe(this.host); | |
} | |
public hostDisconnected(): void { | |
this.observer.unobserve(this.host); | |
} | |
protected updateDimensions(): void { | |
const { width, height } = this.host.getBoundingClientRect(); | |
const previous = (({ width, height }) => ({ width, height }))(this); | |
this.width = width; | |
this.height = height; | |
this.host.requestUpdate(this.key, previous); | |
} | |
} | |
/* | |
class Component extends LitElement { | |
bounds = new BoundsControllerSymbol(this); | |
render() { | |
// use this.bounds.width, this.bounds.height | |
} | |
updated(changedProps) { | |
if (changedProps.has(this.bounds.key)) { | |
// we can respond specifically to BoundsController changes now, | |
// in a way that feels aligned with property and state changes. | |
const prev = changedProps.get(this.bounds.key); | |
console.log('resized from', prev.width, prev.height, 'to', this.bounds.width, this.bounds.height); | |
} | |
} | |
} | |
*/ | |
export class BoundsControllerSymbol implements ReactiveController { | |
public key = Symbol('bounds-key'); | |
public width = 0; | |
public height = 0; | |
protected host: LitElement; | |
protected observer: ResizeObserver; | |
constructor(host: LitElement) { | |
this.host = host; | |
this.observer = new ResizeObserver(() => this.updateDimensions()); | |
host.addController(this); | |
} | |
public hostConnected(): void { | |
this.observer.observe(this.host); | |
} | |
public hostDisconnected(): void { | |
this.observer.unobserve(this.host); | |
} | |
protected updateDimensions(): void { | |
const { width, height } = this.host.getBoundingClientRect(); | |
const previous = (({ width, height }) => ({ width, height }))(this); | |
this.width = width; | |
this.height = height; | |
this.host.requestUpdate(this.key, previous); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment