diff --git a/packages/core/editor/src/components/Block/Block.tsx b/packages/core/editor/src/components/Block/Block.tsx index fa510d3b8..04fa81523 100644 --- a/packages/core/editor/src/components/Block/Block.tsx +++ b/packages/core/editor/src/components/Block/Block.tsx @@ -1,6 +1,6 @@ import { useYooptaEditor } from '../../contexts/YooptaContext/YooptaContext'; import { useSortable } from '@dnd-kit/sortable'; -import { useState } from 'react'; +import { CSSProperties, useState } from 'react'; import { BlockActions } from './BlockActions'; const Block = ({ children, block, blockId }) => { @@ -10,12 +10,15 @@ const Block = ({ children, block, blockId }) => { const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isOver, isDragging } = useSortable({ id: blockId, disabled: editor.readOnly }); - const style = { + const align = block.meta.align || 'left'; + const className = `yoopta-block yoopta-align-${align}`; + + const style: CSSProperties = { + // [TODO] = handle max depth + marginLeft: `${block.meta.depth * 20}px`, transform: transform ? `translate3d(${transform.x}px, ${transform.y}px, 0)` : 'none', transition, opacity: isDragging ? 0.7 : 1, - // [TODO] = handle max depth - marginLeft: `${block.meta.depth * 20}px`, }; const isSelected = editor.selectedBlocks?.includes(block.meta.order); @@ -37,7 +40,7 @@ const Block = ({ children, block, blockId }) => { return (
{ if (isReadOnly) return; - if (event.shiftKey) { - const currentSelectionIndex = editor.selection; - if (!currentSelectionIndex) return; - - const targetBlock = (event.target as HTMLElement).closest('div[data-yoopta-block]'); - const targetBlockId = targetBlock?.getAttribute('data-yoopta-block-id') || ''; - const targetBlockIndex = editor.children[targetBlockId]?.meta.order; - if (typeof targetBlockIndex !== 'number') return; - - const indexesBetween = Array.from({ length: Math.abs(targetBlockIndex - currentSelectionIndex[0]) }).map( - (_, index) => - targetBlockIndex > currentSelectionIndex[0] - ? currentSelectionIndex[0] + index + 1 - : currentSelectionIndex[0] - index - 1, - ); - - editor.blur(); - editor.setBlockSelected([currentSelectionIndex[0], ...indexesBetween], { only: true }); - return; - } + // if (event.shiftKey) { + // const currentSelectionIndex = editor.selection; + // if (!currentSelectionIndex) return; + + // const targetBlock = (event.target as HTMLElement).closest('div[data-yoopta-block]'); + // const targetBlockId = targetBlock?.getAttribute('data-yoopta-block-id') || ''; + // const targetBlockIndex = editor.children[targetBlockId]?.meta.order; + // if (typeof targetBlockIndex !== 'number') return; + + // const indexesBetween = Array.from({ length: Math.abs(targetBlockIndex - currentSelectionIndex[0]) }).map( + // (_, index) => + // targetBlockIndex > currentSelectionIndex[0] + // ? currentSelectionIndex[0] + index + 1 + // : currentSelectionIndex[0] - index - 1, + // ); + + // editor.blur(); + // editor.setBlockSelected([currentSelectionIndex[0], ...indexesBetween], { only: true }); + // return; + // } resetSelectionState(); handleEmptyZoneClick(event); diff --git a/packages/core/editor/src/editor/blocks/createBlock.ts b/packages/core/editor/src/editor/blocks/createBlock.ts index ae4536e0f..a74b9f4ef 100644 --- a/packages/core/editor/src/editor/blocks/createBlock.ts +++ b/packages/core/editor/src/editor/blocks/createBlock.ts @@ -38,6 +38,7 @@ export function createBlock(editor: YooEditor, type: string, options?: CreateBlo meta: { order: block.meta.order, depth: block.meta.depth, + align: block.meta.align, }, value: [elements], }); diff --git a/packages/core/editor/src/editor/blocks/splitBlock.ts b/packages/core/editor/src/editor/blocks/splitBlock.ts index 04bfe8709..baa023ea6 100644 --- a/packages/core/editor/src/editor/blocks/splitBlock.ts +++ b/packages/core/editor/src/editor/blocks/splitBlock.ts @@ -40,6 +40,7 @@ export function splitBlock(editor: YooEditor, options: YooptaEditorTransformOpti meta: { order: currentBlock.meta.order + 1, depth: currentBlock.meta.depth, + align: currentBlock.meta.align, }, // [TODO] - check for mark text formats value: [nextBlockChildren], diff --git a/packages/core/editor/src/editor/types.ts b/packages/core/editor/src/editor/types.ts index 7607e6f9f..f2c4d3a48 100644 --- a/packages/core/editor/src/editor/types.ts +++ b/packages/core/editor/src/editor/types.ts @@ -23,6 +23,7 @@ export type YooptaBlockData = { export type YooptaBlockBaseMeta = { order: number; depth: number; + align?: 'left' | 'center' | 'right' | undefined; }; export type YooptaContentValue = Record; diff --git a/packages/core/editor/src/plugins/SlateEditorComponent.tsx b/packages/core/editor/src/plugins/SlateEditorComponent.tsx index 7628ff1f0..a62eb590f 100644 --- a/packages/core/editor/src/plugins/SlateEditorComponent.tsx +++ b/packages/core/editor/src/plugins/SlateEditorComponent.tsx @@ -125,6 +125,7 @@ const SlateEditorComponent = ({ } if (!ElementComponent) return ; + return ( = { icon?: string | ReactNode | ReactElement; }; shortcuts?: string[]; - align?: 'left' | 'center' | 'right'; HTMLAttributes?: HTMLAttributes; } & T; diff --git a/packages/core/editor/src/styles.css b/packages/core/editor/src/styles.css index 6bb0b3c30..46516a698 100644 --- a/packages/core/editor/src/styles.css +++ b/packages/core/editor/src/styles.css @@ -129,4 +129,17 @@ pre { .yoopta-block-options-group { @apply yoo-editor-flex yoo-editor-flex-col +} + +/* Aligment for elements */ +.yoopta-align-left { + @apply yoo-editor-justify-start yoo-editor-text-left +} + +.yoopta-align-center { + @apply yoo-editor-justify-center yoo-editor-text-center +} + +.yoopta-align-right { + @apply yoo-editor-justify-end yoo-editor-text-right } \ No newline at end of file diff --git a/packages/core/editor/src/utils/editorBuilders.ts b/packages/core/editor/src/utils/editorBuilders.ts index 03be6f63a..ff7721f91 100644 --- a/packages/core/editor/src/utils/editorBuilders.ts +++ b/packages/core/editor/src/utils/editorBuilders.ts @@ -50,7 +50,7 @@ export function buildBlocks(editor, plugins: Plugin { diff --git a/packages/development/src/components/customPlugins/Accordion/Accordion.tsx b/packages/development/src/components/customPlugins/Accordion/Accordion.tsx deleted file mode 100644 index b59ffecfc..000000000 --- a/packages/development/src/components/customPlugins/Accordion/Accordion.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { generateId, SlateElement, YooptaBlockData } from '@yoopta/editor'; - -const ACCORDION_VALUE: SlateElement[] = [ - { - id: generateId(), - type: 'accordion-list', - children: [ - { - id: generateId(), - type: 'accordion-list-item', - props: { - isExpanded: true, - }, - children: [ - { id: generateId(), type: 'accordion-list-item-heading', children: [{ text: 'Title 1' }] }, - { - id: generateId(), - type: 'accordion-list-item-content', - children: [ - { - text: `This is the first item's accordion body. It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.`, - }, - ], - }, - ], - }, - { - id: generateId(), - type: 'accordion-list-item', - props: { - isExpanded: false, - }, - children: [ - { id: generateId(), type: 'accordion-list-item-heading', children: [{ text: 'Title 2' }] }, - { - id: generateId(), - type: 'accordion-list-item-content', - children: [ - { - text: `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis fermentum, lorem eu ultrices blandit, nunc magna dapibus nunc, non ultricies mauris ante ac arcu. Aliquam varius eu nisi et elementum. Suspendisse non tortor ut enim feugiat feugiat. Nulla vestibulum bibendum enim ut sagittis. Donec arcu sem, auctor eu elementum vitae, dignissim ut sem. Integer eros erat, dignissim a ornare eget, pulvinar vel nisi. Duis sit amet sapien in turpis tincidunt pretium eget vel metus. Morbi vitae ipsum eros. Proin et mattis enim. In sodales mauris neque, in eleifend massa mattis eget. Nullam posuere sollicitudin hendrerit. Aenean sed risus quis ligula faucibus ultrices a non purus. Nullam ac lacus quis urna congue lacinia. Etiam vel magna a ligula ornare tincidunt id at nisi.`, - }, - ], - }, - ], - }, - ], - }, -]; - -export const ACCORDION_BLOCK: YooptaBlockData = { - id: generateId(), - type: 'Accordion', - meta: { order: 0, depth: 0 }, - value: ACCORDION_VALUE, -}; diff --git a/packages/development/src/pages/dev/index.tsx b/packages/development/src/pages/dev/index.tsx index 09ce633d9..c52965d58 100644 --- a/packages/development/src/pages/dev/index.tsx +++ b/packages/development/src/pages/dev/index.tsx @@ -21,18 +21,18 @@ const BasicExample = () => { const rectangleSelectionRef = useRef(null); const [readOnly, setReadOnly] = useState(false); - useEffect(() => { - const handleCopy = (value) => console.log('BLOCK COPY', value); - const handleFocus = (focused) => console.log('FOCUS', focused); + // useEffect(() => { + // const handleCopy = (value) => console.log('BLOCK COPY', value); + // const handleFocus = (focused) => console.log('FOCUS', focused); - editor.on('block:copy', handleCopy); - editor.on('focus', handleFocus); + // editor.on('block:copy', handleCopy); + // editor.on('focus', handleFocus); - return () => { - editor.off('block:copy', handleCopy); - editor.off('focus', handleFocus); - }; - }, []); + // return () => { + // editor.off('block:copy', handleCopy); + // editor.off('focus', handleFocus); + // }; + // }, []); const onSubmit = () => { const editorData = editor.getEditorValue(); @@ -56,59 +56,189 @@ const BasicExample = () => { plus: null, }} value={{ - '7453ac69-0d2a-4a27-ac48-21de5021c432': { - id: '7453ac69-0d2a-4a27-ac48-21de5021c432', + 'e5bd3ee7-391c-4a6c-8d99-bd02fae4d4d2': { + id: 'e5bd3ee7-391c-4a6c-8d99-bd02fae4d4d2', value: [ { - id: '7021ff94-a84f-4ce7-9fcc-cae7eaf2588e', - type: 'numbered-list', + id: '7cc1b41e-af96-4728-8422-f0e5ca319439', + type: 'accordion-list', + children: [ + { + id: '03ffc5a8-4882-44bc-a57b-af9fb773bc52', + type: 'accordion-list-item', + children: [ + { + id: '3f010f03-1d09-48a3-8b86-4eea5514ba46', + type: 'accordion-list-item-heading', + children: [ + { + text: 'Why copy/paste and not packaged as a dependency?', + italic: true, + bold: true, + }, + ], + props: { + nodeType: 'block', + }, + }, + { + id: '87fd7485-9864-478e-9b6d-8d4df789f3b9', + type: 'accordion-list-item-content', + children: [ + { + text: 'Start with some sensible defaults, then customize the components to your needs.', + }, + ], + props: { + nodeType: 'block', + }, + }, + ], + props: { + nodeType: 'block', + isExpanded: false, + }, + }, + { + id: 'db504063-91e0-40b9-a7de-dec6731c8da9', + type: 'accordion-list-item', + children: [ + { + id: '0527ee4f-7472-4c6e-8e58-0aee4c84db4e', + type: 'accordion-list-item-heading', + children: [ + { + text: 'Do you plan to publish it as an npm package?', + }, + ], + props: { + nodeType: 'block', + }, + }, + { + id: 'c6e12a11-a248-4385-80ad-36e933ec57f5', + type: 'accordion-list-item-content', + children: [ + { + text: 'No. I have no plans to publish it as an npm package.', + }, + ], + props: { + nodeType: 'block', + }, + }, + ], + props: { + nodeType: 'block', + isExpanded: false, + }, + }, + { + id: 'f89c14d3-88c6-43f1-b274-1cd32ef3ea2d', + type: 'accordion-list-item', + children: [ + { + id: 'e058e58c-a56e-4eb2-8602-34b92cb0cc1b', + type: 'accordion-list-item-heading', + children: [ + { + text: 'Which frameworks are supported?', + }, + ], + props: { + nodeType: 'block', + }, + }, + { + id: '7d6b408f-a2f3-428f-89a0-f52b2848d972', + type: 'accordion-list-item-content', + children: [ + { + text: 'You can use any framework that supports React. ', + }, + ], + props: { + nodeType: 'block', + }, + }, + ], + props: { + nodeType: 'block', + isExpanded: true, + }, + }, + ], + }, + ], + type: 'Accordion', + meta: { + order: 2, + depth: 0, + align: 'center', + }, + }, + '6c7970dd-a624-4c42-a809-6863095419ae': { + id: '6c7970dd-a624-4c42-a809-6863095419ae', + value: [ + { + id: '80ad5c7d-c73c-40bb-b01d-5337357c1f95', + type: 'heading-one', props: { nodeType: 'block', }, children: [ { - text: 'asd', + text: 'Introduction', }, ], }, ], - type: 'NumberedList', + type: 'HeadingOne', meta: { order: 0, depth: 0, + align: 'center', }, }, - 'c55f8f56-d792-4c3a-aaf0-d90b8391e622': { - id: 'c55f8f56-d792-4c3a-aaf0-d90b8391e622', + 'b8a6e071-9393-4991-8d28-923d80c255ad': { + id: 'b8a6e071-9393-4991-8d28-923d80c255ad', value: [ { - id: 'acb880d7-5755-4a64-9aa8-7f0b0c87f18e', - type: 'numbered-list', + id: 'fc748dc8-224a-4b6a-a319-cc942ae7de3b', + type: 'image', + props: { + src: 'https://res.cloudinary.com/ench-app/image/upload/v1719855049/hold-up-let-him-cook_s4rrzh.gif', + alt: 'cloudinary', + srcSet: null, + fit: 'fill', + sizes: { + width: 314, + height: 309, + }, + nodeType: 'void', + }, children: [ { - text: 'asdasd', + text: '', }, ], - props: { - nodeType: 'block', - }, }, ], - type: 'NumberedList', + type: 'Image', meta: { - order: 5, + order: 7, depth: 0, }, }, - '4192a57a-3048-4819-a9b2-9bad2839ee38': { - id: '4192a57a-3048-4819-a9b2-9bad2839ee38', + '22d67b35-7897-42ac-92f4-ea00727a526a': { + id: '22d67b35-7897-42ac-92f4-ea00727a526a', value: [ { - id: '0fb531fe-bb2d-4e0b-8422-7a82e95bc4d3', - type: 'numbered-list', + id: 'd76ed64a-ff59-4df3-bd0e-f4fd38428883', + type: 'paragraph', children: [ { - text: 'asdasdasd', + text: 'Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.', }, ], props: { @@ -116,21 +246,27 @@ const BasicExample = () => { }, }, ], - type: 'NumberedList', + type: 'Paragraph', meta: { - order: 6, + order: 1, depth: 0, + align: 'center', }, }, - 'e4283d23-bf3d-4df3-b372-a4cea302e91b': { - id: 'e4283d23-bf3d-4df3-b372-a4cea302e91b', + '7ddfcf7f-adb6-401f-ba71-08e8830e81da': { + id: '7ddfcf7f-adb6-401f-ba71-08e8830e81da', + type: 'NumberedList', + meta: { + order: 4, + depth: 0, + }, value: [ { - id: '54a57ffd-7c8e-45c4-841d-e2bf07ff9f22', - type: 'paragraph', + id: 'fbc9fb6a-3414-4337-a9e1-b88e6484df02', + type: 'numbered-list', children: [ { - text: '', + text: 'Other color formats', }, ], props: { @@ -138,22 +274,81 @@ const BasicExample = () => { }, }, ], - type: 'Paragraph', - meta: { - order: 8, - depth: 0, - }, }, - '8f85a7ea-e606-4684-a5d2-d20ef138080b': { - id: '8f85a7ea-e606-4684-a5d2-d20ef138080b', + '3bec6a02-f31f-4809-86ac-e405d710ce6a': { + id: '3bec6a02-f31f-4809-86ac-e405d710ce6a', value: [ { - id: 'd6931777-17b3-469c-83f2-0bf85842ca20', + id: '2e5b398b-f997-43bc-a449-02999d657f20', type: 'paragraph', children: [ + { + text: 'See the', + }, + { + text: ' ', + }, { text: '', }, + { + id: '80ea61fd-5fb2-4909-ab33-b7baaef37879', + type: 'link', + props: { + url: 'https://tailwindcss.com/docs/customizing-colors#using-css-variables', + target: '', + rel: '', + title: 'Tailwind CSS documentation', + nodeType: 'inline', + }, + children: [ + { + text: 'Tailwind CSS documentation', + }, + ], + }, + { + text: ' ', + }, + { + text: 'for more information on using', + }, + { + text: ' ', + }, + { + code: true, + text: 'rgb', + }, + { + text: ',', + }, + { + text: ' ', + }, + { + code: true, + text: 'rgba', + }, + { + text: ' ', + }, + { + text: 'or', + }, + { + text: ' ', + }, + { + code: true, + text: 'hsl', + }, + { + text: ' ', + }, + { + text: 'colors.', + }, ], props: { nodeType: 'block', @@ -162,19 +357,26 @@ const BasicExample = () => { ], type: 'Paragraph', meta: { - order: 9, + order: 5, depth: 0, }, }, - 'ee387b66-62c1-4c01-b9f6-35b2ecb01f1c': { - id: 'ee387b66-62c1-4c01-b9f6-35b2ecb01f1c', + '2ab847d7-c765-4e6f-9116-db6669f49318': { + id: '2ab847d7-c765-4e6f-9116-db6669f49318', value: [ { - id: '6962f986-4d98-40ad-bb85-8262d7492b7f', - type: 'paragraph', + id: '9977d4ba-6000-4996-a2fa-3b4ce07f71ee', + type: 'numbered-list', children: [ { - text: 'asdasdas', + text: 'I recommend using HSL c', + }, + { + text: 'olors for theming but you can al', + bold: true, + }, + { + text: 'so use other color formats if you prefer.', }, ], props: { @@ -182,125 +384,129 @@ const BasicExample = () => { }, }, ], - type: 'Paragraph', + type: 'NumberedList', meta: { - order: 1, + order: 3, depth: 0, }, }, - 'e382a6e4-ae76-4b27-9bcb-86b2c699fec4': { - id: 'e382a6e4-ae76-4b27-9bcb-86b2c699fec4', + '9b0a0740-5a6d-4f58-beda-c0ec83fe2168': { + id: '9b0a0740-5a6d-4f58-beda-c0ec83fe2168', value: [ { - id: '21662b6c-0c59-4fd8-bd85-7b0578fc7cd7', - type: 'paragraph', + id: '8126d743-8102-4dff-ba98-e7a57c69886a', + type: 'embed', + props: { + sizes: { + width: 650, + height: 400, + }, + nodeType: 'void', + provider: { + type: 'youtube', + id: 'evJ6gX1lp2o', + url: 'https://www.youtube.com/watch?v=evJ6gX1lp2o&list=RDevJ6gX1lp2o&index=2&ab_channel=Artemas', + }, + }, children: [ { - text: 'dasd', + text: '', }, ], - props: { - nodeType: 'block', - }, }, ], - type: 'Paragraph', + type: 'Embed', meta: { - order: 2, + order: 8, depth: 0, }, }, - '1427c85a-2375-4d96-9535-2ec58f2903af': { - id: '1427c85a-2375-4d96-9535-2ec58f2903af', + 'dc8409b8-0c20-4c47-ac60-2b2016393c53': { + id: 'dc8409b8-0c20-4c47-ac60-2b2016393c53', value: [ { - id: 'fc74e476-445a-426c-82d0-247c2440e52a', - type: 'paragraph', + id: 'd6d7fb8a-9785-4c5f-a3c4-7c1ac100881b', + type: 'video', + props: { + src: 'https://res.cloudinary.com/ench-app/video/upload/v1719868158/No_name_not19t.mp4', + srcSet: null, + sizes: { + width: 416, + height: 234, + }, + nodeType: 'void', + provider: { + type: null, + id: '', + }, + settings: { + controls: false, + loop: true, + muted: true, + autoPlay: true, + }, + fit: 'cover', + }, children: [ { - text: 'sadsad', + text: '', }, ], - props: { - nodeType: 'block', - }, }, ], - type: 'Paragraph', + type: 'Video', meta: { - order: 3, + order: 9, depth: 0, }, }, - '261951ac-1a43-4c0e-887d-a1cddf310071': { - id: '261951ac-1a43-4c0e-887d-a1cddf310071', + 'e805cb24-92ef-4b9f-a551-07d423be06ec': { + id: 'e805cb24-92ef-4b9f-a551-07d423be06ec', value: [ { - id: 'e69c48ae-c423-46a7-965b-cec1669e6c6e', - type: 'paragraph', + id: '423a5be5-0fa5-46a3-8318-73f82d75f86a', + type: 'file', + props: { + size: 13206, + name: 'editor', + src: 'https://res.cloudinary.com/ench-app/raw/upload/v1719868177/editor_r8vu5j.json', + format: 'json', + nodeType: 'void', + }, children: [ { - text: 'Super text', + text: '', }, ], - props: { - nodeType: 'block', - }, }, ], - type: 'Paragraph', + type: 'File', meta: { - order: 4, + order: 6, depth: 0, }, }, - 'a60daf05-5769-4dba-ad2c-b5db07085d00': { - id: 'a60daf05-5769-4dba-ad2c-b5db07085d00', + 'ce29e84c-a40e-4a4f-9734-839835cea334': { + id: 'ce29e84c-a40e-4a4f-9734-839835cea334', value: [ { - id: 'ad69c236-35fe-463f-9634-ca24471648f4', - type: 'accordion-list', + id: '142342e9-fdb6-4ea0-aa0f-a40569d1d9e0', + type: 'code', + props: { + nodeType: 'void', + language: 'javascript', + theme: 'VSCode', + }, children: [ { - id: '784c35bb-d361-40a7-941d-45786bbdbd11', - type: 'accordion-list-item', - children: [ - { - id: '89779009-78a0-4c92-ad37-51e5e433ad99', - type: 'accordion-list-item-heading', - children: [ - { - text: 'asdasdsadasdadasda', - }, - ], - props: { - nodeType: 'block', - }, - }, - { - id: 'cfec5263-7b27-43e9-a561-a82e5e1f193f', - type: 'accordion-list-item-content', - children: [ - { - text: 'asdsadsaddasdasdasd', - }, - ], - props: { - nodeType: 'block', - }, - }, - ], - props: { - nodeType: 'block', - isExpanded: true, - }, + text: 'function getData() {}', }, ], }, ], - type: 'Accordion', + type: 'Code', meta: { - order: 7, + order: 10, depth: 0, }, }, diff --git a/packages/plugins/accordion/src/styles.css b/packages/plugins/accordion/src/styles.css index 1ae5e435f..560bc2a06 100644 --- a/packages/plugins/accordion/src/styles.css +++ b/packages/plugins/accordion/src/styles.css @@ -9,7 +9,7 @@ } .yoopta-accordion-list-item-heading { - @apply yoo-accordion-mb-0 yoo-accordion-relative yoo-accordion-w-full yoo-accordion-items-center yoo-accordion-border-0 yoo-accordion-rounded-none yoo-accordion-py-4 yoo-accordion-pr-8 yoo-accordion-text-left yoo-accordion-cursor-pointer yoo-accordion-relative yoo-accordion-text-base yoo-accordion-font-medium + @apply yoo-accordion-mb-0 yoo-accordion-relative yoo-accordion-w-full yoo-accordion-items-center yoo-accordion-border-0 yoo-accordion-rounded-none yoo-accordion-py-4 yoo-accordion-pr-8 yoo-accordion-cursor-pointer yoo-accordion-relative yoo-accordion-text-base yoo-accordion-font-medium } .yoopta-accordion-list-item-content { diff --git a/packages/plugins/blockquote/README.md b/packages/plugins/blockquote/README.md index e81437d02..031e41293 100644 --- a/packages/plugins/blockquote/README.md +++ b/packages/plugins/blockquote/README.md @@ -48,7 +48,6 @@ const plugins = [ }, options: { shortcuts: [``], - align: 'left' | 'center' | 'right', display: { title: ``, description: ``, diff --git a/packages/plugins/callout/README.md b/packages/plugins/callout/README.md index dba62a2c5..13e327977 100644 --- a/packages/plugins/callout/README.md +++ b/packages/plugins/callout/README.md @@ -49,7 +49,6 @@ const plugins = [ }, options: { shortcuts: [``], - align: 'left' | 'center' | 'right', display: { title: ``, description: ``, diff --git a/packages/plugins/embed/src/ui/Embed.tsx b/packages/plugins/embed/src/ui/Embed.tsx index d4059793e..4e8097c2d 100644 --- a/packages/plugins/embed/src/ui/Embed.tsx +++ b/packages/plugins/embed/src/ui/Embed.tsx @@ -81,14 +81,17 @@ const EmbedRender = ({ element, attributes, children, blockId }: PluginElementRe ); } + const currentAlign = block?.meta?.align || 'center'; + const alignClass = `yoopta-align-${currentAlign}`; + return (
- + {blockSelected && (
)} diff --git a/packages/plugins/embed/src/ui/EmbedBlockOptions.tsx b/packages/plugins/embed/src/ui/EmbedBlockOptions.tsx index 346a5d87c..ce72efcbe 100644 --- a/packages/plugins/embed/src/ui/EmbedBlockOptions.tsx +++ b/packages/plugins/embed/src/ui/EmbedBlockOptions.tsx @@ -1,7 +1,13 @@ -import { UI, YooEditor, YooptaBlockData } from '@yoopta/editor'; -import { ExternalLinkIcon } from '@radix-ui/react-icons'; +import { Blocks, UI, YooEditor, YooptaBlockData } from '@yoopta/editor'; +import { ExternalLinkIcon, TextAlignCenterIcon, TextAlignLeftIcon, TextAlignRightIcon } from '@radix-ui/react-icons'; import { EmbedElementProps } from '../types'; +const ALIGN_ICONS = { + left: TextAlignLeftIcon, + center: TextAlignCenterIcon, + right: TextAlignRightIcon, +}; + const { ExtendedBlockActions, BlockOptionsMenuGroup, BlockOptionsMenuItem, BlockOptionsSeparator } = UI; type Props = { @@ -15,10 +21,27 @@ const EmbedBlockOptions = ({ editor, block, props: embedProps }: Props) => { window.open(embedProps?.provider?.url, '_blank'); }; + const currentAlign = block?.meta?.align || 'center'; + const AlignIcon = ALIGN_ICONS[currentAlign]; + + const onToggleAlign = () => { + const aligns = ['left', 'center', 'right']; + if (!block) return; + + const nextAlign = aligns[(aligns.indexOf(currentAlign) + 1) % aligns.length] as YooptaBlockData['meta']['align']; + Blocks.updateBlock(editor, block.id, { meta: { ...block.meta, align: nextAlign } }); + }; + return ( editor.setSelection([block.meta.order])}> + + + + - - {/* + + + - */} + ); diff --git a/packages/plugins/lists/README.md b/packages/plugins/lists/README.md index cd6507be6..1f6cdbc18 100644 --- a/packages/plugins/lists/README.md +++ b/packages/plugins/lists/README.md @@ -56,7 +56,6 @@ const plugins = [ }, options: { shortcuts: [``], - align: 'left' | 'center' | 'right', display: { title: ``, description: ``, @@ -102,7 +101,6 @@ const plugins = [ }, options: { shortcuts: [``], - align: 'left' | 'center' | 'right', display: { title: ``, description: ``, @@ -149,7 +147,6 @@ const plugins = [ }, options: { shortcuts: [``], - align: 'left' | 'center' | 'right', display: { title: ``, description: ``, diff --git a/packages/plugins/lists/src/elements/BulletedList.tsx b/packages/plugins/lists/src/elements/BulletedList.tsx index afc9d5c67..3ad9ac51b 100644 --- a/packages/plugins/lists/src/elements/BulletedList.tsx +++ b/packages/plugins/lists/src/elements/BulletedList.tsx @@ -1,10 +1,14 @@ -import { PluginElementRenderProps } from '@yoopta/editor'; +import { PluginElementRenderProps, useBlockData } from '@yoopta/editor'; -const BulletedListRender = ({ attributes, element, children, HTMLAttributes = {} }: PluginElementRenderProps) => { +const BulletedListRender = ({ attributes, blockId, children, HTMLAttributes = {} }: PluginElementRenderProps) => { const { className = '', ...htmlAttrs } = HTMLAttributes; + const block = useBlockData(blockId); + + const currentAlign = block?.meta?.align || 'left'; + const alignClass = `yoopta-align-${currentAlign}`; return ( -
+
diff --git a/packages/plugins/lists/src/elements/NumberedList.tsx b/packages/plugins/lists/src/elements/NumberedList.tsx index d6f7c944f..f0707f3b6 100644 --- a/packages/plugins/lists/src/elements/NumberedList.tsx +++ b/packages/plugins/lists/src/elements/NumberedList.tsx @@ -33,21 +33,18 @@ function getNumberedListCount(editor: YooEditor, block: YooptaBlockData) { return count; } -const NumberedListRender = ({ - attributes, - children, - element, - blockId, - HTMLAttributes = {}, -}: PluginElementRenderProps) => { +const NumberedListRender = ({ attributes, children, blockId, HTMLAttributes = {} }: PluginElementRenderProps) => { const { className = '', ...htmlAttrs } = HTMLAttributes; const block = useBlockData(blockId); const editor = useYooptaEditor(); const count = getNumberedListCount(editor, block); + const currentAlign = block?.meta?.align || 'left'; + const alignClass = `yoopta-align-${currentAlign}`; + return ( -
+
{count}. diff --git a/packages/plugins/lists/src/elements/TodoList.tsx b/packages/plugins/lists/src/elements/TodoList.tsx index 530dc9455..37459caef 100644 --- a/packages/plugins/lists/src/elements/TodoList.tsx +++ b/packages/plugins/lists/src/elements/TodoList.tsx @@ -1,8 +1,9 @@ -import { Elements, PluginElementRenderProps, useYooptaEditor } from '@yoopta/editor'; +import { Elements, PluginElementRenderProps, useBlockData, useYooptaEditor } from '@yoopta/editor'; import { TodoListElementProps } from '../types'; const TodoListRender = ({ attributes, element, children, blockId, HTMLAttributes = {} }: PluginElementRenderProps) => { const editor = useYooptaEditor(); + const block = useBlockData(blockId); const { className = '', ...htmlAttrs } = HTMLAttributes; const { checked = false } = (element.props || {}) as TodoListElementProps; @@ -10,8 +11,16 @@ const TodoListRender = ({ attributes, element, children, blockId, HTMLAttributes textDecoration: checked ? 'line-through' : 'none', }; + const currentAlign = block?.meta?.align || 'left'; + const alignClass = `yoopta-align-${currentAlign}`; + return ( -
+
Elements.updateElement(editor, blockId, { type: 'todo-list', props: { checked: !checked } })} contentEditable={false} diff --git a/packages/plugins/lists/src/styles.css b/packages/plugins/lists/src/styles.css index 9e353b049..ef2aa3bf9 100644 --- a/packages/plugins/lists/src/styles.css +++ b/packages/plugins/lists/src/styles.css @@ -9,10 +9,6 @@ @apply yoo-lists-min-w-[10px] yoo-lists-w-auto yoo-lists-select-none yoo-lists-absolute yoo-lists-left-0 yoo-lists-top-[2px] } -.yoopta-numbered-list-content { - @apply yoo-lists-flex-grow -} - /* Bulleted list */ .yoopta-bulleted-list { @apply yoo-lists-ml-[10px] yoo-lists-flex yoo-lists-items-center yoo-lists-pl-4 yoo-lists-space-x-1 yoo-lists-py-[2px] yoo-lists-text-[16px] yoo-lists-leading-7 yoo-lists-relative @@ -23,7 +19,7 @@ } .yoopta-bulleted-list-content { - @apply yoo-lists-flex-grow yoo-lists-ml-0 + @apply yoo-lists-ml-0 } /* Todo list */ @@ -31,10 +27,6 @@ @apply yoo-lists-ml-[10px] yoo-lists-flex yoo-lists-items-center yoo-lists-pl-4 yoo-lists-space-x-1 yoo-lists-py-[2px] yoo-lists-text-[16px] yoo-lists-leading-[28px] yoo-lists-relative } -.yoopta-todo-list-content { - @apply yoo-lists-flex-grow -} - .yoopta-todo-list-checkbox { @apply yoo-lists-select-none yoo-lists-cursor-pointer yoo-lists-absolute yoo-lists-left-0 yoo-lists-top-[4px] } diff --git a/packages/plugins/paragraph/README.md b/packages/plugins/paragraph/README.md index 949520284..7429e5e9c 100644 --- a/packages/plugins/paragraph/README.md +++ b/packages/plugins/paragraph/README.md @@ -48,7 +48,6 @@ const plugins = [ }, options: { shortcuts: [``], - align: 'left' | 'center' | 'right', display: { title: ``, description: ``, diff --git a/packages/plugins/video/src/ui/Video.tsx b/packages/plugins/video/src/ui/Video.tsx index 8d65fbd18..3fd184bdb 100644 --- a/packages/plugins/video/src/ui/Video.tsx +++ b/packages/plugins/video/src/ui/Video.tsx @@ -81,14 +81,17 @@ const VideoRender = ({ element, attributes, children, blockId }: PluginElementRe ); } + const currentAlign = block?.meta?.align || 'center'; + const alignClass = `yoopta-align-${currentAlign}`; + return (
- + {blockSelected && (
)} diff --git a/packages/plugins/video/src/ui/VideoBlockOptions.tsx b/packages/plugins/video/src/ui/VideoBlockOptions.tsx index 6b6af04f6..6871b2d08 100644 --- a/packages/plugins/video/src/ui/VideoBlockOptions.tsx +++ b/packages/plugins/video/src/ui/VideoBlockOptions.tsx @@ -1,9 +1,23 @@ -import { Elements, UI, YooEditor, YooptaBlockData } from '@yoopta/editor'; -import { RowSpacingIcon, SizeIcon, WidthIcon, ExternalLinkIcon } from '@radix-ui/react-icons'; +import { Blocks, Elements, UI, YooEditor, YooptaBlockData } from '@yoopta/editor'; +import { + RowSpacingIcon, + SizeIcon, + WidthIcon, + ExternalLinkIcon, + TextAlignCenterIcon, + TextAlignLeftIcon, + TextAlignRightIcon, +} from '@radix-ui/react-icons'; import { VideoElementProps, VideoPluginElements } from '../types'; import CheckmarkIcon from '../icons/checkmark.svg'; import DownloadIcon from '../icons/download.svg'; +const ALIGN_ICONS = { + left: TextAlignLeftIcon, + center: TextAlignCenterIcon, + right: TextAlignRightIcon, +}; + const { ExtendedBlockActions, BlockOptionsMenuGroup, BlockOptionsMenuItem, BlockOptionsSeparator } = UI; type Props = { @@ -56,6 +70,17 @@ const VideoBlockOptions = ({ editor, block, props: videoProps }: Props) => { } }; + const currentAlign = block?.meta?.align || 'center'; + const AlignIcon = ALIGN_ICONS[currentAlign]; + + const onToggleAlign = () => { + const aligns = ['left', 'center', 'right']; + if (!block) return; + + const nextAlign = aligns[(aligns.indexOf(currentAlign) + 1) % aligns.length] as YooptaBlockData['meta']['align']; + Blocks.updateBlock(editor, block.id, { meta: { ...block.meta, align: nextAlign } }); + }; + return ( editor.setSelection([block.meta.order])} id="yoopta-video-options"> @@ -99,6 +124,16 @@ const VideoBlockOptions = ({ editor, block, props: videoProps }: Props) => { + + +