Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support nested props #123

Merged
merged 11 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions apps/web/components/ComponentMonitor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,22 +181,21 @@ export function ComponentMonitor({
badgeClass: 'bg-success',
name: 'return',
componentId: parseComponentId(
isFromComponent ? message.componentId : message.targetId
isFromComponent ? message.containerId : message.targetId
)!,
summary: `[${requestId.split('-')[0]}] returned ${result} ${
!isFromComponent ? 'to' : ''
}`,
};
}
case 'component.update': {
const { __componentcallbacks, ...simpleProps } = message.props || {};
return {
message,
isFromComponent,
badgeClass: 'bg-warning',
name: 'update',
componentId: parseComponentId(toComponent!)!,
summary: `updated props ${JSON.stringify(simpleProps)} on`,
summary: `updated props ${JSON.stringify(message.props || {})} on`,
};
}
case 'component.domCallback': {
Expand Down
74 changes: 37 additions & 37 deletions packages/application/src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,50 +49,50 @@ export function deserializeProps({
}

delete props.__bweMeta;
if (!props.__domcallbacks) {
return props;
}

Object.entries(props.__domcallbacks).forEach(
([propKey, callback]: [string, any]) => {
props[propKey.split('::')[0]] = (...args: any[]) => {
let serializedArgs: any = args;
const event = args[0] || {};
return Object.fromEntries(
Object.entries(props).map(([k, v]) => {
const callbackMeta = v as { callbackIdentifier: string } | any;
if (!callbackMeta?.callbackIdentifier) {
return [k, v];
}

const { callbackIdentifier } = callbackMeta;
return [
k,
(...args: any[]) => {
let serializedArgs: any = args;
const event = args[0] || {};

// TODO make this opt-in/out?
event.preventDefault?.();

const { target } = event;
// is this a DOM event?
if (target && typeof target === 'object') {
const { target } = event;// is this a DOM event?
if (target && typeof target === 'object') {
const { checked, name, type, value } = target;
serializedArgs = {
event: {
target: {
checked,
name,
type,
value,
serializedArgs = {
event: {
target: {
checked,
name,
type,
value,
},
},
},
};
}
};
}

sendMessage({
componentId: id,
message: {
args: serializedArgs,
method: callback.__componentMethod,
type: 'component.domCallback',
},
onMessageSent,
});
};
}
sendMessage({
componentId: id,
message: {
args: serializedArgs,
method: callbackIdentifier,
type: 'component.domCallback',
},
onMessageSent,
});
},
];
})
);

delete props.__domcallbacks;
delete props.__componentcallbacks;

return props;
}
4 changes: 2 additions & 2 deletions packages/application/src/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ export function onCallbackResponse({
a component has executed a callback invoked from another component
return the value of the callback execution to the calling component
*/
const { requestId, result, targetId, componentId } = data;
const { requestId, result, targetId, containerId } = data;
sendMessage({
componentId: targetId,
message: {
componentId,
containerId,
result,
requestId,
targetId,
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/types/messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export interface ComponentCallbackInvocation extends PostMessageParams {
}

export interface ComponentCallbackResponse extends PostMessageParams {
componentId: string;
containerId: string;
requestId: string;
result: string; // stringified JSON in the form of { result: any, error: string }
targetId: string;
Expand Down
2 changes: 0 additions & 2 deletions packages/common/src/types/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ export interface KeyValuePair {

export interface Props extends KeyValuePair {
__bweMeta?: WebEngineMeta;
__domcallbacks?: { [key: string]: any };
__componentcallbacks?: { [key: string]: any };
children?: any[];
className?: string;
id?: string;
Expand Down
14 changes: 1 addition & 13 deletions packages/common/src/types/serialization.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Props } from './render';
import { KeyValuePair } from './render';
import type { ComponentTrust } from './trust';

export interface ComponentChildMetadata {
Expand All @@ -10,22 +9,11 @@ export interface ComponentChildMetadata {
}

export type SerializedArgs = Array<
string | number | object | any[] | { __componentMethod: string }
string | number | object | any[] | { callbackIdentifier: string }
>;

export interface SerializedNode {
childComponents?: ComponentChildMetadata[];
type: string;
props: Props;
}

export interface SerializedComponentCallback {
__componentMethod: string;
parentId: string;
}

export interface SerializedProps extends KeyValuePair {
__componentcallbacks?: {
[key: string]: SerializedComponentCallback;
};
}
17 changes: 8 additions & 9 deletions packages/container/src/callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function invokeComponentCallback({
args,
buildRequest,
callbacks,
componentId,
containerId,
invokeCallback,
method,
postCallbackInvocationMessage,
Expand All @@ -49,19 +49,19 @@ export function invokeComponentCallback({
}: InvokeComponentCallbackParams): any {
// unknown method
if (!callbacks[method]) {
console.error(`No method ${method} on component ${componentId}`);
console.error(`No method ${method} on container ${containerId}`);
return null;
}

// some arguments to this callback are methods on other Components
// these must be replaced with wrappers invoking Component methods
if (
typeof args?.some === 'function' &&
args.some((arg: any) => arg.__componentMethod)
args.some((arg: any) => arg?.callbackIdentifier)
) {
args = args.map((arg: any) => {
const { __componentMethod: componentMethod } = arg;
if (!componentMethod) {
const { callbackIdentifier } = arg;
if (!callbackIdentifier) {
return arg;
}

Expand All @@ -72,12 +72,11 @@ export function invokeComponentCallback({
postCallbackInvocationMessage({
args: childArgs,
callbacks,
componentId,
method: componentMethod,
containerId,
method: callbackIdentifier,
requestId,
// TODO must specify a real value here
serializeArgs,
targetId: componentMethod.split('::').slice(1).join('::'),
targetId: callbackIdentifier.split('::').slice(1).join('::'),
});
};
});
Expand Down
8 changes: 4 additions & 4 deletions packages/container/src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function initContainer({
postComponentRenderMessage,
} = composeMessagingMethods();

const { deserializeProps, serializeArgs, serializeNode } =
const { deserializeArgs, deserializeProps, serializeArgs, serializeNode } =
composeSerializationMethods({
buildRequest,
callbacks,
Expand Down Expand Up @@ -67,11 +67,11 @@ export function initContainer({
const processEvent = buildEventHandler({
buildRequest,
callbacks,
componentId,
containerId: componentId,
deserializeArgs,
deserializeProps,
invokeCallback,
invokeComponentCallback,
parentContainerId,
postCallbackInvocationMessage,
postCallbackResponseMessage,
requests,
Expand All @@ -97,7 +97,7 @@ export function initContainer({
const props = buildSafeProxy({
componentId,
props: deserializeProps({
componentId,
containerId: componentId,
props: componentPropsJson,
}),
});
Expand Down
24 changes: 9 additions & 15 deletions packages/container/src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import type { ProcessEventParams } from './types';
* Return an event handler function to be registered under `window.addEventHandler('message', fn(event))`
* @param buildRequest Function to build an inter-Component asynchronous callback request
* @param callbacks The set of callbacks defined on the target Component
* @param componentId ID of the target Component on which the
* @param containerId ID of the container handling messages
* @param deserializeProps Function to deserialize props passed on the event
* @param invokeCallback Function to execute the specified function in the current context
* @param invokeComponentCallback Function to execute the specified function, either in the current context or another Component's
* @param parentContainerId ID of the parent container
* @param postCallbackInvocationMessage Request invocation on external Component via window.postMessage
* @param postCallbackResponseMessage Send callback execution result to calling Component via window.postMessage
* @param requests The set of inter-Component callback requests being tracked by the Component
Expand All @@ -21,11 +20,11 @@ import type { ProcessEventParams } from './types';
export function buildEventHandler({
buildRequest,
callbacks,
componentId,
containerId,
deserializeArgs,
deserializeProps,
invokeCallback,
invokeComponentCallback,
parentContainerId,
postCallbackInvocationMessage,
postCallbackResponseMessage,
requests,
Expand All @@ -44,22 +43,17 @@ export function buildEventHandler({
args: SerializedArgs;
method: string;
}) {
if (!parentContainerId) {
console.error(`no parent container for ${componentId}`);
return;
}

const deserializedArgs = deserializeArgs({ args, containerId });
return invokeComponentCallback({
args,
args: deserializedArgs,
buildRequest,
callbacks,
componentId,
containerId,
invokeCallback,
method,
postCallbackInvocationMessage,
requests,
serializeArgs,
targetId: parentContainerId,
});
}

Expand Down Expand Up @@ -108,7 +102,7 @@ export function buildEventHandler({
result = applyRecursivelyToComponents(result, (n: any) =>
serializeNode({
node: n,
parentId: method,
parentId: method.split('::')[0],
childComponents: [],
})
);
Expand All @@ -117,7 +111,7 @@ export function buildEventHandler({
if (requestId) {
postCallbackResponseMessage({
error,
componentId,
containerId,
requestId,
result: value,
targetId: originator,
Expand Down Expand Up @@ -188,7 +182,7 @@ export function buildEventHandler({
case 'component.update': {
updateProps(
deserializeProps({
componentId,
containerId,
props: event.data.props,
})
);
Expand Down
10 changes: 5 additions & 5 deletions packages/container/src/messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ export function composeMessagingMethods() {
function postCallbackInvocationMessage({
args,
callbacks,
componentId,
containerId,
method,
requestId,
serializeArgs,
targetId,
}: PostMessageComponentCallbackInvocationParams): void {
postMessage<ComponentCallbackInvocation>({
args: serializeArgs({ args, callbacks, componentId }),
args: serializeArgs({ args, callbacks, containerId }),
method,
originator: componentId,
originator: containerId,
requestId,
targetId,
type: 'component.callbackInvocation',
Expand All @@ -53,7 +53,7 @@ export function composeMessagingMethods() {

function postCallbackResponseMessage({
error,
componentId,
containerId,
requestId,
result,
targetId,
Expand All @@ -63,7 +63,7 @@ export function composeMessagingMethods() {

postMessage<ComponentCallbackResponse>({
requestId,
componentId,
containerId,
result: JSON.stringify({
value: result,
error: serializedError,
Expand Down
Loading
Loading