Skip to content

Commit

Permalink
fixup! refactor: Change syntax to support closers capturing variables
Browse files Browse the repository at this point in the history
  • Loading branch information
mhevery committed Jan 24, 2022
1 parent 6bb9707 commit 0b58880
Show file tree
Hide file tree
Showing 9 changed files with 32 additions and 109 deletions.
2 changes: 1 addition & 1 deletion src/core/component/q-component.docs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const OtherComponent = qComponent(() => {
//
// <docs anchor="props">
const MyComp = qComponent((props: { title: 'MyTitle'; label: 'defaultLabel' }) => {
withProps(...other);
withProps({ title: props.title, ...other });
return onRender(() => <span></span>);
});
// </docs>
Expand Down
3 changes: 1 addition & 2 deletions src/core/component/q-component.public.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { assertDefined } from '../assert/assert';
import { qImport } from '../import/qImport';
import { QRL, toQrlOrError } from '../import/qrl';
import type { qrlFactory } from '../props/q-props-on';
Expand Down Expand Up @@ -147,7 +146,7 @@ export function qComponent<PROPS extends {}>(
const invokeCtx = newInvokeContext(hostElement);
return useInvoke(invokeCtx, onMount, componentProps);
};
return h(tagName, { 'on:qRender': onRenderFactory }) as any;
return h(tagName, { 'on:qRender': onRenderFactory, ...props }) as any;
};
}

Expand Down
6 changes: 0 additions & 6 deletions src/core/props/q-props-on.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { qImport } from '../import/qImport';
import { isQrl, parseQRL, QRL, stringifyQRL } from '../import/qrl';
import { qDeflate } from '../json/q-json';
import { h } from '../render/jsx/factory';
import { Fragment } from '../render/jsx/jsx-runtime';
import { getInvokeContext, useInvoke } from '../use/use-core';
import { fromCamelToKebabCase } from '../util/case';
import { EMPTY_ARRAY } from '../util/flyweight';
import { isPromise } from '../util/promises';
import { qGlobal } from '../util/qdev';
import { debugStringify } from '../util/stringify';
import type { ValueOrPromise } from '../util/types';
import type { QPropsContext } from './q-props';
Expand Down Expand Up @@ -58,9 +55,6 @@ export function qPropReadQRL(
if (!qrl.symbolRef) {
qrl.symbolRef = await qImport(cache.__element__, qrl);
}
// TODO(HACK): Hack to work around Optimizer bug.
qGlobal.h = h;
qGlobal.Fragment = Fragment;

return useInvoke(context, qrl.symbolRef);
})
Expand Down
1 change: 0 additions & 1 deletion src/core/props/q-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { parseQRL, QRL } from '../import/qrl';
import { qJsonParse, qJsonStringify } from '../json/q-json';
import { getQObjectId, QObjectIdSymbol, wrap } from '../object/q-object';
import { QStore_hydrate } from '../object/q-store';
import { isRef } from '../render/ref';
import { fromCamelToKebabCase } from '../util/case';
import { EMPTY_ARRAY } from '../util/flyweight';
import { AttributeMarker } from '../util/markers';
Expand Down
60 changes: 14 additions & 46 deletions src/core/render/cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { didQPropsChange } from '../props/q-props';
import type { ComponentRenderQueue } from './q-render';
import { getSlotMap, isSlotMap, NamedSlot, NamedSlotEnum, SlotMap } from './slots';
import { qProps } from '../props/q-props.public';
import type { Ref } from './ref';

