Teact: Support ref function, update types; TeactN: Support detaching containers
This commit is contained in:
parent
694529ebde
commit
abd92f2ae8
@ -108,7 +108,7 @@ function renderWithVirtual<T extends VirtualElement | undefined>(
|
|||||||
if (!$current && $new) {
|
if (!$current && $new) {
|
||||||
if (isNewComponent || isNewFragment) {
|
if (isNewComponent || isNewFragment) {
|
||||||
if (isNewComponent) {
|
if (isNewComponent) {
|
||||||
$new = initComponent(parentEl, $new as VirtualElementComponent, $parent, index) as typeof $new;
|
$new = initComponent(parentEl, $new as VirtualElementComponent, $parent, index) as unknown as typeof $new;
|
||||||
}
|
}
|
||||||
|
|
||||||
mountChildren(parentEl, $new as VirtualElementComponent | VirtualElementFragment, { nextSibling, fragment });
|
mountChildren(parentEl, $new as VirtualElementComponent | VirtualElementFragment, { nextSibling, fragment });
|
||||||
@ -127,7 +127,7 @@ function renderWithVirtual<T extends VirtualElement | undefined>(
|
|||||||
|
|
||||||
if (isNewComponent || isNewFragment) {
|
if (isNewComponent || isNewFragment) {
|
||||||
if (isNewComponent) {
|
if (isNewComponent) {
|
||||||
$new = initComponent(parentEl, $new as VirtualElementComponent, $parent, index) as typeof $new;
|
$new = initComponent(parentEl, $new as VirtualElementComponent, $parent, index) as unknown as typeof $new;
|
||||||
}
|
}
|
||||||
|
|
||||||
remount(parentEl, $current, undefined);
|
remount(parentEl, $current, undefined);
|
||||||
@ -262,6 +262,8 @@ function createNode($element: VirtualElementReal): Node {
|
|||||||
|
|
||||||
if (typeof props.ref === 'object') {
|
if (typeof props.ref === 'object') {
|
||||||
props.ref.current = element;
|
props.ref.current = element;
|
||||||
|
} else if (typeof props.ref === 'function') {
|
||||||
|
props.ref(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
processControlled(tag, props);
|
processControlled(tag, props);
|
||||||
@ -557,7 +559,20 @@ function processControlled(tag: string, props: AnyLiteral) {
|
|||||||
onChange?.(e);
|
onChange?.(e);
|
||||||
|
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
e.currentTarget.value = value;
|
const { selectionStart, selectionEnd } = e.currentTarget;
|
||||||
|
|
||||||
|
if (e.currentTarget.value !== value) {
|
||||||
|
e.currentTarget.value = value;
|
||||||
|
|
||||||
|
if (selectionStart !== undefined && selectionEnd !== undefined) {
|
||||||
|
e.currentTarget.setSelectionRange(selectionStart, selectionEnd);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
|
e.currentTarget.dataset.__teactSelectionStart = String(selectionStart);
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
|
e.currentTarget.dataset.__teactSelectionEnd = String(selectionEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checked !== undefined) {
|
if (checked !== undefined) {
|
||||||
@ -616,7 +631,15 @@ function setAttribute(element: HTMLElement, key: string, value: any) {
|
|||||||
// An optimization attempt
|
// An optimization attempt
|
||||||
} else if (key === 'value') {
|
} else if (key === 'value') {
|
||||||
if ((element as HTMLInputElement).value !== value) {
|
if ((element as HTMLInputElement).value !== value) {
|
||||||
|
const {
|
||||||
|
__teactSelectionStart: selectionStart, __teactSelectionEnd: selectionEnd,
|
||||||
|
} = (element as HTMLInputElement).dataset;
|
||||||
|
|
||||||
(element as HTMLInputElement).value = value;
|
(element as HTMLInputElement).value = value;
|
||||||
|
|
||||||
|
if (selectionStart !== undefined && selectionEnd !== undefined) {
|
||||||
|
(element as HTMLInputElement).setSelectionRange(Number(selectionStart), Number(selectionEnd));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (key === 'style') {
|
} else if (key === 'style') {
|
||||||
element.style.cssText = value;
|
element.style.cssText = value;
|
||||||
|
|||||||
@ -32,7 +32,10 @@ type ActionHandler = (
|
|||||||
payload: any,
|
payload: any,
|
||||||
) => GlobalState | void | Promise<void>;
|
) => GlobalState | void | Promise<void>;
|
||||||
|
|
||||||
type MapStateToProps<OwnProps = undefined> = ((global: GlobalState, ownProps: OwnProps) => AnyLiteral);
|
type DetachWhenChanged = (current: any) => void;
|
||||||
|
type MapStateToProps<OwnProps = undefined> = (
|
||||||
|
(global: GlobalState, ownProps: OwnProps, detachWhenChanged: DetachWhenChanged) => AnyLiteral
|
||||||
|
);
|
||||||
|
|
||||||
let currentGlobal = {} as GlobalState;
|
let currentGlobal = {} as GlobalState;
|
||||||
|
|
||||||
@ -52,6 +55,9 @@ const containers = new Map<string, {
|
|||||||
mappedProps?: Props;
|
mappedProps?: Props;
|
||||||
forceUpdate: Function;
|
forceUpdate: Function;
|
||||||
areMappedPropsChanged: boolean;
|
areMappedPropsChanged: boolean;
|
||||||
|
isDetached: boolean;
|
||||||
|
detachReason: any;
|
||||||
|
detachWhenChanged: DetachWhenChanged;
|
||||||
DEBUG_updates: number;
|
DEBUG_updates: number;
|
||||||
DEBUG_componentName: string;
|
DEBUG_componentName: string;
|
||||||
}>();
|
}>();
|
||||||
@ -139,13 +145,21 @@ function updateContainers() {
|
|||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
for (const container of containers.values()) {
|
for (const container of containers.values()) {
|
||||||
const {
|
const {
|
||||||
mapStateToProps, ownProps, mappedProps, forceUpdate,
|
mapStateToProps, ownProps, mappedProps, forceUpdate, isDetached, detachWhenChanged,
|
||||||
} = container;
|
} = container;
|
||||||
|
|
||||||
|
if (isDetached) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let newMappedProps;
|
let newMappedProps;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
newMappedProps = mapStateToProps(currentGlobal, ownProps);
|
newMappedProps = mapStateToProps(currentGlobal, ownProps, detachWhenChanged);
|
||||||
|
|
||||||
|
if (container.isDetached) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
handleError(err);
|
handleError(err);
|
||||||
|
|
||||||
@ -213,7 +227,7 @@ export function removeCallback(cb: Function) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function withGlobal<OwnProps>(
|
export function withGlobal<OwnProps extends AnyLiteral>(
|
||||||
mapStateToProps: MapStateToProps<OwnProps> = () => ({}),
|
mapStateToProps: MapStateToProps<OwnProps> = () => ({}),
|
||||||
) {
|
) {
|
||||||
return (Component: FC) => {
|
return (Component: FC) => {
|
||||||
@ -229,13 +243,25 @@ export function withGlobal<OwnProps>(
|
|||||||
};
|
};
|
||||||
}, [id]);
|
}, [id]);
|
||||||
|
|
||||||
let container = containers.get(id);
|
let container = containers.get(id)!;
|
||||||
if (!container) {
|
if (!container) {
|
||||||
container = {
|
container = {
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
ownProps: props,
|
ownProps: props,
|
||||||
areMappedPropsChanged: false,
|
areMappedPropsChanged: false,
|
||||||
forceUpdate,
|
forceUpdate,
|
||||||
|
isDetached: false,
|
||||||
|
detachReason: undefined,
|
||||||
|
// This allows to ignore changes in global during animation before unmount
|
||||||
|
detachWhenChanged: (current) => {
|
||||||
|
const { detachReason } = container!;
|
||||||
|
|
||||||
|
if (detachReason === undefined && current !== undefined) {
|
||||||
|
container!.detachReason = current;
|
||||||
|
} else if (detachReason !== undefined && detachReason !== current) {
|
||||||
|
container!.isDetached = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
DEBUG_updates: 0,
|
DEBUG_updates: 0,
|
||||||
DEBUG_componentName: Component.name,
|
DEBUG_componentName: Component.name,
|
||||||
};
|
};
|
||||||
@ -251,7 +277,7 @@ export function withGlobal<OwnProps>(
|
|||||||
container.ownProps = props;
|
container.ownProps = props;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
container.mappedProps = mapStateToProps(currentGlobal, props);
|
container.mappedProps = mapStateToProps(currentGlobal, props, container.detachWhenChanged);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
handleError(err);
|
handleError(err);
|
||||||
}
|
}
|
||||||
@ -297,8 +323,9 @@ export function typify<ProjectGlobalState, ActionPayloads, NonTypedActionNames e
|
|||||||
name: ActionName,
|
name: ActionName,
|
||||||
handler: ActionHandlers[ActionName],
|
handler: ActionHandlers[ActionName],
|
||||||
) => void,
|
) => void,
|
||||||
withGlobal: withGlobal as <OwnProps>(
|
withGlobal: withGlobal as <OwnProps extends AnyLiteral>(
|
||||||
mapStateToProps: ((global: ProjectGlobalState, ownProps: OwnProps) => AnyLiteral),
|
mapStateToProps: (
|
||||||
|
(global: ProjectGlobalState, ownProps: OwnProps, detachWhenChanged: DetachWhenChanged) => AnyLiteral),
|
||||||
) => (Component: FC) => FC<OwnProps>,
|
) => (Component: FC) => FC<OwnProps>,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user