@knyt/luthier
Version:
A library for building standardized, type-safe native web components with full SSR and hydration support.
239 lines • 9.33 kB
TypeScript
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