Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for contexts? #1182

Closed
mcjazzyfunky opened this issue Apr 2, 2021 · 2 comments
Closed

Support for contexts? #1182

mcjazzyfunky opened this issue Apr 2, 2021 · 2 comments

Comments

@mcjazzyfunky
Copy link

mcjazzyfunky commented Apr 2, 2021

Remark: I haven't found a lot of conversation about "context support in lit-element" - just #46 and this seems quite old.

Description

If you develop a non-trivial component suite with React, very often it's necessary that you not just export the components themselves but also the context objects that are needed for those components (at least if you do not wrap all those context objects in custom hooks and special components). Means: Those context objects are a very important part of your published component suite.

Any plans/chance that lit-element will provide out-of-the-box support for contexts in near future too?
Of course, something like this is doable in userland, but then everybody has her own solution and for each solution you may need some special adapters or whatever, which would be (and actually currently is) quite annoying. A de facto standard would be much, much, much, much better.

Of course the base context API should be framework agnostic, so that the core types/interfaces of that context API could also be used outside of the lit-element world.

Frankly, I currently have no idea whether such a context API could be implemented performant for SSR.

If this topic may be of interest please find here some more details

// One of many possible context APIs

// framework agnostic
// maybe an additional readonly property `uuid` would also be useful
type Context<T> = {
  readonly kind: 'context',
  readonly defaultValue: T
}

// framwork agnostic
function createContext<T>(defaultValue: T): Context<T> {
  return Object.freeze({
    kind: 'context',
    defaultValue
  })
}

// framework agnostic
function createProvider<T>(): CustomElementConstructor {
  ....
}

// Here just for example a @context decorator to handle the
// context value injections. Of course this could be also handled
// in a completely different non-decorator-based way.
// More infos about that decorator will follow in the example below.
// Not framework agnostic!
function context(...) { ... }

/*************************************
 * Here's a little example           *
 *************************************/

enum Theme {
  Light = 'light',
  Dark = 'dark'
}

const ThemeCtx = createContext(Theme.Light)
const ThemeProvider = createProvider(ThemeCtx)

customElements.define('theme-provider', ThemeProvider)

@customElement('theme-info')
class ThemeInfo extends LitElement {
  @context(ThemeCtx)
  private theme = ThemeCtx.defaultValue
  
  render() {
    return html`<div>Current theme: ${this.theme}</div>`
  }
}

const output = html`
  <theme-provider .value=${Theme.Dark}>
    <h3>Context demo</h3>
    <theme-info></theme-info>
  </theme-provider>
`

Find here some remarks on how the context API of the web component library `haunted` could be transferred to a framework agnostic API


Please find here the important parts of the context API in `haunted`: Link

The most important part is this (please be aware that nothing is framework agnostic here):

const contextEvent = 'haunted.context';

interface Context<T> {
  Provider: ComponentConstructor<{}>;
  Consumer: ComponentConstructor<ConsumerProps<T>>;
  defaultValue: T;
}

interface ContextDetail<T> {
  Context: Context<T>;
  callback: (value: T) => void;

  // These properties will not exist if a context consumer lacks a provider
  value: T;
  unsubscribe?: (this: Context<T>) => void;
}

A framework agnostic variant of that could for example look as follows:

const contextEvent = 'component.context';

type Context<T> = {
  readonly kind: 'context',
  readonly defaultValue: T
}

type ContextDetail<T> = {
  readonly context: Context<T>
  readonly callback: (newValue: T) => void
  readonly cancelled: Promise<null>
}

Acceptance criteria

  • Core context API (=> types/interfaces + description how underlying event handling should work) must be framework agnostic - no need to share a concrete implementation
  • Should work fine and performant with SSR
@thepassle
Copy link

There's been a bunch of discussion on context here

@sorvell
Copy link
Member

sorvell commented Jan 15, 2022

Closing this issue since there's an active PR where this is being developed and refined. Please feel free to kick the tires on that and post feedback. Thanks!

@sorvell sorvell closed this as completed Jan 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants