From f7e5f31ebdb78da3dc35dc4f495bf52f4674e92c Mon Sep 17 00:00:00 2001 From: Francis Gyimah Date: Tue, 8 Aug 2023 09:13:29 +0000 Subject: [PATCH 01/11] [DEV-11237] Added with WithButtons story in storybook --- .../src/modules/editor/Editor.stories.tsx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/slate-editor/src/modules/editor/Editor.stories.tsx b/packages/slate-editor/src/modules/editor/Editor.stories.tsx index 1276fdf78..dc52b2aad 100644 --- a/packages/slate-editor/src/modules/editor/Editor.stories.tsx +++ b/packages/slate-editor/src/modules/editor/Editor.stories.tsx @@ -113,3 +113,34 @@ WithVariables.args = { ], }, } as IBaseProps & { withVariables?: VariablesExtensionParameters }; + +export const WithButtons = () => { + const [value, setValue] = useState(createEmptyValue()); + + return ( + + ); +}; From ef327bb4d9b91372c2993dd4a2f912f2287d1301 Mon Sep 17 00:00:00 2001 From: Francis Gyimah Date: Tue, 8 Aug 2023 10:37:17 +0000 Subject: [PATCH 02/11] [DEV-11237] Added ButtonBlock extension --- .../button-block/ButtonBlockExtension.tsx | 37 +++++++++++++++++++ .../button-block/ButtonBlockNode.ts | 35 ++++++++++++++++++ .../src/extensions/button-block/index.ts | 3 ++ .../button-block/lib/createButtonBlock.ts | 27 ++++++++++++++ .../src/extensions/button-block/lib/index.ts | 4 ++ .../button-block/lib/insertButtonBlock.ts | 17 +++++++++ ...normalizeRedundantButtonBlockAttributes.ts | 32 ++++++++++++++++ .../lib/parseSerializedButtonBlockElement.ts | 13 +++++++ .../src/modules/editor/Editor.stories.tsx | 18 +++------ .../src/modules/editor/Editor.tsx | 9 +++++ .../modules/editor/getEnabledExtensions.ts | 8 ++++ .../src/modules/editor/menuOptions.tsx | 14 +++++++ .../src/modules/editor/test-utils.ts | 1 + .../slate-editor/src/modules/editor/types.ts | 2 + .../queries/isAllowedOnTopLevel.ts | 2 + 15 files changed, 210 insertions(+), 12 deletions(-) create mode 100644 packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx create mode 100644 packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts create mode 100644 packages/slate-editor/src/extensions/button-block/index.ts create mode 100644 packages/slate-editor/src/extensions/button-block/lib/createButtonBlock.ts create mode 100644 packages/slate-editor/src/extensions/button-block/lib/index.ts create mode 100644 packages/slate-editor/src/extensions/button-block/lib/insertButtonBlock.ts create mode 100644 packages/slate-editor/src/extensions/button-block/lib/normalizeRedundantButtonBlockAttributes.ts create mode 100644 packages/slate-editor/src/extensions/button-block/lib/parseSerializedButtonBlockElement.ts diff --git a/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx b/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx new file mode 100644 index 000000000..522f32d75 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx @@ -0,0 +1,37 @@ +import { createDeserializeElement, type Extension } from '@prezly/slate-commons'; +import React from 'react'; +import type { RenderElementProps } from 'slate-react'; + +import { composeElementDeserializer } from '#modules/html-deserialization'; + +import { ButtonBlockNode } from './ButtonBlockNode'; +import { normalizeRedundantButtonBlockAttributes, parseSerializedButtonBlockElement } from './lib'; + +export const EXTENSION_ID = 'ButtonBlockExtension'; + +export interface ButtonBlockExtensionConfiguration { + withNewTabOption?: boolean; +} + +export function ButtonBlockExtension({ + withNewTabOption = false, +}: ButtonBlockExtensionConfiguration): Extension { + return { + id: EXTENSION_ID, + deserialize: { + element: composeElementDeserializer({ + [ButtonBlockNode.Type]: createDeserializeElement(parseSerializedButtonBlockElement), + }), + }, + normalizeNode: normalizeRedundantButtonBlockAttributes, + renderElement: ({ attributes, children, element }: RenderElementProps) => { + if (ButtonBlockNode.isButtonBlockNode(element)) { + console.log(JSON.stringify({ element, withNewTabOption })); + return
{children}
; + } + + return undefined; + }, + isVoid: ButtonBlockNode.isButtonBlockNode, + }; +} diff --git a/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts b/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts new file mode 100644 index 000000000..386ef0fe7 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts @@ -0,0 +1,35 @@ +import type { ElementNode } from '@prezly/slate-types'; +import { isElementNode } from '@prezly/slate-types'; +import type { Node } from 'slate'; + +type Uuid = string; + +export interface ButtonBlockNode extends ElementNode { + type: typeof ButtonBlockNode.Type; + uuid: Uuid; + href: string; + layout: ButtonBlockNode.Layout; + variant: ButtonBlockNode.Variant; + new_tab: boolean; + text: string; +} + +export namespace ButtonBlockNode { + export const Type = 'button-block'; + + export enum Layout { + LEFT = 'left', + RIGHT = 'right', + CENTER = 'center', + FULL_WIDTH = 'full-width', + } + + export enum Variant { + DEFAULT = 'default', + OUTLINE = 'outline', + } + + export function isButtonBlockNode(node: Node): node is ButtonBlockNode { + return isElementNode(node, Type); + } +} diff --git a/packages/slate-editor/src/extensions/button-block/index.ts b/packages/slate-editor/src/extensions/button-block/index.ts new file mode 100644 index 000000000..441bc34f7 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/index.ts @@ -0,0 +1,3 @@ +export * from './ButtonBlockExtension'; +export * from './ButtonBlockNode'; +export { insertButtonBlock } from './lib'; diff --git a/packages/slate-editor/src/extensions/button-block/lib/createButtonBlock.ts b/packages/slate-editor/src/extensions/button-block/lib/createButtonBlock.ts new file mode 100644 index 000000000..3fc69a915 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/lib/createButtonBlock.ts @@ -0,0 +1,27 @@ +import { v4 as generateUuid } from 'uuid'; + +import { ButtonBlockNode } from '../ButtonBlockNode'; + +export function createButtonBlock( + props: Partial>, +): ButtonBlockNode { + const { + href = '', + new_tab = false, + layout = ButtonBlockNode.Layout.CENTER, + variant = ButtonBlockNode.Variant.DEFAULT, + uuid = generateUuid(), + text = 'Click me!', + } = props; + + return { + href, + layout, + new_tab, + text, + type: ButtonBlockNode.Type, + uuid, + variant, + children: [{ text: '' }], + }; +} diff --git a/packages/slate-editor/src/extensions/button-block/lib/index.ts b/packages/slate-editor/src/extensions/button-block/lib/index.ts new file mode 100644 index 000000000..94aed4cce --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/lib/index.ts @@ -0,0 +1,4 @@ +export * from './normalizeRedundantButtonBlockAttributes'; +export * from './parseSerializedButtonBlockElement'; +export * from './createButtonBlock'; +export * from './insertButtonBlock'; diff --git a/packages/slate-editor/src/extensions/button-block/lib/insertButtonBlock.ts b/packages/slate-editor/src/extensions/button-block/lib/insertButtonBlock.ts new file mode 100644 index 000000000..6b2efec3c --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/lib/insertButtonBlock.ts @@ -0,0 +1,17 @@ +import { EditorCommands } from '@prezly/slate-commons'; +import type { Editor } from 'slate'; + +import type { ButtonBlockNode } from '../ButtonBlockNode'; + +import { createButtonBlock } from './createButtonBlock'; + +export function insertButtonBlock( + editor: Editor, + props: Partial> = {}, +) { + const button = createButtonBlock(props); + + EditorCommands.insertNodes(editor, [button], { ensureEmptyParagraphAfter: true }); + + return button; +} diff --git a/packages/slate-editor/src/extensions/button-block/lib/normalizeRedundantButtonBlockAttributes.ts b/packages/slate-editor/src/extensions/button-block/lib/normalizeRedundantButtonBlockAttributes.ts new file mode 100644 index 000000000..091d82225 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/lib/normalizeRedundantButtonBlockAttributes.ts @@ -0,0 +1,32 @@ +import { EditorCommands } from '@prezly/slate-commons'; +import type { Editor, Node, NodeEntry } from 'slate'; + +import { ButtonBlockNode } from '../ButtonBlockNode'; + +const shape: Record = { + type: true, + href: true, + new_tab: true, + children: true, + layout: true, + variant: true, + text: true, + uuid: true, +}; + +const ALLOWED_BUTTON_BLOCK_ATTRIBUTES = Object.keys(shape); + +export function normalizeRedundantButtonBlockAttributes( + editor: Editor, + [node, path]: NodeEntry, +) { + if (ButtonBlockNode.isButtonBlockNode(node)) { + return EditorCommands.normalizeRedundantAttributes( + editor, + [node, path], + ALLOWED_BUTTON_BLOCK_ATTRIBUTES, + ); + } + + return false; +} diff --git a/packages/slate-editor/src/extensions/button-block/lib/parseSerializedButtonBlockElement.ts b/packages/slate-editor/src/extensions/button-block/lib/parseSerializedButtonBlockElement.ts new file mode 100644 index 000000000..c387dc5b5 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/lib/parseSerializedButtonBlockElement.ts @@ -0,0 +1,13 @@ +import { ButtonBlockNode } from '../ButtonBlockNode'; + +import { createButtonBlock } from './createButtonBlock'; + +export function parseSerializedButtonBlockElement(serialized: string): ButtonBlockNode | undefined { + const parsed = JSON.parse(serialized); + + if (ButtonBlockNode.isButtonBlockNode(parsed)) { + return createButtonBlock(parsed); + } + + return undefined; +} diff --git a/packages/slate-editor/src/modules/editor/Editor.stories.tsx b/packages/slate-editor/src/modules/editor/Editor.stories.tsx index dc52b2aad..8e00cb71d 100644 --- a/packages/slate-editor/src/modules/editor/Editor.stories.tsx +++ b/packages/slate-editor/src/modules/editor/Editor.stories.tsx @@ -119,28 +119,22 @@ export const WithButtons = () => { return ( ); }; diff --git a/packages/slate-editor/src/modules/editor/Editor.tsx b/packages/slate-editor/src/modules/editor/Editor.tsx index b3493dcc2..97c6e0efa 100644 --- a/packages/slate-editor/src/modules/editor/Editor.tsx +++ b/packages/slate-editor/src/modules/editor/Editor.tsx @@ -29,6 +29,7 @@ import { ReactEditor, Slate } from 'slate-react'; import { useFunction, useGetSet, useSize } from '#lib'; +import { insertButtonBlock } from '#extensions/button-block'; import { FlashNodes } from '#extensions/flash-nodes'; import { FloatingAddMenu } from '#extensions/floating-add-menu'; import type { Option } from '#extensions/floating-add-menu'; @@ -86,6 +87,7 @@ export const Editor = forwardRef((props, forwardedRef) = withAttachments = false, withAutoformat = false, withBlockquotes = false, + withButtonBlocks = false, withCoverage = false, withCursorInView = false, withCustomNormalization = false, @@ -145,6 +147,7 @@ export const Editor = forwardRef((props, forwardedRef) = withAttachments, withAutoformat, withBlockquotes, + withButtonBlocks, withCoverage, withCustomNormalization, withDivider, @@ -305,6 +308,7 @@ export const Editor = forwardRef((props, forwardedRef) = const menuOptions = generateFloatingAddMenuOptions(editor, { withAttachments, withBlockquotes, + withButtonBlocks: Boolean(withButtonBlocks), withCoverage: Boolean(withCoverage), withDivider, withTables: Boolean(withTables), @@ -351,6 +355,11 @@ export const Editor = forwardRef((props, forwardedRef) = EditorCommands.selectNode(editor, placeholder); return; } + if (action === MenuAction.ADD_BUTTON_BLOCK) { + const button = insertButtonBlock(editor); + EditorCommands.selectNode(editor, button); + return; + } if (action === MenuAction.ADD_CONTACT) { const placeholder = insertPlaceholder( editor, diff --git a/packages/slate-editor/src/modules/editor/getEnabledExtensions.ts b/packages/slate-editor/src/modules/editor/getEnabledExtensions.ts index ee2edc3cb..a663f57f5 100644 --- a/packages/slate-editor/src/modules/editor/getEnabledExtensions.ts +++ b/packages/slate-editor/src/modules/editor/getEnabledExtensions.ts @@ -5,6 +5,7 @@ import { noop } from '@technically/lodash'; import { AllowedBlocksExtension } from '#extensions/allowed-blocks'; import { AutoformatExtension } from '#extensions/autoformat'; import { BlockquoteExtension } from '#extensions/blockquote'; +import { ButtonBlockExtension } from '#extensions/button-block'; import { CoverageExtension } from '#extensions/coverage'; import { CustomNormalizationExtension } from '#extensions/custom-normalization'; import { DecorateSelectionExtension } from '#extensions/decorate-selection'; @@ -70,6 +71,7 @@ type Parameters = { | 'withAttachments' | 'withAutoformat' | 'withBlockquotes' + | 'withButtonBlocks' | 'withCoverage' | 'withCustomNormalization' | 'withDivider' @@ -104,6 +106,7 @@ export function* getEnabledExtensions(parameters: Parameters): Generator Date: Tue, 8 Aug 2023 16:08:00 +0300 Subject: [PATCH 03/11] [DEV-11237] Fix Babel transpilation of Typescript namespaces See https://babeljs.io/docs/babel-plugin-transform-typescript#impartial-namespace-support --- .../slate-editor/src/components/SearchInput/SearchInput.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/slate-editor/src/components/SearchInput/SearchInput.tsx b/packages/slate-editor/src/components/SearchInput/SearchInput.tsx index e86f00dfe..8eb339d3d 100644 --- a/packages/slate-editor/src/components/SearchInput/SearchInput.tsx +++ b/packages/slate-editor/src/components/SearchInput/SearchInput.tsx @@ -163,7 +163,8 @@ export namespace SearchInput { onSelect: (suggestion: Suggestion) => void; } - export namespace Props { + // Note: using `declare` here to not confuse Babel. @see https://babeljs.io/docs/babel-plugin-transform-typescript#impartial-namespace-support + export declare namespace Props { export interface Empty { query: string; loading: boolean; From 0a227b766fb19bafa3c948d04406f3e3f5aca777 Mon Sep 17 00:00:00 2001 From: Francis Gyimah Date: Tue, 8 Aug 2023 14:00:18 +0000 Subject: [PATCH 04/11] [DEV-11237] Changed ButtonNode text property to label --- .../src/extensions/button-block/ButtonBlockExtension.tsx | 8 ++++++-- .../src/extensions/button-block/ButtonBlockNode.ts | 2 +- .../src/extensions/button-block/lib/createButtonBlock.ts | 4 ++-- .../lib/normalizeRedundantButtonBlockAttributes.ts | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx b/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx index 522f32d75..72eec023a 100644 --- a/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx +++ b/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx @@ -26,8 +26,12 @@ export function ButtonBlockExtension({ normalizeNode: normalizeRedundantButtonBlockAttributes, renderElement: ({ attributes, children, element }: RenderElementProps) => { if (ButtonBlockNode.isButtonBlockNode(element)) { - console.log(JSON.stringify({ element, withNewTabOption })); - return
{children}
; + return ( +
+                        {JSON.stringify({ element, withNewTabOption })}
+                        {children}
+                    
+ ); } return undefined; diff --git a/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts b/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts index 386ef0fe7..fcfb9b28c 100644 --- a/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts +++ b/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts @@ -11,7 +11,7 @@ export interface ButtonBlockNode extends ElementNode { layout: ButtonBlockNode.Layout; variant: ButtonBlockNode.Variant; new_tab: boolean; - text: string; + label: string; } export namespace ButtonBlockNode { diff --git a/packages/slate-editor/src/extensions/button-block/lib/createButtonBlock.ts b/packages/slate-editor/src/extensions/button-block/lib/createButtonBlock.ts index 3fc69a915..35e2de68b 100644 --- a/packages/slate-editor/src/extensions/button-block/lib/createButtonBlock.ts +++ b/packages/slate-editor/src/extensions/button-block/lib/createButtonBlock.ts @@ -11,14 +11,14 @@ export function createButtonBlock( layout = ButtonBlockNode.Layout.CENTER, variant = ButtonBlockNode.Variant.DEFAULT, uuid = generateUuid(), - text = 'Click me!', + label = 'Click me!', } = props; return { href, layout, new_tab, - text, + label, type: ButtonBlockNode.Type, uuid, variant, diff --git a/packages/slate-editor/src/extensions/button-block/lib/normalizeRedundantButtonBlockAttributes.ts b/packages/slate-editor/src/extensions/button-block/lib/normalizeRedundantButtonBlockAttributes.ts index 091d82225..11ca78168 100644 --- a/packages/slate-editor/src/extensions/button-block/lib/normalizeRedundantButtonBlockAttributes.ts +++ b/packages/slate-editor/src/extensions/button-block/lib/normalizeRedundantButtonBlockAttributes.ts @@ -10,7 +10,7 @@ const shape: Record = { children: true, layout: true, variant: true, - text: true, + label: true, uuid: true, }; From d67667467201898315275321523c4aa9cc82ea67 Mon Sep 17 00:00:00 2001 From: Francis Gyimah Date: Wed, 9 Aug 2023 11:30:18 +0000 Subject: [PATCH 05/11] [DEV-11237] Updated Button icon and copy in editor options --- .../src/icons/Component-Button.svg | 4 ++++ packages/slate-editor/src/icons/index.ts | 1 + .../src/modules/editor/menuOptions.tsx | 20 ++++++++++--------- 3 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 packages/slate-editor/src/icons/Component-Button.svg diff --git a/packages/slate-editor/src/icons/Component-Button.svg b/packages/slate-editor/src/icons/Component-Button.svg new file mode 100644 index 000000000..7994ded68 --- /dev/null +++ b/packages/slate-editor/src/icons/Component-Button.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/packages/slate-editor/src/icons/index.ts b/packages/slate-editor/src/icons/index.ts index 340105b90..292342147 100644 --- a/packages/slate-editor/src/icons/index.ts +++ b/packages/slate-editor/src/icons/index.ts @@ -14,6 +14,7 @@ export { default as Dice } from './Dice.svg'; export { default as Download } from './Download.svg'; export { default as Embed } from './Embed.svg'; export { default as ComponentAttachment } from './Component-Attachment.svg'; +export { default as ComponentButton } from './Component-Button.svg'; export { default as ComponentContact } from './Component-Contact.svg'; export { default as ComponentCoverage } from './Component-Coverage.svg'; export { default as ComponentDivider } from './Component-Divider.svg'; diff --git a/packages/slate-editor/src/modules/editor/menuOptions.tsx b/packages/slate-editor/src/modules/editor/menuOptions.tsx index 86be00f34..2ffd41e17 100644 --- a/packages/slate-editor/src/modules/editor/menuOptions.tsx +++ b/packages/slate-editor/src/modules/editor/menuOptions.tsx @@ -59,11 +59,12 @@ interface Params { */ const Suggested: Partial> = { [MenuAction.ADD_IMAGE]: 1, - [MenuAction.ADD_CONTACT]: 2, - [MenuAction.ADD_GALLERY]: 3, - [MenuAction.ADD_DIVIDER]: 4, - [MenuAction.ADD_ATTACHMENT]: 5, - [MenuAction.ADD_SNIPPET]: 5, + [MenuAction.ADD_BUTTON_BLOCK]: 2, + [MenuAction.ADD_CONTACT]: 3, + [MenuAction.ADD_GALLERY]: 4, + [MenuAction.ADD_DIVIDER]: 5, + [MenuAction.ADD_ATTACHMENT]: 6, + [MenuAction.ADD_SNIPPET]: 7, }; export function generateFloatingAddMenuOptions( @@ -151,11 +152,12 @@ function* generateOptions( if (withButtonBlocks) { yield { action: MenuAction.ADD_BUTTON_BLOCK, - icon: Icons.ComponentSnippet, + icon: Icons.ComponentButton, group: Group.TEXT_N_LAYOUT, - // TODO: update copy - text: 'Call to action', - description: 'Insert a call to action', + text: 'Button', + description: 'Insert a button', + keywords: ['cta', 'call to action', 'calltoaction'], + isNew: true, }; } From ec22c2b3c71066f78f3543f01a8aeaeacbed92d3 Mon Sep 17 00:00:00 2001 From: Francis Gyimah Date: Wed, 9 Aug 2023 12:50:28 +0000 Subject: [PATCH 06/11] [DEV-11237] Updated button block design in editor --- .../components/EditorBlock/EditorBlock.tsx | 2 +- .../button-block/ButtonBlockExtension.tsx | 10 +++-- .../button-block/ButtonBlockNode.ts | 28 ++++++++------ .../components/Button/Button.module.scss | 37 +++++++++++++++++++ .../button-block/components/Button/Button.tsx | 26 +++++++++++++ .../button-block/components/Button/index.ts | 1 + .../components/ButtonBlockElement.tsx | 36 ++++++++++++++++++ .../button-block/components/index.ts | 1 + .../button-block/lib/createButtonBlock.ts | 6 +-- 9 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 packages/slate-editor/src/extensions/button-block/components/Button/Button.module.scss create mode 100644 packages/slate-editor/src/extensions/button-block/components/Button/Button.tsx create mode 100644 packages/slate-editor/src/extensions/button-block/components/Button/index.ts create mode 100644 packages/slate-editor/src/extensions/button-block/components/ButtonBlockElement.tsx create mode 100644 packages/slate-editor/src/extensions/button-block/components/index.ts diff --git a/packages/slate-editor/src/components/EditorBlock/EditorBlock.tsx b/packages/slate-editor/src/components/EditorBlock/EditorBlock.tsx index b63aac23c..0dce7b8e0 100644 --- a/packages/slate-editor/src/components/EditorBlock/EditorBlock.tsx +++ b/packages/slate-editor/src/components/EditorBlock/EditorBlock.tsx @@ -35,7 +35,7 @@ export interface RenderProps { export interface Props extends Omit, SlateInternalAttributes { - align?: Alignment; + align?: `${Alignment}`; border?: boolean; className?: string; element: ElementNode; diff --git a/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx b/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx index 72eec023a..999aed29b 100644 --- a/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx +++ b/packages/slate-editor/src/extensions/button-block/ButtonBlockExtension.tsx @@ -5,6 +5,7 @@ import type { RenderElementProps } from 'slate-react'; import { composeElementDeserializer } from '#modules/html-deserialization'; import { ButtonBlockNode } from './ButtonBlockNode'; +import { ButtonBlockElement } from './components'; import { normalizeRedundantButtonBlockAttributes, parseSerializedButtonBlockElement } from './lib'; export const EXTENSION_ID = 'ButtonBlockExtension'; @@ -27,10 +28,13 @@ export function ButtonBlockExtension({ renderElement: ({ attributes, children, element }: RenderElementProps) => { if (ButtonBlockNode.isButtonBlockNode(element)) { return ( -
-                        {JSON.stringify({ element, withNewTabOption })}
+                    
                         {children}
-                    
+ ); } diff --git a/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts b/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts index fcfb9b28c..03cc177f7 100644 --- a/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts +++ b/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts @@ -8,26 +8,30 @@ export interface ButtonBlockNode extends ElementNode { type: typeof ButtonBlockNode.Type; uuid: Uuid; href: string; - layout: ButtonBlockNode.Layout; - variant: ButtonBlockNode.Variant; + layout: ButtonBlockNode.ButtonLayout; + variant: ButtonBlockNode.ButtonVariant; new_tab: boolean; label: string; } +enum Layout { + LEFT = 'left', + RIGHT = 'right', + CENTER = 'center', + FULL_WIDTH = 'full-width', +} + +enum Variant { + DEFAULT = 'default', + OUTLINE = 'outline', +} + export namespace ButtonBlockNode { export const Type = 'button-block'; - export enum Layout { - LEFT = 'left', - RIGHT = 'right', - CENTER = 'center', - FULL_WIDTH = 'full-width', - } + export type ButtonLayout = `${Layout}`; - export enum Variant { - DEFAULT = 'default', - OUTLINE = 'outline', - } + export type ButtonVariant = `${Variant}`; export function isButtonBlockNode(node: Node): node is ButtonBlockNode { return isElementNode(node, Type); diff --git a/packages/slate-editor/src/extensions/button-block/components/Button/Button.module.scss b/packages/slate-editor/src/extensions/button-block/components/Button/Button.module.scss new file mode 100644 index 000000000..db8233704 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/components/Button/Button.module.scss @@ -0,0 +1,37 @@ +@import "styles/variables"; +@import "styles/helpers"; + +.Button { + @include btn-unstyled; + + display: flex; + padding: $spacing-1-5 $spacing-2; + justify-content: center; + align-items: center; + border-radius: $border-radius-small; + width: max-content; + color: $white; + background-color: $indigo-400; + font-size: $font-size-medium; + font-weight: 600; + line-height: 160%; + + &.active { + background-color: $indigo-600; + } + + &.outline { + border: 2px solid $indigo-400; + color: $indigo-400; + background-color: $white; + + &.active { + color: $indigo-600; + border-color: $indigo-600; + } + } + + &.fullWidth { + width: 100%; + } +} diff --git a/packages/slate-editor/src/extensions/button-block/components/Button/Button.tsx b/packages/slate-editor/src/extensions/button-block/components/Button/Button.tsx new file mode 100644 index 000000000..98533db37 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/components/Button/Button.tsx @@ -0,0 +1,26 @@ +import classNames from 'classnames'; +import React from 'react'; + +import type { ButtonBlockNode } from '../../ButtonBlockNode'; + +import styles from './Button.module.scss'; + +interface Props { + node: ButtonBlockNode; +} + +export function Button({ node }: Props) { + const { label, variant, layout, href } = node; + + return ( + + ); +} diff --git a/packages/slate-editor/src/extensions/button-block/components/Button/index.ts b/packages/slate-editor/src/extensions/button-block/components/Button/index.ts new file mode 100644 index 000000000..8b166a86e --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/components/Button/index.ts @@ -0,0 +1 @@ +export * from './Button'; diff --git a/packages/slate-editor/src/extensions/button-block/components/ButtonBlockElement.tsx b/packages/slate-editor/src/extensions/button-block/components/ButtonBlockElement.tsx new file mode 100644 index 000000000..43b2f3609 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/components/ButtonBlockElement.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import type { RenderElementProps } from 'slate-react'; + +import { EditorBlock } from '#components'; + +import type { ButtonBlockNode } from '../ButtonBlockNode'; + +import { Button } from './Button/Button'; + +interface Props extends RenderElementProps { + element: ButtonBlockNode; + withNewTabOption: boolean; +} + +export function ButtonBlockElement({ attributes, children, element }: Props) { + const { layout: buttonLayout } = element; + + const align = buttonLayout === 'full-width' ? 'center' : buttonLayout; + const layout = buttonLayout === 'full-width' ? 'full-width' : 'contained'; + + return ( + + + + ); +} diff --git a/packages/slate-editor/src/extensions/button-block/transforms/index.ts b/packages/slate-editor/src/extensions/button-block/transforms/index.ts new file mode 100644 index 000000000..df79363f5 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/transforms/index.ts @@ -0,0 +1,2 @@ +export * from './removeButtonBlock'; +export * from './updateButtonBlock'; diff --git a/packages/slate-editor/src/extensions/button-block/transforms/removeButtonBlock.ts b/packages/slate-editor/src/extensions/button-block/transforms/removeButtonBlock.ts new file mode 100644 index 000000000..c6f6cd9af --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/transforms/removeButtonBlock.ts @@ -0,0 +1,10 @@ +import { EditorCommands } from '@prezly/slate-commons'; +import type { Editor } from 'slate'; + +import { ButtonBlockNode } from '../ButtonBlockNode'; + +export function removeButtonBlock(editor: Editor): ButtonBlockNode | null { + return EditorCommands.removeNode(editor, { + match: ButtonBlockNode.isButtonBlockNode, + }); +} diff --git a/packages/slate-editor/src/extensions/button-block/transforms/updateButtonBlock.ts b/packages/slate-editor/src/extensions/button-block/transforms/updateButtonBlock.ts new file mode 100644 index 000000000..e1dc8cba8 --- /dev/null +++ b/packages/slate-editor/src/extensions/button-block/transforms/updateButtonBlock.ts @@ -0,0 +1,14 @@ +import type { Editor } from 'slate'; +import { Transforms } from 'slate'; + +import { ButtonBlockNode } from '../ButtonBlockNode'; + +export function updateButtonBlock( + editor: Editor, + patch: Partial>, +) { + Transforms.setNodes(editor, patch, { + at: [], + match: ButtonBlockNode.isButtonBlockNode, + }); +} diff --git a/packages/slate-editor/src/icons/ButtonLayoutCenter.svg b/packages/slate-editor/src/icons/ButtonLayoutCenter.svg new file mode 100644 index 000000000..1b658248f --- /dev/null +++ b/packages/slate-editor/src/icons/ButtonLayoutCenter.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/slate-editor/src/icons/ButtonLayoutLeft.svg b/packages/slate-editor/src/icons/ButtonLayoutLeft.svg new file mode 100644 index 000000000..86e13c871 --- /dev/null +++ b/packages/slate-editor/src/icons/ButtonLayoutLeft.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/slate-editor/src/icons/ButtonLayoutRight.svg b/packages/slate-editor/src/icons/ButtonLayoutRight.svg new file mode 100644 index 000000000..59c689e0b --- /dev/null +++ b/packages/slate-editor/src/icons/ButtonLayoutRight.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/slate-editor/src/icons/ButtonLayoutWide.svg b/packages/slate-editor/src/icons/ButtonLayoutWide.svg new file mode 100644 index 000000000..1b658248f --- /dev/null +++ b/packages/slate-editor/src/icons/ButtonLayoutWide.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/slate-editor/src/icons/index.ts b/packages/slate-editor/src/icons/index.ts index 292342147..e34108286 100644 --- a/packages/slate-editor/src/icons/index.ts +++ b/packages/slate-editor/src/icons/index.ts @@ -4,6 +4,10 @@ export { default as AlignLeft } from './Align-Left.svg'; export { default as AlignRight } from './Align-Right.svg'; export { default as Attachment } from './Attachment.svg'; export { default as BatsIllustration } from './Bats-Illustration.svg'; +export { default as ButtonLayoutLeft } from './ButtonLayoutLeft.svg'; +export { default as ButtonLayoutRight } from './ButtonLayoutRight.svg'; +export { default as ButtonLayoutCenter } from './ButtonLayoutCenter.svg'; +export { default as ButtonLayoutWide } from './ButtonLayoutWide.svg'; export { default as ChickenNoSignalIllustration } from './Chicken-no-signal-Illustration.svg'; export { default as Bookmark } from './Embed.svg'; // this will be reworked in scope of MT-4462 export { default as Clear } from './Clear.svg'; From e40ac2bad0ddbe70ac75a70196d1b2501e73926d Mon Sep 17 00:00:00 2001 From: Francis Gyimah Date: Thu, 10 Aug 2023 11:24:58 +0000 Subject: [PATCH 08/11] [DEV-11237] Updated button colors to match design, fixed icons and layout issues --- .../button-block/ButtonBlockNode.ts | 2 +- .../components/Button/Button.module.scss | 24 +++++++++---------- .../button-block/components/Button/Button.tsx | 7 +++--- .../components/ButtonBlockElement.tsx | 8 +++---- .../components/ButtonBlockMenu.tsx | 18 +++++++------- .../src/icons/ButtonLayoutCenter.svg | 7 +++--- .../src/icons/ButtonLayoutLeft.svg | 4 ++-- .../src/icons/ButtonLayoutRight.svg | 4 ++-- .../src/icons/ButtonLayoutWide.svg | 6 ++--- .../slate-editor/src/styles/variables.scss | 2 ++ 10 files changed, 40 insertions(+), 42 deletions(-) diff --git a/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts b/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts index 03cc177f7..61aa3fcd9 100644 --- a/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts +++ b/packages/slate-editor/src/extensions/button-block/ButtonBlockNode.ts @@ -18,7 +18,7 @@ enum Layout { LEFT = 'left', RIGHT = 'right', CENTER = 'center', - FULL_WIDTH = 'full-width', + WIDE = 'wide', } enum Variant { diff --git a/packages/slate-editor/src/extensions/button-block/components/Button/Button.module.scss b/packages/slate-editor/src/extensions/button-block/components/Button/Button.module.scss index db8233704..2f4fec533 100644 --- a/packages/slate-editor/src/extensions/button-block/components/Button/Button.module.scss +++ b/packages/slate-editor/src/extensions/button-block/components/Button/Button.module.scss @@ -2,36 +2,34 @@ @import "styles/helpers"; .Button { - @include btn-unstyled; - + cursor: pointer; display: flex; padding: $spacing-1-5 $spacing-2; justify-content: center; align-items: center; border-radius: $border-radius-small; - width: max-content; color: $white; - background-color: $indigo-400; + background-color: rgba($color: $editor-link-color, $alpha: 0.5); font-size: $font-size-medium; font-weight: 600; line-height: 160%; + &.notWide { + width: max-content; + } + &.active { - background-color: $indigo-600; + background-color: $editor-link-color; } &.outline { - border: 2px solid $indigo-400; - color: $indigo-400; + border: 2px solid rgba($color: $editor-link-color, $alpha: 0.5); + color: rgba($color: $editor-link-color, $alpha: 0.5); background-color: $white; &.active { - color: $indigo-600; - border-color: $indigo-600; + color: $editor-link-color; + border-color: $editor-link-color; } } - - &.fullWidth { - width: 100%; - } } diff --git a/packages/slate-editor/src/extensions/button-block/components/Button/Button.tsx b/packages/slate-editor/src/extensions/button-block/components/Button/Button.tsx index 98533db37..42a216545 100644 --- a/packages/slate-editor/src/extensions/button-block/components/Button/Button.tsx +++ b/packages/slate-editor/src/extensions/button-block/components/Button/Button.tsx @@ -13,14 +13,15 @@ export function Button({ node }: Props) { const { label, variant, layout, href } = node; return ( - + ); } diff --git a/packages/slate-editor/src/extensions/button-block/components/ButtonBlockElement.tsx b/packages/slate-editor/src/extensions/button-block/components/ButtonBlockElement.tsx index d6cdfa20d..f5c90d8c5 100644 --- a/packages/slate-editor/src/extensions/button-block/components/ButtonBlockElement.tsx +++ b/packages/slate-editor/src/extensions/button-block/components/ButtonBlockElement.tsx @@ -17,10 +17,9 @@ interface Props extends RenderElementProps { export function ButtonBlockElement({ attributes, children, element, withNewTabOption }: Props) { const editor = useSlateStatic(); - const { layout: buttonLayout } = element; + const { layout } = element; - const align = buttonLayout === 'full-width' ? 'center' : buttonLayout; - const layout = buttonLayout === 'full-width' ? 'full-width' : 'contained'; + const align = layout === 'wide' ? 'center' : layout; const handleUpdate = useCallback( function (patch: Partial) { @@ -41,7 +40,6 @@ export function ButtonBlockElement({ attributes, children, element, withNewTabOp {...attributes} element={element} align={align} - layout={layout} overlay="autohide" // We have to render children or Slate will fail when trying to find the node. renderAboveFrame={children} @@ -61,7 +59,7 @@ export function ButtonBlockElement({ attributes, children, element, withNewTabOp withNewTabOption={withNewTabOption} /> )} - width={layout === 'contained' ? 'min-content' : undefined} + width={layout !== 'wide' ? 'min-content' : undefined} rounded void /> diff --git a/packages/slate-editor/src/extensions/button-block/components/ButtonBlockMenu.tsx b/packages/slate-editor/src/extensions/button-block/components/ButtonBlockMenu.tsx index ae35f4004..eca65c9f0 100644 --- a/packages/slate-editor/src/extensions/button-block/components/ButtonBlockMenu.tsx +++ b/packages/slate-editor/src/extensions/button-block/components/ButtonBlockMenu.tsx @@ -76,13 +76,13 @@ const BUTTON_LAYOUT_OPTIONS: OptionsGroupOption[] }, { value: 'right', - label: 'right', + label: 'Right', icon: ({ isActive }) => ( ), }, { - value: 'full-width', + value: 'wide', label: 'Wide', icon: ({ isActive }) => ( @@ -128,8 +128,8 @@ export function ButtonMenu({ onUpdate, onClose, onRemove, value, withNewTabOptio - - + + Text - - + + Link - - + + Styling options - + Alignment - - - - + + + diff --git a/packages/slate-editor/src/icons/ButtonLayoutLeft.svg b/packages/slate-editor/src/icons/ButtonLayoutLeft.svg index 86e13c871..e76698fe3 100644 --- a/packages/slate-editor/src/icons/ButtonLayoutLeft.svg +++ b/packages/slate-editor/src/icons/ButtonLayoutLeft.svg @@ -1,6 +1,6 @@ - - + + diff --git a/packages/slate-editor/src/icons/ButtonLayoutRight.svg b/packages/slate-editor/src/icons/ButtonLayoutRight.svg index 59c689e0b..96237b55e 100644 --- a/packages/slate-editor/src/icons/ButtonLayoutRight.svg +++ b/packages/slate-editor/src/icons/ButtonLayoutRight.svg @@ -1,6 +1,6 @@ - - + + diff --git a/packages/slate-editor/src/icons/ButtonLayoutWide.svg b/packages/slate-editor/src/icons/ButtonLayoutWide.svg index 1b658248f..208f10fe4 100644 --- a/packages/slate-editor/src/icons/ButtonLayoutWide.svg +++ b/packages/slate-editor/src/icons/ButtonLayoutWide.svg @@ -1,7 +1,7 @@ - - - + + + diff --git a/packages/slate-editor/src/styles/variables.scss b/packages/slate-editor/src/styles/variables.scss index 0f00cbd6a..d50226b85 100644 --- a/packages/slate-editor/src/styles/variables.scss +++ b/packages/slate-editor/src/styles/variables.scss @@ -74,3 +74,5 @@ $editor-selection-bg: #c7d2fe; $editor-selection-color: #3630a3; $editor-bookmark-card-height: 180px; + +$editor-link-color: #3c91ff; From cef919255f4b33f34ffe5ef800bd792bb8cafa5c Mon Sep 17 00:00:00 2001 From: Francis Gyimah Date: Thu, 10 Aug 2023 13:04:04 +0000 Subject: [PATCH 09/11] [DEV-11237] PR comments updates --- .../OptionsGroup/OptionsGroup.module.scss | 1 - .../components/OptionsGroup/OptionsGroup.tsx | 5 ++-- .../button-block/ButtonBlockExtension.tsx | 8 ++++-- .../button-block/ButtonBlockNode.ts | 28 ++++++++----------- .../components/ButtonBlockElement.tsx | 8 +++++- .../components/ButtonBlockMenu.module.scss | 4 --- .../components/ButtonBlockMenu.tsx | 19 ++++++------- .../button-block/lib/createButtonBlock.ts | 6 ++-- .../lib/fixDuplicateButtonBlockUuid.ts | 24 ++++++++++++++++ .../src/extensions/button-block/lib/index.ts | 5 ++-- .../transforms/removeButtonBlock.ts | 8 ++++-- .../src/icons/Component-Button.svg | 6 ++-- .../slate-editor/src/modules/events/types.ts | 3 ++ 13 files changed, 78 insertions(+), 47 deletions(-) create mode 100644 packages/slate-editor/src/extensions/button-block/lib/fixDuplicateButtonBlockUuid.ts diff --git a/packages/slate-editor/src/components/OptionsGroup/OptionsGroup.module.scss b/packages/slate-editor/src/components/OptionsGroup/OptionsGroup.module.scss index edd53b2dc..faca6d386 100644 --- a/packages/slate-editor/src/components/OptionsGroup/OptionsGroup.module.scss +++ b/packages/slate-editor/src/components/OptionsGroup/OptionsGroup.module.scss @@ -57,7 +57,6 @@ &.variant-icon-label { opacity: 0.5; padding-top: $spacing-half; - min-width: 74px; border-radius: 8px; .hidden-input:not(:disabled) + &:hover { diff --git a/packages/slate-editor/src/components/OptionsGroup/OptionsGroup.tsx b/packages/slate-editor/src/components/OptionsGroup/OptionsGroup.tsx index 2224c049e..54d9eba54 100644 --- a/packages/slate-editor/src/components/OptionsGroup/OptionsGroup.tsx +++ b/packages/slate-editor/src/components/OptionsGroup/OptionsGroup.tsx @@ -18,7 +18,6 @@ interface OptionsGroupProps { onChange: (value: T) => void; disabled?: boolean; variant?: 'icon-label' | 'pills'; - optionClassName?: string; } export function OptionsGroup(props: OptionsGroupProps) { @@ -37,7 +36,7 @@ export function OptionsGroup(props: OptionsGroupProps) { ? { gridTemplateColumns: `repeat(auto-fit, minmax(48px, 1fr))` } : { gridTemplateColumns: `repeat(${totalColumns}, 1fr)` } } - className={classNames(styles['options-group'], variantClassName, props.optionClassName)} + className={classNames(styles['options-group'], variantClassName)} > {props.options.map((o) => (