|
| 1 | +// Copied from https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md#definitions |
| 2 | +// at 43f8158a75446af25164ff35d1a6b4f9e96e9d36 |
| 3 | + |
| 4 | +/** |
| 5 | + * A context key. |
| 6 | + * |
| 7 | + * A context key can be any type of object, including strings and symbols. The |
| 8 | + * Context type brands the key type with the `__context__` property that |
| 9 | + * carries the type of the value the context references. |
| 10 | + */ |
| 11 | +export type Context<KeyType, ValueType> = KeyType & {__context__: ValueType}; |
| 12 | + |
| 13 | +/** |
| 14 | + * An unknown context type |
| 15 | + */ |
| 16 | +export type UnknownContext = Context<unknown, unknown>; |
| 17 | + |
| 18 | +/** |
| 19 | + * A helper type which can extract a Context value type from a Context type |
| 20 | + */ |
| 21 | +export type ContextType<T extends UnknownContext> = |
| 22 | + // eslint-disable-next-line @typescript-eslint/no-unused-vars |
| 23 | + T extends Context<infer _, infer V> ? V : never; |
| 24 | + |
| 25 | +/** |
| 26 | + * A function which creates a Context value object |
| 27 | + */ |
| 28 | +export const createContext = <ValueType>(key: unknown) => |
| 29 | + key as Context<typeof key, ValueType>; |
| 30 | + |
| 31 | +/** |
| 32 | + * A callback which is provided by a context requester and is called with the value satisfying the request. |
| 33 | + * This callback can be called multiple times by context providers as the requested value is changed. |
| 34 | + */ |
| 35 | +export type ContextCallback<ValueType> = ( |
| 36 | + value: ValueType, |
| 37 | + unsubscribe?: () => void |
| 38 | +) => void; |
| 39 | + |
| 40 | +/** |
| 41 | + * An event fired by a context requester to signal it desires a named context. |
| 42 | + * |
| 43 | + * A provider should inspect the `context` property of the event to determine if it has a value that can |
| 44 | + * satisfy the request, calling the `callback` with the requested value if so. |
| 45 | + * |
| 46 | + * If the requested context event contains a truthy `subscribe` value, then a provider can call the callback |
| 47 | + * multiple times if the value is changed, if this is the case the provider should pass an `unsubscribe` |
| 48 | + * function to the callback which requesters can invoke to indicate they no longer wish to receive these updates. |
| 49 | + */ |
| 50 | +export class ContextRequestEvent<T extends UnknownContext> extends Event { |
| 51 | + public constructor( |
| 52 | + public readonly context: T, |
| 53 | + public readonly callback: ContextCallback<ContextType<T>>, |
| 54 | + public readonly subscribe?: boolean |
| 55 | + ) { |
| 56 | + super('context-request', {bubbles: true, composed: true}); |
| 57 | + } |
| 58 | +} |
| 59 | + |
| 60 | +declare global { |
| 61 | + interface HTMLElementEventMap { |
| 62 | + /** |
| 63 | + * A 'context-request' event can be emitted by any element which desires |
| 64 | + * a context value to be injected by an external provider. |
| 65 | + */ |
| 66 | + 'context-request': ContextRequestEvent<Context<unknown, unknown>>; |
| 67 | + } |
| 68 | +} |
0 commit comments