/**
* Cursor represents a set of sibling elements at a given level in the DOM.
Expand Down Expand Up @@ -130,8 +129,7 @@ export function cursorReconcileElement(
component: QComponentCtx | null,
expectTag: string,
expectProps: Record<string, any> | typeof String,
_componentRenderQueue: ComponentRenderQueue,
isComponent: boolean
componentRenderQueue: ComponentRenderQueue | null
): Cursor {
let node = getNode(cursor);
assertNotEqual(node, undefined, 'Cursor already closed');
Expand All @@ -144,8 +142,7 @@ export function cursorReconcileElement(
component,
expectTag,
expectProps,
_componentRenderQueue,
isComponent
componentRenderQueue
);
} else {
assertNotEqual(node, undefined, 'Cursor already closed');
Expand All @@ -156,13 +153,11 @@ export function cursorReconcileElement(
component,
expectTag,
expectProps,
_componentRenderQueue,
isComponent,
false
componentRenderQueue
);
assertDefined(node);
setNode(cursor, node.nextSibling);
return _reconcileElementChildCursor(node as Element, isComponent);
return _reconcileElementChildCursor(node as Element, !!componentRenderQueue);
}
}

Expand All @@ -173,8 +168,7 @@ function slotMapReconcileSlots(
component: QComponentCtx | null,
expectTag: string,
expectProps: Record<string, any>,
_componentRenderQueue: ComponentRenderQueue,
isComponent: boolean
componentRenderQueue: ComponentRenderQueue | null
): Cursor {
const slotName = expectProps[AttributeMarker.QSlotAttr] || '';
const namedSlot = keyValueArrayGet(slots, slotName);
Expand All @@ -194,9 +188,7 @@ function slotMapReconcileSlots(
component,
expectTag,
expectProps,
_componentRenderQueue,
isComponent,
false
componentRenderQueue
);
if (childNode !== node) {
namedSlot[index] = node;
Expand All @@ -212,13 +204,11 @@ function slotMapReconcileSlots(
component,
expectTag,
expectProps,
_componentRenderQueue,
isComponent,
true
);
assertDefined(childNode);
}
return _reconcileElementChildCursor(childNode as Element, isComponent);
return _reconcileElementChildCursor(childNode as Element, !!componentRenderQueue);
}

function _reconcileElement(
Expand All @@ -227,17 +217,15 @@ function _reconcileElement(
end: Node | null,
component: QComponentCtx | null,
expectTag: string,
expectProps: Record<string, any>,
componentRenderQueue: ComponentRenderQueue,
isComponent: boolean,
isProjected: boolean
expectProps: Record<string, any> | StringConstructor,
componentRenderQueue: ComponentRenderQueue | null | true
): Element {
let shouldDescendIntoComponent: boolean;
let reconciledElement: HTMLElement;
if (isDomElementWithTagName(existing, expectTag)) {
const props = qProps(existing as HTMLElement) as any;
propAssign(existing, props, expectProps, componentRenderQueue);
shouldDescendIntoComponent = didQPropsChange(props) && isComponent;
Object.assign(props, expectProps);
shouldDescendIntoComponent = didQPropsChange(props) && !!componentRenderQueue;
reconciledElement = existing as HTMLElement;
} else {
// Expected node and actual node did not match. Need to switch.
Expand All @@ -247,14 +235,14 @@ function _reconcileElement(
(isDocument(parent) ? parent : parent.ownerDocument!).createElement(expectTag),
end
);
shouldDescendIntoComponent = isComponent;
propAssign(reconciledElement, qProps(reconciledElement), expectProps, componentRenderQueue);
shouldDescendIntoComponent = !!componentRenderQueue;
Object.assign(qProps(reconciledElement), expectProps);
}
component && component.styleClass && reconciledElement.classList.add(component.styleClass);
if (shouldDescendIntoComponent) {
const hostComponent = getQComponent(reconciledElement)!;
hostComponent.styleHostClass && reconciledElement.classList.add(hostComponent.styleHostClass);
if (isComponent && !isProjected) {
if (Array.isArray(componentRenderQueue)) {
componentRenderQueue.push(hostComponent.render());
} else if (reconciledElement.getAttribute(AttributeMarker.OnRenderAttr)) {
reconciledElement.setAttribute(AttributeMarker.RenderNotify, '');
Expand All @@ -263,26 +251,6 @@ function _reconcileElement(
return reconciledElement;
}

function propAssign(
element: Element,
dst: Record<string, any>,
src: Record<string, any>,
componentRenderQueue: ComponentRenderQueue | null | true
) {
for (const key in src) {
if (Object.prototype.hasOwnProperty.call(src, key)) {
if (key === 'q:ref') {
assertDefined(componentRenderQueue);
const ref: Ref = src[key];
ref.current = element;
(componentRenderQueue as ComponentRenderQueue).push(ref.onRender && ref.onRender(element));
} else {
dst[key] = src[key];
}
}
}
}

function _reconcileElementChildCursor(node: Element, isComponent: boolean) {
assertDefined(node);
if (isComponent) {
Expand Down
34 changes: 14 additions & 20 deletions src/core/render/cursor.unit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ describe('cursor', () => {
expect(parentCursor.parent).toEqual(parent);
expect(parentCursor.node).toEqual(null);

const divCursor = cursorReconcileElement(parentCursor, null, 'div', {}, [], false);
const divCursor = cursorReconcileElement(parentCursor, null, 'div', {}, null);
expect(parentCursor.node).toEqual(null);
cursorReconcileText(divCursor, 'A');
cursorReconcileEnd(divCursor);

const spanCursor = cursorReconcileElement(parentCursor, null, 'span', {}, [], false);
const spanCursor = cursorReconcileElement(parentCursor, null, 'span', {}, null);
expect(parentCursor.node).toEqual(null);
cursorReconcileText(spanCursor, 'B');
cursorReconcileEnd(spanCursor);
Expand All @@ -53,11 +53,11 @@ describe('cursor', () => {
expect(parentCursor.parent).toEqual(parent);
expect(parentCursor.node).toEqual(parent.querySelector('div'));

const divCursor = cursorReconcileElement(parentCursor, null, 'div', { id: 123 }, [], false);
const divCursor = cursorReconcileElement(parentCursor, null, 'div', { id: 123 }, null);
cursorReconcileText(divCursor, 'A');
cursorReconcileEnd(divCursor);

const spanCursor = cursorReconcileElement(parentCursor, null, 'span', {}, [], false);
const spanCursor = cursorReconcileElement(parentCursor, null, 'span', {}, null);
cursorReconcileText(spanCursor, 'B');
cursorReconcileEnd(spanCursor);

Expand All @@ -83,11 +83,11 @@ describe('cursor', () => {
);
const parentCursor = cursorForParent(parent);

const divCursor = cursorReconcileElement(parentCursor, null, 'div', {}, [], false);
const divCursor = cursorReconcileElement(parentCursor, null, 'div', {}, null);
cursorReconcileText(divCursor, 'A');
cursorReconcileEnd(divCursor);

const spanCursor = cursorReconcileElement(parentCursor, null, 'span', {}, [], false);
const spanCursor = cursorReconcileElement(parentCursor, null, 'span', {}, null);
cursorReconcileText(spanCursor, 'B');
cursorReconcileEnd(spanCursor);

Expand Down Expand Up @@ -120,7 +120,7 @@ describe('cursor', () => {
);
cursorReconcileStartVirtualNode(childCursor);
cursorReconcileText(childCursor, 'ABC');
cursorReconcileElement(childCursor, null, 'div', {}, [], false);
cursorReconcileElement(childCursor, null, 'div', {}, null);
cursorReconcileEnd(childCursor);
expectDOM(
parent,
Expand All @@ -146,7 +146,7 @@ describe('cursor', () => {
const parentCursor = cursorForParent(parent);
const span = parent.querySelector('span');

const spanCursor = cursorReconcileElement(parentCursor, null, 'span', {}, [], false);
const spanCursor = cursorReconcileElement(parentCursor, null, 'span', {}, null);
cursorReconcileText(spanCursor, 'A');
cursorReconcileEnd(spanCursor);

Expand Down Expand Up @@ -176,8 +176,7 @@ describe('cursor', () => {
null,
'component',
COMPONENT_ATTRS,
log,
true
log
);
cursorReconcileText(componentCursor, 'ABC');

Expand Down Expand Up @@ -211,8 +210,7 @@ describe('cursor', () => {
null,
'component',
COMPONENT_ATTRS,
log,
true
log
);
cursorReconcileText(componentCursor, 'NEW');
cursorReconcileEnd(componentCursor);
Expand Down Expand Up @@ -246,16 +244,14 @@ describe('cursor', () => {
null,
'component',
COMPONENT_ATTRS,
log,
true
log
);
const divCursor = cursorReconcileElement(
componentCursor,
null,
'div',
{ [AttributeMarker.QSlotAttr]: 'detail' },
log,
false
null
);
cursorReconcileText(divCursor, 'DETAIL');

Expand Down Expand Up @@ -351,16 +347,14 @@ describe('cursor', () => {
null,
'component',
COMPONENT_ATTRS,
log,
true
log
);
const childCursor = cursorReconcileElement(
componentCursor,
null,
'child',
{ [AttributeMarker.OnRenderAttr]: childOnRender },
log,
true
log
);
cursorReconcileEnd(childCursor);
cursorReconcileEnd(componentCursor);
Expand Down
16 changes: 0 additions & 16 deletions src/core/render/q-render.public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { NodeType } from '../util/types';
import { cursorForParent } from './cursor';
import type { JSXNode } from './jsx/types/jsx-node';
import { ComponentRenderQueue, visitJsxNode } from './q-render';
import { Ref as RefClass } from './ref';

/**
* Render JSX.
Expand All @@ -30,18 +29,3 @@ export async function qRender(
visitJsxNode(null, renderQueue, cursor, jsxNode);
return flattenPromiseTree<HTMLElement>(renderQueue);
}

/**
* @public
*/
export interface Ref {
current: Element | undefined;
onRender: ((element: Element) => void | Promise<any>) | undefined;
}

/**
* @public
*/
export function createRef(onRender?: (element: Element) => void | Promise<any>): Ref {
return new RefClass(onRender);
}
6 changes: 2 additions & 4 deletions src/core/render/q-render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ function visitJsxLiteralNode(
component,
jsxTag,
jsxNode.props,
renderQueue,
isQComponent
isQComponent ? renderQueue : null
);
if (!hasInnerHtmlOrTextBinding(jsxNode)) {
// we don't process children if we have inner-html bound to something.
Expand Down Expand Up @@ -126,8 +125,7 @@ export function visitQSlotJsxNode(
component,
AttributeMarker.QSlot,
{ [AttributeMarker.QSlotName]: slotName, ...jsxNode.props },
renderQueue,
false
null
);
const slotMap = getSlotMap(component);
const namedSlot = keyValueArrayGet(slotMap, slotName);
Expand Down
13 changes: 0 additions & 13 deletions src/core/render/ref.ts

This file was deleted.

0 comments on commit 0b58880

Please sign in to comment.