be-enhanced
Version:
be-enhanced provides a base class that enables casting spells, or enhancing server-rendered DOM elements based on cross-cutting custom attributes
242 lines (201 loc) • 7.67 kB
TypeScript
export interface JSONSerializableMountInit{
readonly on?: CSSMatch,
readonly observedAttrsWhenMounted?: (string | ObservedSourceOfTruthAttribute)[],
readonly whereAttr?: WhereAttr,
readonly whereElementIntersectsWith?: IntersectionObserverInit,
readonly whereMediaMatches?: MediaQuery,
readonly import?: ImportString | [ImportString, ImportAssertions] | PipelineProcessor,
}
export interface ObservedSourceOfTruthAttribute<TProps = any> {
name: string,
mapsTo?: keyof TProps & string,
valIfNull?: any,
valIfFalsy?: any,
instanceOf?: any,
customParser?: (newValue: string | null, oldValue: string | null, instance: Element) => any
}
export type Assigner = (target: any, source: any) => Promise<void> | void;
export interface MountInit extends JSONSerializableMountInit{
readonly withTargetShadowRoot?: ShadowRoot,
readonly whereInstanceOf?: Array<{new(): Element}>,
readonly whereSatisfies?: PipelineProcessor<boolean>,
readonly do?: MountObserverCallbacks,
readonly assigner?: Assigner,
readonly idleTimeout?: number
// /**
// * Purpose -- there are scenarios where we may only want to affect changes that occur after the initial
// * server rendering, so we only want to mount elements that appear
// */
// readonly ignoreInitialMatches?: boolean,
}
export interface MountObserverOptions{
leaveBreadcrumb?: boolean,
}
export interface MountObserverCallbacks{
readonly mount?: PipelineProcessor,
readonly dismount?: PipelineProcessor,
readonly disconnect?: PipelineProcessor,
readonly reconfirm?: PipelineProcessor,
readonly exit?: PipelineProcessor,
}
export interface RootCnfg{
start: string,
context: 'BuiltIn' | 'CustomElement' | 'Both'
}
//export type RootAttrOptions = Array<string | RootCnfg>;
export type delimiter = string;
export interface WhereAttr{
hasBase?: string | [delimiter, string],
hasBranchIn?: Array<string> | [delimiter, Array<string>],
hasRootIn?: Array<RootCnfg>,
/**
* Used by consumers to track the universal meaning of this combination
* regardless of how the actual name values may be changed.
*/
metadata?: any,
}
type CSSMatch = string;
type ImportString = string;
type MediaQuery = string;
export interface AttribMatch{
names: string[],
//for boolean, support true/false/mixed
// type?: 'number' | 'string' | 'date' | 'json-object' | 'boolean',
// valConverter?: (s: string) => any,
// validator?: (v: any) => boolean;
}
export interface WeakDual<T extends Object>{
weakSet: WeakSet<T>,
setWeak: Set<WeakRef<T>>
}
export interface IMountObserver extends EventTarget {
// readonly mountInit: MountInit,
// readonly mountedRefs: WeakRef<Element>[],
// readonly dismountedRefs: WeakRef<Element>[],
observe(within: Node): void;
disconnect(within: Node): void;
module?: any;
mountedElements: WeakDual<Element>;
readAttrs(match: Element, branchIndexes?: Set<number>) : AttrChangeInfo[];
observedAttrs(): Promise<Array<string> | undefined>;
}
export interface MountContext{
stage?: PipelineStage,
initializing?: boolean,
}
type PipelineStage = 'Inspecting' | 'PreImport' | 'PostImport' | 'Import'
export type PipelineProcessor<ReturnType = void> = (matchingElement: Element, observer: IMountObserver, ctx: MountContext) => Promise<ReturnType> | ReturnType;
//#region mutation event
export type mutationEventName = 'mutation-event';
export interface MutationEvent{
mutationRecords: Array<MutationRecord>
}
export type mutationEventHandler = (e: MutationEvent) => void;
export interface AddMutationEventListener {
addEventListener(eventName: mutationEventName, handler: mutationEventHandler, options?: AddEventListenerOptions): void;
}
//#endregion
interface AttrParts{
name: string,
root?: string,
base?: string,
branch?: string,
branchIdx: number,
leaf?: string, //TODO
leafIdx?: number, //TODO
rootCnfg?: RootCnfg,
metadata?: any,
}
interface AttrChangeInfo{
oldValue: string | null,
newValue: string | null,
isSOfTAttr: boolean,
idx?: number,
name: string,
parts?: AttrParts,
mapsTo?: string,
}
//#region mount event
export type mountEventName = 'mount';
export interface IMountEvent extends Event{
mountedElement: Element,
}
export type mountEventHandler = (e: IMountEvent) => void;
export interface AddMountEventListener {
addEventListener(eventName: mountEventName, handler: mountEventHandler, options?: AddEventListenerOptions): void;
}
//#endregion
//#region dismount event
export type dismountEventName = 'dismount';
export interface IDismountEvent {
dismountedElement: Element
}
export type dismountEventHandler = (e: IDismountEvent) => void;
export interface AddDismountEventListener {
addEventListener(eventName: dismountEventName, handler: dismountEventHandler, options?: AddEventListenerOptions): void;
}
//#endregion
//#region disconnected event
export type disconnectedEventName = 'disconnect';
export interface IDisconnectEvent {
disconnectedElement: Element
}
export type disconnectedEventHandler = (e: IDisconnectEvent) => void;
export interface AddDisconnectEventListener {
addEventListener(eventName: disconnectedEventName, handler: disconnectedEventHandler, options?: AddEventListenerOptions): void;
}
//endregion
//#region attribute change event
export type attrChangeEventName = 'attrChange';
export interface IAttrChangeEvent extends IMountEvent {
attrChangeInfos: Array<AttrChangeInfo>,
}
export type attrChangeEventHandler = (e: IAttrChangeEvent) => void;
export interface AddAttrChangeEventListener{
addEventListener(eventName: attrChangeEventName, handler: attrChangeEventHandler, options?: AddEventListenerOptions): void;
}
//#endregion
//#region load event
export type loadEventName = 'load';
export interface ILoadEvent {
clone: DocumentFragment
}
export type loadEventHandler = (e: ILoadEvent) => void;
export interface AddLoadEventListener{
addEventListener(eventName: loadEventName, handler: loadEventHandler, options?: AddEventListenerOptions): void
}
//#endregion
//#region MountObserver Script Element
export interface MOSEAddedProps<TSynConfig=any>{
init: JSONSerializableMountInit;
observer: IMountObserver;
do: MountObserverCallbacks;
synConfig: TSynConfig;
}
export interface MOSE<TSynConfig=any>
extends HTMLScriptElement, MOSEAddedProps<TSynConfig>{
}
export interface BindishOptions{
assigner?: Assigner,
//waitFor?: string,
/**
* If derived from a template, set to true
* to indicate that the initial
*/
csr?: boolean,
ctr?: IshCtr,
initPropVals?: any,
}
//TODO: move to mount observer
export interface HasIsh {
ish: any;
}
export interface Ishcycle{
'<mount>'?(self: Ishcycle, el: Element & HasIsh, options: BindishOptions): Promise<void>;
//'</dismount>'?(self: IshFace, el: Element): Promise<void>;
'<inScope>'?(self: Ishcycle, el: Element & HasIsh, options: BindishOptions): Promise<void>;
'arr=>'?(self: Ishcycle, arr: any[] | undefined, el: Element & HasIsh, options: BindishOptions): Promise<void | any[]>;
//'</outOfScope>'?(self: IshFace, el: Element): Promise<void>;
}
export type IshCtr = ({new() : Ishcycle}) | (() => Promise<{new() : Ishcycle}>);
//#endregion