UNPKG

@knyt/luthier

Version:

A library for building standardized, type-safe native web components with full SSR and hydration support.

239 lines 9.33 kB
import { type BoundMap, type DOMAttributeValue, type ObjectToFunctionPropertyNames, type Observable, type Reference, type Subscription, type UnwrapRef } from "@knyt/artisan"; import type { PropertyChangePayload, ReactiveControllerHost } from "@knyt/tasker"; import type { PropertiesDefinition, PropertyDefinition, PropertyName, ReactiveProperties, ReactiveProperty } from "./types"; /** * This symbol is used to attach the reactive adapter to an element. * * @remarks * * This symbol must be in the runtime-wide symbol registry * (`Symbol.for`) so that the reactive adapter can be * accessed from within different contexts. * * @internal scope: package */ export declare const __reactiveAdapter: unique symbol; /** * Determines how the reactive adapter will handle updates. * * @internal scope: workspace */ export declare enum ReactiveUpdateMode { /** * Automatically request an update on the host when a property changes. * * @public */ Reactive = "reactive", /** * Does not automatically request an update when a property changes. * However, an event will still be emitted when a property changes. * * @public */ Manual = "manual" } declare enum ReactivePropertyChangeOrigin { /** * The property change originated from a property setter. */ Property = 0, /** * The property change originated from an attribute change. */ Attribute = 1 } /** * An object with reactive properties. */ export type Reactive = { [__reactiveAdapter]: ReactiveAdapter; }; declare enum HookName { Update = "update", UpdateRequest = "updateRequested" } /** * A reactive adapter for managing reactive properties on an element. */ export declare class ReactiveAdapter<Props extends Record<PropertyName, any> = Record<PropertyName, any>> { #private; readonly isPropertyUpdating$: Reference.Readonly<boolean>; constructor({ reactiveProperties, hooks, options, }: { reactiveProperties: ReactiveProperties; hooks?: ReactiveAdapter.Hooks; options?: ReactiveAdapter.Options; }); /** * Get the value of a reactive property. */ getProp<K extends keyof Props>(name: K): Props[K] | undefined; /** * Set the value of a reactive property. */ setProp<K extends keyof Props>(name: K, value: Props[K]): void; /** * Set the values of multiple reactive properties at once. */ setProps(props: Partial<Props>): void; /** * Create an observable that emits property changes */ observePropChange<K extends keyof Props = keyof Props, T extends Props[K] = Props[K]>(): Observable.WithSubscription<PropertyChangePayload<K, T>>; /** * @internal scope: package */ _findPropConfig<K extends keyof Props>(propertyName: K): ReactiveProperty | undefined; /** * Create a reference to a reactive property value. * * @remarks * * This method is used to create a reference to a reactive property value * that will automatically update when the property value changes. */ refProp<K extends keyof Props>(propertyName: K): Reference.WithSubscription<Props[K]>; refProp<K extends keyof Props, T>(propertyName: K, transform: (value: Props[K]) => T): Reference.SubscriberRetaining<T, Props[K]>; refProp<K extends keyof Props>(propertyName: K, fallback: NonNullable<Props[K]> extends (...args: any[]) => any ? never : NonNullable<Props[K]>): Reference.SubscriberRetaining<NonNullable<Props[K]>, Props[K]>; _refPropOnly<K extends keyof Props>(propertyName: K): Reference.WithSubscription<Props[K]>; /** * Subscribe to property changes on the element. * * @beta */ onPropChange<K extends keyof Props>(propertyName: K, callback: (currentValue: Props[K], previousValue: Props[K]) => void): Subscription; onPropChange<K extends keyof Props = keyof Props, T extends Props[K] = Props[K]>(listener: (payload: PropertyChangePayload<K, T>) => void): Subscription; /** * Set a reactive property value from a property setter or an attribute change. */ _setReactivePropertyValue<T extends ReactiveProperty>(changeOrigin: ReactivePropertyChangeOrigin, config: T, nextValue: PropertyDefinition.ToValue<T> | undefined): void; /** * Get a reactive property value. * * @internal scope: package */ _getReactivePropertyValue<T extends ReactiveProperty>(config: T): PropertyDefinition.ToValue<T> | undefined; /** * Retrieves the changed properties since the last call to this method, * and resets the changed properties map. */ _flushChangedProperties(hookName: `${HookName}`): BoundMap.Readonly<any>; /** * Get all reactive property values as an object. * * @remarks * Useful for accessing multiple properties at once. For best type safety, * prefer accessing individual properties directly. * * @public */ getProps(): Props; /** * Set the attribute values from reactive properties that have attribute names. * * @remarks * * While this method can technically be called at any time, it is primarily * intended to be called after the host has been fully constructed. This is * because attributes cannot be set on an element during its construction phase, * and doing so will result in the browser throwing an error. */ syncAttributeValues(): void; /** * Creates a dictionary of attribute names and their corresponding values * based on the reactive properties that have an associated attribute name. */ getAttributeValues(): Record<string, DOMAttributeValue>; /** * Set attribute values on the element using the provided attribute values * using the hooks defined in the constructor. */ setAttributeValues(attributeValues: Record<string, DOMAttributeValue>): void; /** * @internal scope: package */ _setPropertyFromAttributeChange(name: string, _prevAttributeValue: DOMAttributeValue, nextAttributeValue: DOMAttributeValue): void; /** * Creates a reference that maps a property value to a transformed value. * * @deprecated Use `mapRef` instead. */ mapProp<P extends keyof Props, T>(propertyName: P, transform: (value: Props[P]) => T): Reference.SubscriberRetaining<T, Props[P]>; /** * @deprecated Use `unwrapRef` instead. */ unwrapProp<K extends keyof Props>(propertyName: K): Reference.Unwrapped<UnwrapRef<Props[K]> | undefined>; /** * @see https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements */ handleAttributeChanged(name: string, previousValue: DOMAttributeValue, nextValue: DOMAttributeValue): void; } export declare namespace ReactiveAdapter { type Options = { updateMode?: `${ReactiveUpdateMode}`; }; /** * A set of hooks that can be used to interact with the element. * * @remarks * * These hooks are used to interact with the element in a way that is * compatible with the reactive adapter. They are used to perform actions * such as setting attributes, removing attributes, and requesting updates. * * @internal scope: package */ type Hooks = { isConnected?: HTMLElement["isConnected"]; removeAttribute?: HTMLElement["removeAttribute"]; setAttribute?: HTMLElement["setAttribute"]; requestUpdate?: ReactiveControllerHost["requestUpdate"]; }; } /** * Determines whether the input is a {@link ReactiveAdapter}. */ export declare function isReactiveAdapter(value: unknown): value is ReactiveAdapter; /** * Determines whether the input is a {@link Reactive}. */ export declare function isReactive(value: unknown): value is Reactive; /** * Retrieves the reactive adapter from an object. * * @returns The reactive adapter if the object is reactive, * otherwise `undefined`. * * @internal scope: package */ export declare function getReactiveAdapter(value: unknown): ReactiveAdapter | undefined; /** * Assert that the object is a {@link Reactive}. */ export declare function assertReactive(value: unknown): asserts value is Reactive; /** * Defines reactive properties on a given object. */ export declare function makeReactive<T extends object, B>(targetObj: T, properties: PropertiesDefinition<B>): ReactiveProperties; /** * Adds reactivity to an instance of a class. * * @remarks * * Although the function works on class instances, it modifies the prototype of the class. * The prototype is modified only once, so all instances of the class will have the same reactive properties. * The trade-off is miniscule overhead to check if the prototype has already been modified * on each instance creation. */ export declare function withReactivity<T extends object, P>({ instance, properties, hooks, options, }: { instance: T; properties: PropertiesDefinition<P>; hooks?: ReactiveAdapter.Hooks; options?: ReactiveAdapter.Options; }): void; type MixableMemberName = ObjectToFunctionPropertyNames<ReactiveAdapter>; export declare function applyReactiveMixin<T extends { prototype: object; }>(Constructor: T, members?: MixableMemberName[]): void; export {}; //# sourceMappingURL=Reactive.d.ts.map