Skip to content

Commit

Permalink
docs: Expand inline documentation
Browse files Browse the repository at this point in the history
Align with Gutenberg project practices.
  • Loading branch information
dcalhoun committed Nov 20, 2024
1 parent 398d2e2 commit 4f18999
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 12 deletions.
6 changes: 6 additions & 0 deletions src/components/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
import Editor from './editor';
import EditorLoadNotice from './editor-load-notice';

/**
* Entry component rendering editor and surround UI.
*
* @param {Object} props - The properties passed to the component.
* @return {JSX.Element} The rendered App component.
*/
function App(props) {
return (
<>
Expand Down
10 changes: 10 additions & 0 deletions src/components/editor-load-notice.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import { Notice } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useState, useEffect } from '@wordpress/element';

/**
* Displays a notice with actions to retry or dismiss.
*
* @return {?JSX.Element} The rendered component or null if no notice is present.
*/
export default function EditorLoadNotice() {
const { notice, clearNotice } = useEditorLoadNotice();

Expand Down Expand Up @@ -34,6 +39,11 @@ export default function EditorLoadNotice() {
);
}

/**
* Conditionally and temporarily sets a notice message based on the URL.
*
* @return {{notice:string, clearNotice:()=>void}} The notice message and a function to clear it.
*/
function useEditorLoadNotice() {
const [notice, setNotice] = useState(null);

Expand Down
6 changes: 6 additions & 0 deletions src/components/editor-toolbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ import { Button, Popover, ToolbarButton } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { close, cog } from '@wordpress/icons';

/**
* Renders the editor toolbar with an inserter button, block toolbar, and a settings button
* that opens a popover with block settings when a block is selected.
*
* @return {JSX.Element} The rendered editor toolbar component.
*/
const EditorToolbar = () => {
const [isBlockInspectorShown, setBlockInspectorShown] = useState(false);
const { isSelected } = useSelect((select) => {
Expand Down
23 changes: 22 additions & 1 deletion src/components/editor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,23 @@ import { useEditorStyles } from '../hooks/use-editor-styles';
import { unlock } from '../lock-unlock';
import { useMediaUpload } from '../hooks/use-media-upload';

/**
* @typedef {import('../utils/bridge').Post} Post
*/

// Current editor (assumes can be only one instance).
const editor = {};

const { ExperimentalBlockCanvas: BlockCanvas } = unlock(blockEditorPrivateApis);

/**
* Editor component for managing and editing post content.
*
* @param {Object} props - The component props.
* @param {Post} props.post - The post object containing post details.
*
* @return {JSX.Element} The rendered Editor component.
*/
function Editor({ post }) {
const editorPostTitleRef = useRef();
const postTitleRef = useRef(post.title);
Expand Down Expand Up @@ -201,8 +213,17 @@ function Editor({ post }) {

export default Editor;

/**
* Blurs the currently active paragraph element in the document.
*
* This function checks if the currently active element is a paragraph (`<p>`).
* If it is, the function removes focus from that element.
*
* @todo Address the disabled eslint rule `@wordpress/no-global-active-element`.
*
* @return {void}
*/
function blurEditor() {
// TODO: Address the disabled eslint rule.
// eslint-disable-next-line @wordpress/no-global-active-element
const activeElement = document.activeElement;

Expand Down
8 changes: 7 additions & 1 deletion src/hooks/use-editor-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ import { unlock } from '../lock-unlock';

const { getLayoutStyles } = unlock(blockEditorPrivateApis);

// This should be exported from Core so no reimplementation is needed.
/**
* Custom hook to retrieve and memoize editor styles.
*
* @todo This should be exported from Core so no reimplementation is needed.
*
* @return {any[]} An array of editor styles.
*/
export function useEditorStyles() {
const { hasThemeStyleSupport, editorSettings } = useSelect((select) => {
return {
Expand Down
27 changes: 27 additions & 0 deletions src/hooks/use-media-upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ import { useCallback, useEffect } from '@wordpress/element';
*/
import { openMediaLibrary } from '../utils/bridge';

/**
* @typedef {Object} MediaUploadConfig
* @property {Function} onSelect Callback function to handle the selected media.
* @property {string[]} [allowedTypes] Comma-separated list of media types to allow.
* @property {boolean} [multiple=false] Flag to indicate if multiple media items can be selected.
* @property {number|number[]} [value] The context's currently selected media.
*/

/**
* Adds a filter for the MediaUpload component in the Gutenberg editor.
*
* @return {void}
*/
export function useMediaUpload() {
useEffect(() => {
addFilter('editor.MediaUpload', 'GutenbergKit', () => MediaUpload);
Expand All @@ -19,12 +32,26 @@ export function useMediaUpload() {
}, []);
}

/**
* Component exposing the native media library.
*
* @param {MediaUploadConfig} props - The component props.
*
* @return {Element} The rendered component.
*/
function MediaUpload({ render, ...config }) {
const { open } = useNativeMediaLibrary(config);

return render({ open });
}

/**
* Establishes global bridge function to handle native Media Library interactions.
*
* @param {MediaUploadConfig} config - Configuration object for the Media Library.
*
* @return {{open: ()=>void}} - An object containing a function to open the Media Library.
*/
function useNativeMediaLibrary({ onSelect, ...config }) {
useEffect(() => {
window.editor.setMediaUploadAttachment = (attachment) => {
Expand Down
6 changes: 4 additions & 2 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import './index.css';

window.GBKit = getGBKit();
initializeApiFetch();
initializeEditor();

/**
* Configure editor settings and styles, and render the editor.
*/
function initializeEditor() {
const { themeStyles, siteApiRoot } = getGBKit();

Expand Down Expand Up @@ -47,5 +51,3 @@ function initializeEditor() {
</StrictMode>
);
}

initializeEditor();
3 changes: 3 additions & 0 deletions src/remote.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ window.wp.apiFetch = apiFetch;
initializeApiFetch();
initalizeRemoteEditor();

/**
* Configure editor settings and styles, and render the editor.
*/
async function initalizeRemoteEditor() {
try {
const { themeStyles, siteURL, siteApiRoot } = getGBKit();
Expand Down
30 changes: 22 additions & 8 deletions src/utils/api-fetch-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import { getGBKit } from './bridge';
/**
* Initializes the API fetch configuration and middleware.
*
* This function sets up the root URL middleware, adds headers to requests,
* and preloads some endpoints with mock data for specific components.
* @return {void}
*/
export function initializeApiFetch() {
const { siteApiRoot, authHeader } = getGBKit();
Expand Down Expand Up @@ -86,19 +85,30 @@ export function initializeApiFetch() {
);
}

/**
* Middleware setting the CORS mode and remove a specific header causing CORS errors.
*
* @type {import('@wordpress/api-fetch').APIFetchMiddleware}
*
* @todo Address the CORS header hack.
*/
function corsMiddleware(options, next) {
options.mode = 'cors';

// TODO: Ensure this header is not set via CORS mode.
// This custom header causes CORS errors. Although settings the mode to 'cors'
// should prevent this header, incorrect middleware order results in setting
// the header.
// HACK: This custom header causes CORS errors. Although settings the mode to
// 'cors' should prevent this header, incorrect middleware order results in
// setting the header.
// https://github.com/Automattic/jetpack/blob/7801b7f21e01d8a4a102c44dac69c6ebdd1e549d/projects/plugins/jetpack/extensions/editor.js#L22-L52
delete options.headers['x-wp-api-fetch-from-editor'];

return next(options);
}

/**
* Middleware modifying the API path by inserting the site API namespace.
*
* @type {import('@wordpress/api-fetch').APIFetchMiddleware}
*/
function apiPathModifierMiddleware(options, next) {
const { siteApiNamespace } = getGBKit();

Expand Down Expand Up @@ -128,6 +138,11 @@ function createHeadersMiddleware(authHeader) {
};
}

/**
* Middleware to filter out requests to specific endpoints.
*
* @type {import('@wordpress/api-fetch').APIFetchMiddleware}
*/
function filterEndpointsMiddleware(options, next) {
const disabledEndpoints = [
/^\/wp\/v2\/posts\/-?\d+/, // Matches /wp/v2/posts/{ID}
Expand All @@ -149,8 +164,7 @@ function filterEndpointsMiddleware(options, next) {
* This middleware intercepts requests to the media endpoint and conditionally
* removes the 'post' field if its value is '-1', which is used for draft posts.
*
* @param {Object} options The fetch options.
* @param {Function} next The next middleware in the chain.
* @type {import('@wordpress/api-fetch').APIFetchMiddleware}
*/
function mediaUploadMiddleware(options, next) {
if (
Expand Down
44 changes: 44 additions & 0 deletions src/utils/bridge.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* Notifies the native host that the editor has loaded.
*
* @return {void}
*/
export function editorLoaded() {
if (window.editorDelegate) {
window.editorDelegate.onEditorLoaded();
Expand All @@ -11,6 +16,11 @@ export function editorLoaded() {
}
}

/**
* Notifies the native host that the editor content has changed.
*
* @return {void}
*/
export function onEditorContentChanged() {
if (window.editorDelegate) {
window.editorDelegate.onEditorContentChanged();
Expand All @@ -23,6 +33,13 @@ export function onEditorContentChanged() {
}
}

/**
* Notifies the native host that blocks have changed.
*
* @param {boolean} [isEmpty=false] - Whether the editor is empty.
*
* @return {void}
*/
export function onBlocksChanged(isEmpty = false) {
if (window.editorDelegate) {
window.editorDelegate.onBlocksChanged(isEmpty);
Expand All @@ -36,6 +53,11 @@ export function onBlocksChanged(isEmpty = false) {
}
}

/**
* Requests the native host to show the block picker.
*
* @return {void}
*/
export function showBlockPicker() {
if (window.editorDelegate) {
window.editorDelegate.showBlockPicker();
Expand All @@ -49,6 +71,13 @@ export function showBlockPicker() {
}
}

/**
* Requests the native host to open the Media Library
*
* @param {import('../hooks/use-media-upload').MediaUploadConfig} config - Media Library configuration.
*
* @return {void}
*/
export function openMediaLibrary(config) {
if (window.editorDelegate) {
window.editorDelegate.openMediaLibrary(JSON.stringify(config));
Expand Down Expand Up @@ -90,6 +119,21 @@ export function getGBKit() {
}
}

/**
* @typedef {Object} Post
* @property {string} [title] - The title of the post.
* @property {string} [content] - The content of the post.
* @property {string} type - The type of the post.
* @property {number} id - The ID of the post.
* @property {number} [author] - The author ID of the post.
* @property {string} [status] - The status of the post.
*/

/**
* Retrieves the current post data from the GBKit global.
*
* @return {Post} The post object containing the following properties:
*/
export function getPost() {
const { post } = getGBKit();
if (post) {
Expand Down

0 comments on commit 4f18999

Please sign in to comment.