From 74ac86b3c1b51352fc83e66fd84eb1aadcbc4292 Mon Sep 17 00:00:00 2001 From: Maxwell Frank <92897870+MaxFrank13@users.noreply.github.com> Date: Wed, 13 Dec 2023 14:43:14 -0500 Subject: [PATCH] Documenting hooks.js file (#5) * docs: plugin hooks --------- Co-authored-by: Maxwell Frank --- src/plugins/data/hooks.js | 89 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/src/plugins/data/hooks.js b/src/plugins/data/hooks.js index 04c9ae92..4f03e681 100644 --- a/src/plugins/data/hooks.js +++ b/src/plugins/data/hooks.js @@ -1,9 +1,19 @@ +/** + * Hooks file for functions that handle the communication between a Plugin and its Host + */ + import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react'; import { getConfig } from '@edx/frontend-platform'; import { PLUGIN_MOUNTED, PLUGIN_READY, PLUGIN_UNMOUNTED } from './constants'; +/** + * Called by PluginSlot to extract a list of plugins based on the JS configuration + * + * @param {String} id - Name of PluginSlot + * @returns {Object} - JS configuration for the PluginSlot + */ export function usePluginSlot(id) { if (getConfig().plugins[id] !== undefined) { return getConfig().plugins[id]; @@ -11,54 +21,109 @@ export function usePluginSlot(id) { return { keepDefault: true, plugins: [] }; } +/* Listening for events */ + +/** + * Dynamically add an event listener to the provided source window. + * The source window can be the global parent (ie. the "window" object in the browser) + * or it can be the content window of an individual element (ie. iFrame plugin container) + * + * @param {Object} srcWindow - Window object that the event originates from + * @param {String} type - Event name (eg. PLUGIN_RESIZE) + * @param {Function} callback - Called when the event is triggered + */ export function useMessageEvent(srcWindow, type, callback) { + // useLayoutEffect is called before the browser repaints the screen useLayoutEffect(() => { + // Create a listener callback function const listener = (event) => { // Filter messages to those from our source window. + // NOTE: the "srcWindow" is determined by the below useHostEvent and usePluginEvent functions if (event.source === srcWindow) { + // Fire callback if the type from the listened event matches the type from the message event if (event.data.type === type) { callback({ type, payload: event.data.payload }); } } }; + // Add the listener to the global object if the srcWindow is not null if (srcWindow !== null) { global.addEventListener('message', listener); } + // useEffect cleanup return () => { global.removeEventListener('message', listener); }; }, [srcWindow, type, callback]); } +/** + * Called by the Plugin component to use events that were listened to (ie. PLUGIN_RESIZE) + * + * @param {String} type - Event name (eg. PLUGIN_RESIZE) + * @param {Function} callback - Called when the event is triggered + */ export function useHostEvent(type, callback) { useMessageEvent(global.parent, type, callback); } -export function usePluginEvent(iframeElement, type, callback) { - const contentWindow = iframeElement ? iframeElement.contentWindow : null; +/** + * Used to listen for events from a wrapped Plugin element (eg. PluginContainerIframe) + * + * @param {Object} element - Plugin element (eg.