Skip to content

Commit

Permalink
Merge pull request #265 from belk1ng/feat/usePostMessage
Browse files Browse the repository at this point in the history
feat: add usePostMessage hook
  • Loading branch information
debabin authored Dec 21, 2024
2 parents 16dc765 + 55d3892 commit 3080538
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export * from './usePaint/usePaint';
export * from './useParallax/useParallax';
export * from './usePermission/usePermission';
export * from './usePointerLock/usePointerLock';
export * from './usePostMessage/usePostMessage';
export * from './usePreferredColorScheme/usePreferredColorScheme';
export * from './usePreferredContrast/usePreferredContrast';
export * from './usePreferredDark/usePreferredDark';
Expand Down
23 changes: 23 additions & 0 deletions src/hooks/usePostMessage/usePostMessage.demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { usePostMessage } from './usePostMessage';

const Demo = () => {
const { postMessage } = usePostMessage<string>((event) => {
if (location.origin === event.origin) {
console.log('MessageEvent: ', event);
}
});

const onClick = () => {
postMessage(window, 'Custom Message', {
targetOrigin: '*'
});
};

return (
<section>
<button onClick={onClick}>Click to post message</button>
</section>
);
};

export default Demo;
72 changes: 72 additions & 0 deletions src/hooks/usePostMessage/usePostMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useEffect } from 'react';

/** The possible entity types */
type PossibleEntity = Window | Worker | MessagePort;

/** The use post message entity arguments */
type PostMessageEntityArguments<Entity extends PossibleEntity> = Entity['postMessage'] extends (
message: unknown,
...rest: infer Rest
) => void
? Rest
: never;

/** The use post message return type */
export interface UsePostMessageReturn<MessagePayload> {
postMessage: <Entity extends PossibleEntity>(
targetSource: Entity,
message: MessagePayload,
...args: PostMessageEntityArguments<Entity>
) => void;
}

/**
* @name usePostMessage
* @description - Hook that allows you to use `postMessage` function
* @category Browser
*
* @overload
* @template MessagePayload The message data type
* @param {(message: MessageEvent<MessagePayload>) => void} onMessage callback to get received message event
* @returns {UsePostMessageReturn} An object with a patched `postMethod` function
*
* @example
* const { postMessage } = usePostMessage();
*/
export const usePostMessage = <MessagePayload = unknown>(
onMessage?: (message: MessageEvent<MessagePayload>) => void
): UsePostMessageReturn<MessagePayload> => {
const postMessage = <Entity extends PossibleEntity>(
targetSource: Entity,
message: MessagePayload,
...args: unknown[]
) => {
if (targetSource instanceof Window) {
targetSource.postMessage(message, ...(args as PostMessageEntityArguments<Window>));
} else if (targetSource instanceof Worker) {
targetSource.postMessage(message, ...(args as PostMessageEntityArguments<Worker>));
} else {
targetSource.postMessage(message, ...(args as PostMessageEntityArguments<MessagePort>));
}
};

useEffect(() => {
const controller = new AbortController();

window.addEventListener(
'message',
(event: MessageEvent<MessagePayload>) => {
onMessage?.(event);
},
{ signal: controller.signal }
);

return () => {
controller.abort();
};
}, [onMessage]);

return {
postMessage
};
};

0 comments on commit 3080538

Please sign in to comment.