npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@lit/context

v1.1.3

Published

Helpers and controllers for using Context protocol

Downloads

229,397

Readme

@lit/context

Overview

This module defines an implementation of controllers and decorators for using the Context Protocol as defined by the Web Components Community Group.

This protocol facilitates the communication between components lower in the DOM hierarchy with their ancestors, allowing data to be passed down the tree without having to be passed via 'prop drilling' where each element in the path passes on the data.

For further explanation of the Context Protocol please see the community protocol documentation.

Usage

There are several different usages of the Context API.

Creating a Context

First lets define a context key we can use elsewhere in our examples:

logger.ts:

import {createContext} from '@lit/context';

export interface Logger {
  log: (msg: string) => void;
}

export const loggerContext = createContext<Logger>('logger');

Consuming a Context

Now we can define a consumer for this context - some component in our app needs the logger.

Here we're using the @consume property decorator to make a ContextConsumer controller and update its value when the context changes:

my-element.ts:

import {LitElement, property} from 'lit';
import {consume} from '@lit/context';
import {Logger, loggerContext} from './logger.js';

export class MyElement extends LitElement {
  @consume({context: loggerContext, subscribe: true})
  @property({attribute: false})
  public logger?: Logger;

  private doThing() {
    this.logger?.log('a thing was done');
  }
}

Another way we can use a context in a component is via the ContextConsumer controller directly:

my-element.ts:

import {LitElement, property} from 'lit';
import {ContextConsumer} from '@lit/context';
import {Logger, loggerContext} from './logger.js';

export class MyElement extends LitElement {
  public logger = new ContextConsumer(
    this,
    loggerContext,
    undefined, // don't need to pass a callback
    true // pass true to get updates if the logger changes
  );

  private doThing() {
    this.logger.value?.log('a thing was done');
  }
}

Providing a Context

Finally we want to be able to provide this context from somewhere higher in the DOM.

Here we're using a @provide property decorator to make a ContextProvider controller and update its value when the property value changes.

my-app.ts:

import {LitElement, property, html} from 'lit';
import {provide} from '@lit/context';
import {loggerContext, Logger} from './logger.js';

export class MyApp extends LitElement {
  @provide({context: loggerContext})
  @property({attribute: false})
  public logger: Logger = {
    log: (msg) => {
      console.log(`[my-app] ${msg}`);
    },
  };

  protected render(): TemplateResult {
    return html`<my-thing></my-thing>`;
  }
}

We can also use the ContextProvider controller directly:

my-app.ts:

import {LitElement, html} from 'lit';
import {ContextProvider} from '@lit/context';
import {loggerContext, Logger} from './logger.js';

export class MyApp extends LitElement {
  // create a provider controller and a default logger
  private provider = new ContextProvider(this, loggerContext, {
    log: (msg) => {
      console.log(`[my-app] ${msg}`);
    },
  });

  protected render(): TemplateResult {
    return html`<my-thing></my-thing>`;
  }

  public setLogger(newLogger: Logger) {
    // update the provider with a new logger value
    this.provider.setValue(newLogger);
  }
}

ContextProvider can also be used with plain HTML elements. This can be useful to provide a context provider without introducing a custom element:

my-app.js:

import {ContextProvider} from '@lit/context';
import {loggerContext, Logger} from './logger.js';

// create a provider for the whole document body.
const loggingProvider = new ContextProvider(document.body, {
    context: loggerContext,
    initialValue: {
      log: (msg) => {
        console.log(`[global] ${msg}`);
      },
    },
);

If the provider is being added when there is already a consumer registered with a parent of the specified element or with a ContextRoot, then .hostConnected() must be called on the provider after creating it. This ensures existing downstream consumers will now get their context values from the closest parent provider.

Known Issues

Late upgraded Context Providers

In some cases you might have a context providing element that is upgraded late. LightDOM content below this provider may end up requesting a context that is currently not provided by any provider.

To solve this case we provide a ContextRoot class which can intercept and track unsatisfied context-request events and then redispatch these requests when providers are updated.

Example usage:

index.ts:

import {ContextRoot} from '@lit/context';
const root = new ContextRoot();
root.attach(document.body);

The ContextRoot can be attached to any element and it will gather a list of any context requests which are received at the attached element. The ContextProvider controllers will emit context-provider events when they are connected to the DOM. These events act as triggers for the ContextRoot to redispatch these context-request events from their sources.

This solution has a small overhead, in that if a provider is not within the DOM hierarchy of the unsatisfied requests we are unnecessarily refiring these requests, but this approach is safest and most correct in that it is very hard to manage unstable DOM hierarchies with the semantics of slotting and reparenting that is common in web components implementations.

Note that ContextRoot uses WeakRefs which are not supported in IE11.

Protected / Private Properties

You can use the @consume and @provide decorators on TypeScript protected and private properties, but be aware that there is no type checking between the type of the context and the type of the property. This is because the TypeScript compiler does not make type information for protected or private properties available to decorators. Standard #private properties are not supported at all.

We expect to fix all of this when we switch to standard decorators. See #3926.

Contributing

Please see CONTRIBUTING.md.