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

Add VBE editor injector #86123

Merged
merged 22 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ cached-requests.json
/packages/*/dist/
/build-tools/dist/
/apps/*/.cache/
/packages/*/.cache/
/desktop/.cache/
/apps/*/release-files/
/apps/**/*/build_meta.json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@ const CommentBlockEditor = ( {

useEffect( () => {
if ( siteId ) {
addApiMiddleware( siteId );
addApiMiddleware( ( url ) => ( {
path: `/sites/${ encodeURIComponent( siteId ) }/proxy`,
query: `url=${ encodeURIComponent( url ) }`,
apiNamespace: 'oembed/1.0',
} ) );
}
}, [ siteId ] );

return (
<div className="editor__wrapper">
<div className="verbum-editor-wrapper">
<Editor initialContent={ commentContent } onChange={ onChange } isRTL={ isRTL } />
</div>
);
Expand Down
34 changes: 27 additions & 7 deletions packages/verbum-block-editor/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
# Verbum Block Editor

Verbum Block Editor is a lightweight Gutenberg editor designed specifically for comments. It provides a simplified and intuitive interface for users to compose and format their comments effortlessly.
Verbum Block Editor is a lightweight Gutenberg editor, tailored specifically for enhancing the commenting experience. It offers a user-friendly interface, enabling effortless composition and formatting of comments.

## Features

- Autofocus on the last block when the empty white space is clicked.
- Autofocus on the first paragraph on load.
- Handles embeds by adding all the needed API middlewares.
- Uses and iframed editor to limit CSS collisions.
- Automatically focuses on the last block when clicking on any empty white space.
- Initial focus is set to the first paragraph upon loading.
- Efficiently handles embeds by integrating all necessary API middlewares.
- Incorporates an iframed editor to minimize CSS collisions.

## WIP
Soon, this will be published on NPM and used everywhere a user can edit comments (in Verbum and in Calypso's `/comments/all/` page).
## Development

This package can be utilized in two primary ways:

### Directly In Calypso
- The package is directly integrated into Calypso as a standard package.
- No separate build process is required after modifications.
- Direct file alterations are reflected immediately in Calypso.

### Via widgets.wp.com
- The package publishes a bundle on widgets.wp.com for broader accessibility.
- Development process:
1. Navigate to the package's directory: `cd package/verbum-block-editor`.
2. Execute `yarn dev --sync`.
3. Changes are synchronized to `/home/wpcom/public_html/widgets.wp.com/verbum-block-editor` on your sandbox.

### Deploying Changes

To deploy modifications to the package:
1. Ensure your sandbox is in a clean git state.
2. Run `yarn build --sync`.
3. Create a patch.
4. Deploy the patch.
8 changes: 5 additions & 3 deletions packages/verbum-block-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@
"bugs": "https://github.com/Automattic/wp-calypso/issues",
"types": "dist/types",
"scripts": {
"clean": "tsc --build ./tsconfig.json ./tsconfig-cjs.json --clean && rm -rf dist",
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json && copy-assets",
"prepack": "yarn run clean && yarn run build",
"clean": "rm -rf dist",
"build": "NODE_ENV=production yarn dev",
"build:app": "calypso-build",
"dev": "yarn run calypso-apps-builder --localPath dist --remotePath /home/wpcom/public_html/widgets.wp.com/verbum-block-editor",
"watch": "tsc --build ./tsconfig.json --watch",
"prepare": "yarn build"
},
"dependencies": {
"@automattic/calypso-apps-builder": "workspace:^",
"@types/wordpress__block-editor": "^11.5.8",
"@wordpress/base-styles": "^4.39.0",
"@wordpress/block-editor": "^12.16.0",
Expand Down
19 changes: 13 additions & 6 deletions packages/verbum-block-editor/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,26 @@ function createFallbackResponse( url: string ) {
};
}

export function addApiMiddleware( siteId: number ) {
export type EmbedRequestParams = {
path: string;
query: string;
apiNamespace: string;
};

export function addApiMiddleware(
requestParamsGenerator: ( embedURL: string ) => EmbedRequestParams
) {
apiFetch.setFetchHandler( ( options ) => {
const { path } = options;

if ( path?.startsWith( '/oembed/1.0/proxy' ) ) {
const url = new URL( 'https://wordpress.com' + path );
const embedUrl = url.searchParams.get( 'url' );

return wpcomRequest( {
path: `/sites/${ encodeURIComponent( siteId ) }/proxy`,
query: `url=${ embedUrl }`,
apiNamespace: 'oembed/1.0',
} );
if ( embedUrl ) {
return wpcomRequest( requestParamsGenerator( embedUrl ) );
}
return Promise.reject( new Error( 'Invalid embed URL' ) );
}

return defaultFetchHandler( options );
Expand Down
138 changes: 76 additions & 62 deletions packages/verbum-block-editor/src/editor/editor-style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,95 +4,109 @@
@import "@wordpress/block-editor/build-style/style";
@import "@wordpress/block-editor/build-style/content.css";

.editor__wrapper {
.verbum-editor-wrapper {
width: 100%;
padding: 0 10px;
box-sizing: border-box;
}

.editor__header {
top: 0;
overflow: hidden;
position: sticky;
display: grid;
grid-template-rows: 0fr;
border: 1px solid var(--color-neutral-0);
// Avoid double border.
border-bottom: none;

&.is-editing {
overflow: visible;
grid-template-rows: 1fr;
transition: all 0.5s 0.5s ease-in-out;
}

@at-root body.admin-bar & {
top: 32px;
}

.editor__header-wrapper {
display: flex;
.editor__header {
top: 0;
overflow: hidden;
justify-content: space-between;
align-items: center;
position: sticky;
display: grid;
border: 1px solid var(--color-neutral-0);
// Avoid double border.
border-bottom: none;

&.is-editing {
overflow: visible;
}

.editor__header-toolbar {
flex-grow: 1;
@at-root body.admin-bar & {
top: 32px;
}

.block-editor-block-toolbar {
.editor__header-wrapper {
display: flex;
overflow: hidden;
justify-content: space-between;
align-items: center;
min-height: 52px;
border-bottom: solid 1px #dcdcde;

.editor__header-toolbar {
flex-grow: 1;

.block-editor-block-settings-menu,
button:disabled {
display: none;
.block-editor-block-contextual-toolbar.components-accessible-toolbar {
border-bottom: none;
}

.block-editor-block-parent-selector {
background-color: transparent;
.block-editor-block-toolbar {

.block-editor-block-settings-menu,
button:disabled {
display: none;
}

.block-editor-block-parent-selector {
background-color: transparent;

button.block-editor-block-parent-selector__button {
border: none;
button.block-editor-block-parent-selector__button {
border: none;
}
}
}
}
}

.block-editor-inserter {
padding: 5px 8px;
.block-editor-inserter {
padding: 5px 8px;

.block-editor-inserter__toggle {
svg {
margin: auto;
.block-editor-inserter__toggle {
svg {
margin: auto;
}
}
}
}

.block-editor-media-placeholder__url-input-form {
display: flex;
box-sizing: border-box;
}
.block-editor-media-placeholder__url-input-form {
display: flex;
box-sizing: border-box;
}

.block-editor-media-flow__url-input {
border-top: 1px solid #1e1e1e;
margin-top: -9px;
padding: 8px 16px;
.block-editor-media-flow__url-input {
border-top: 1px solid #1e1e1e;
margin-top: -9px;
padding: 8px 16px;

.block-editor-media-replace-flow__image-url-label {
display: block;
margin-bottom: 8px;
font-size: 13px;
}
.block-editor-media-replace-flow__image-url-label {
display: block;
margin-bottom: 8px;
font-size: 13px;
}

.block-editor-link-control {
width: 300px;
.block-editor-link-control {
width: 300px;
}
}
}
}
}

.editor__main {
border: solid 1px var(--color-neutral-0);
margin-bottom: 10px;
.editor__main {
border: 1px solid var(--color-neutral-0);
margin-bottom: 10px;
&.loading-placeholder {
&.loading {
display: flex;
justify-content: center;
align-items: center;
}
}

&,
& iframe {
min-height: 140px;
}
}
}


Expand Down
45 changes: 24 additions & 21 deletions packages/verbum-block-editor/src/editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import {
store as blockEditorStore,
// @ts-expect-error - Typings missing
} from '@wordpress/block-editor';
import { parse } from '@wordpress/blocks';
import { createBlock, serialize, type BlockInstance } from '@wordpress/blocks';
import { Popover, SlotFillProvider, KeyboardShortcuts } from '@wordpress/components';
import { useStateWithHistory, useResizeObserver } from '@wordpress/compose';
import { useDispatch } from '@wordpress/data';
import { useState, useEffect, useCallback } from '@wordpress/element';
import React, { useState, useEffect, useCallback } from '@wordpress/element';
import { rawShortcut } from '@wordpress/keycodes';
import classNames from 'classnames';
import { safeParse } from '../utils';
import { editorSettings } from './editor-settings';
import { EditorProps, StateWithUndoManager } from './editor-types';
import type { MouseEvent, KeyboardEvent } from 'react';
import type { MouseEvent, KeyboardEvent, FC } from 'react';
import css from '!!css-loader!sass-loader!./inline-iframe-style.scss';
import './editor-style.scss';

Expand All @@ -28,14 +28,16 @@ const iframedCSS = css.reduce( ( css: string, [ , item ]: [ string, string ] ) =
/**
* Editor component
*/
export const Editor: React.FC< EditorProps > = ( { initialContent = '', onChange, isRTL } ) => {
export const Editor: FC< EditorProps > = ( { initialContent = '', onChange, isRTL } ) => {
// We keep the content in state so we can access the blocks in the editor.
const {
value: editorContent,
setValue,
undo,
redo,
} = useStateWithHistory( parse( initialContent ) ) as unknown as StateWithUndoManager;
} = useStateWithHistory(
initialContent !== '' ? safeParse( initialContent ) : [ createBlock( 'core/paragraph' ) ]
) as unknown as StateWithUndoManager;
const [ isEditing, setIsEditing ] = useState( false );

const handleContentUpdate = useCallback(
Expand All @@ -53,26 +55,27 @@ export const Editor: React.FC< EditorProps > = ( { initialContent = '', onChange

const selectLastBlock = ( event?: MouseEvent | KeyboardEvent ) => {
const lastBlock = editorContent[ editorContent.length - 1 ];
if ( lastBlock ) {
// If this is a click event only shift focus if the click is in the root.
// We don't want to shift focus if the click is in a block.
if ( event ) {
if ( ( event.target as HTMLDivElement ).dataset.isDropZone ) {
// If the last block isn't a paragraph, add a new one.
// This allows the user to add text after a non-text block without clicking the inserter.
if ( lastBlock.name !== 'core/paragraph' ) {
const newParagraph = createBlock( 'core/paragraph' );
handleContentUpdate( [ ...editorContent, newParagraph ] );
selectBlock( newParagraph.clientId );
}

// If this is a click event only shift focus if the click is in the root.
// We don't want to shift focus if the click is in a block.
if ( event ) {
if ( ( event.target as HTMLDivElement ).dataset.isDropZone ) {
// If the last block isn't a paragraph, add a new one.
// This allows the user to add text after a non-text block without clicking the inserter.
if ( lastBlock.name !== 'core/paragraph' ) {
const newParagraph = createBlock( 'core/paragraph' );
handleContentUpdate( [ ...editorContent, newParagraph ] );
selectBlock( newParagraph.clientId );
selectBlock( lastBlock.clientId );
} else {
return;
}

selectBlock( lastBlock.clientId );
} else {
return;
}
}

selectBlock( lastBlock.clientId );
selectBlock( lastBlock.clientId );
}
};

useEffect( () => {
Expand Down
1 change: 1 addition & 0 deletions packages/verbum-block-editor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { Editor } from './editor';
export { loadTextFormatting } from './load-text-formatting';
export { loadBlocksWithCustomizations } from './load-blocks';
export { addApiMiddleware } from './api';
export { attachGutenberg } from './text-area-injector';
Loading
Loading