From 093252d0dad9c3a279538e7491ba92c594e93a0b Mon Sep 17 00:00:00 2001 From: xypnox Date: Tue, 4 Oct 2022 20:36:34 +0530 Subject: [PATCH 1/3] Copy balloon toolbar input for note and snippet creation with toast --- .../BalloonToolbar/EditorBalloonToolbar.tsx | 201 +++++++++--------- .../components/SelectionToNode.tsx | 57 ++++- .../components/SelectionToSnippet.tsx | 56 ++++- .../BalloonToolbar/components/useTransform.ts | 75 +++++-- .../src/Components/Toast/useOpenToast.tsx | 45 ++++ apps/webapp/src/Components/Todo/index.tsx | 2 +- .../src/Hooks/useBalloonToolbarPopper.ts | 47 +++- .../shared/src/Style/BalloonToolbar.styles.ts | 12 ++ 8 files changed, 364 insertions(+), 131 deletions(-) create mode 100644 apps/webapp/src/Components/Toast/useOpenToast.tsx diff --git a/apps/webapp/src/Components/Editor/BalloonToolbar/EditorBalloonToolbar.tsx b/apps/webapp/src/Components/Editor/BalloonToolbar/EditorBalloonToolbar.tsx index 0c042223e..448637495 100644 --- a/apps/webapp/src/Components/Editor/BalloonToolbar/EditorBalloonToolbar.tsx +++ b/apps/webapp/src/Components/Editor/BalloonToolbar/EditorBalloonToolbar.tsx @@ -37,14 +37,18 @@ import { usePlateEditorRef } from '@udecode/plate' -import { ButtonSeparator } from '@mexit/shared' +import { ButtonSeparator, useBalloonToolbarStore } from '@mexit/shared' import { BalloonToolbar } from './BalloonToolbar' -import { SelectionToNode } from './components/SelectionToNode' -import { SelectionToSnippet } from './components/SelectionToSnippet' + +import { SelectionToNode, SelectionToNodeInput } from './components/SelectionToNode' +import { SelectionToSnippet, SelectionToSnippetInput } from './components/SelectionToSnippet' import { SelectionToTask } from './components/SelectionToTask' const BallonMarkToolbarButtons = () => { + const toolbarState = useBalloonToolbarStore((s) => s.toolbarState) + // const setToolbarState = useBalloonToolbarStore((s) => s.setToolbarState) + const editor = usePlateEditorRef() const arrow = false @@ -67,98 +71,105 @@ const BallonMarkToolbarButtons = () => { return ( - } - tooltip={{ content: 'Heading 1', ...tooltip }} - /> - - } - tooltip={{ content: 'Heading 2', ...tooltip }} - /> - - } - tooltip={{ content: 'Heading 3', ...tooltip }} - /> - - - } - /> - } - /> - } - /> - - - - } - tooltip={{ content: 'Quote', ...tooltip }} - /> - - } - tooltip={{ content: 'Bullet List', ...tooltip }} - /> - - } - tooltip={{ content: 'Ordered List', ...tooltip }} - /> - - - - } - tooltip={{ content: 'Bold (⌘B)', ...tooltip }} - /> - } - /> - } - tooltip={{ content: 'Italic (⌘I)', ...tooltip }} - /> - } /> - - - - } - tooltip={{ content: 'Convert Blocks to Task', ...tooltip }} - /> - - } - tooltip={{ content: 'Convert Blocks to New Node', ...tooltip }} - /> - - } - tooltip={{ content: 'Convert Blocks to New Snippet', ...tooltip }} - /> - {/* - } /> */} - {/* Looses focus when used. */} + { + { + normal: ( + <> + } + tooltip={{ content: 'Heading 1', ...tooltip }} + /> + + } + tooltip={{ content: 'Heading 2', ...tooltip }} + /> + + } + tooltip={{ content: 'Heading 3', ...tooltip }} + /> + + + } + /> + } + /> + } + /> + + + + } + tooltip={{ content: 'Quote', ...tooltip }} + /> + + } + tooltip={{ content: 'Bullet List', ...tooltip }} + /> + + } + tooltip={{ content: 'Ordered List', ...tooltip }} + /> + + + + } + tooltip={{ content: 'Bold (⌘B)', ...tooltip }} + /> + } + /> + } + tooltip={{ content: 'Italic (⌘I)', ...tooltip }} + /> + } /> + + + + } + tooltip={{ content: 'Convert Blocks to Task', ...tooltip }} + /> + + } + tooltip={{ content: 'Convert Blocks to New Node', ...tooltip }} + /> + + } + tooltip={{ content: 'Convert Blocks to New Snippet', ...tooltip }} + /> + + ), + 'new-note': , + 'new-snippet': + }[toolbarState] + } ) } diff --git a/apps/webapp/src/Components/Editor/BalloonToolbar/components/SelectionToNode.tsx b/apps/webapp/src/Components/Editor/BalloonToolbar/components/SelectionToNode.tsx index d34afcca7..4e58b7868 100644 --- a/apps/webapp/src/Components/Editor/BalloonToolbar/components/SelectionToNode.tsx +++ b/apps/webapp/src/Components/Editor/BalloonToolbar/components/SelectionToNode.tsx @@ -1,20 +1,28 @@ import { ToolbarButton, ToolbarButtonProps } from '@udecode/plate' import { getPreventDefaultHandler, usePlateEditorState } from '@udecode/plate-core' -import React from 'react' +import React, { useEffect } from 'react' import { useTransform } from './useTransform' +import fileList2Line from '@iconify/icons-ri/file-list-2-line' + +import { useBalloonToolbarStore, BalloonToolbarInputWrapper, Input } from '@mexit/shared' +import { Icon } from '@iconify/react' +// import { Input } from '@style/Form' /** * Toolbar button to Create new note from editor selection */ export const SelectionToNode = ({ ...props }: ToolbarButtonProps) => { const editor = usePlateEditorState()! - const { selectionToNode, isConvertable } = useTransform() + const { isConvertable } = useTransform() + const setToolbarState = useBalloonToolbarStore((s) => s.setToolbarState) return ( setToolbarState('new-note')) + : undefined } // Fade out when sync is selected styles={{ root: { opacity: !!editor?.selection && isConvertable(editor) ? 1 : 0.25 } }} @@ -22,3 +30,46 @@ export const SelectionToNode = ({ ...props }: ToolbarButtonProps) => { /> ) } + +export const SelectionToNodeInput = () => { + const editor = usePlateEditorState()! + const setOpen = useBalloonToolbarStore((s) => s.setOpen) + const { selectionToNode, isConvertable } = useTransform() + + const inputRef = React.useRef(null) + + useEffect(() => { + const timeoutId = setTimeout(() => { + if (inputRef.current) { + inputRef.current.focus() + } + }, 1) + return () => clearTimeout(timeoutId) + }, [inputRef]) + + return ( + + + { + if (e.key === 'Enter') { + if (!!editor?.selection && isConvertable(editor)) { + const inputVal = e.currentTarget?.value + // console.log('We got that val', { inputVal }) + if (inputVal !== '') { + selectionToNode(editor, inputVal ?? undefined) + } else selectionToNode(editor) + } + setOpen(false) + } + if (e.key === 'Escape') { + setOpen(false) + // setToolbarState('normal') + } + }} + /> + + ) +} diff --git a/apps/webapp/src/Components/Editor/BalloonToolbar/components/SelectionToSnippet.tsx b/apps/webapp/src/Components/Editor/BalloonToolbar/components/SelectionToSnippet.tsx index c4d6f4772..e95cfe2c1 100644 --- a/apps/webapp/src/Components/Editor/BalloonToolbar/components/SelectionToSnippet.tsx +++ b/apps/webapp/src/Components/Editor/BalloonToolbar/components/SelectionToSnippet.tsx @@ -1,20 +1,26 @@ +import quillPenLine from '@iconify/icons-ri/quill-pen-line' +import { BalloonToolbarInputWrapper, useBalloonToolbarStore, Input } from '@mexit/shared' import { ToolbarButton, ToolbarButtonProps } from '@udecode/plate' import { getPreventDefaultHandler, usePlateEditorState } from '@udecode/plate-core' -import React from 'react' +import React, { useEffect } from 'react' import { useTransform } from './useTransform' +import { Icon } from '@iconify/react' /** * Toolbar button to Create new note from editor selection */ export const SelectionToSnippet = ({ ...props }: ToolbarButtonProps) => { const editor = usePlateEditorState()! - const { selectionToSnippet, isConvertable } = useTransform() + const { isConvertable } = useTransform() + const setToolbarState = useBalloonToolbarStore((s) => s.setToolbarState) return ( setToolbarState('new-snippet')) + : undefined } // Fade out when sync is selected styles={{ root: { opacity: !!editor?.selection && isConvertable(editor) ? 1 : 0.25 } }} @@ -22,3 +28,47 @@ export const SelectionToSnippet = ({ ...props }: ToolbarButtonProps) => { /> ) } + +export const SelectionToSnippetInput = () => { + const editor = usePlateEditorState()! + const setOpen = useBalloonToolbarStore((s) => s.setOpen) + const { selectionToSnippet, isConvertable } = useTransform() + + const inputRef = React.useRef(null) + + useEffect(() => { + const timeoutId = setTimeout(() => { + if (inputRef.current) { + inputRef.current.focus() + } + }, 1) + return () => clearTimeout(timeoutId) + }, [inputRef]) + + return ( + + + { + if (e.key === 'Enter') { + if (!!editor?.selection && isConvertable(editor)) { + const inputVal = e.currentTarget?.value + // console.log('We got that val', { inputVal }) + if (inputVal !== '') { + selectionToSnippet(editor, inputVal ?? undefined) + } else selectionToSnippet(editor) + } + setOpen(false) + } + if (e.key === 'Escape') { + setOpen(false) + // setToolbarState('normal') + } + }} + /> + + ) +} + diff --git a/apps/webapp/src/Components/Editor/BalloonToolbar/components/useTransform.ts b/apps/webapp/src/Components/Editor/BalloonToolbar/components/useTransform.ts index 288e0a408..b05997ede 100644 --- a/apps/webapp/src/Components/Editor/BalloonToolbar/components/useTransform.ts +++ b/apps/webapp/src/Components/Editor/BalloonToolbar/components/useTransform.ts @@ -1,6 +1,7 @@ import { deleteText, getNodeEntries, + getNodeFragment, getPath, getSelectionText, insertNodes, @@ -33,9 +34,12 @@ import { useSnippets } from '../../../../Hooks/useSnippets' import { useUpdater } from '../../../../Hooks/useUpdater' import { useEditorStore } from '../../../../Stores/useEditorStore' import { convertValueToTasks } from '../../../../Utils/convertValueToTasks' +import { cleanEditorId } from '../../../Todo' +import { useDataStore } from '../../../../Stores/useDataStore' +import { useOpenToast } from '../../../Toast/useOpenToast' export const useTransform = () => { - const node = useEditorStore((state) => state.node) + const { openNoteToast, openSnippetToast } = useOpenToast() const { updateSnippet } = useSnippets() const { createNewNote } = useCreateNewNote() const { updater } = useUpdater() @@ -164,7 +168,7 @@ export const useTransform = () => { * Inserts the link of new node in place of the selection * @param editor */ - const selectionToNode = (editor: TEditor) => { + const selectionToNode = (editor: TEditor, title?: string) => { if (!editor.selection) return if (!isConvertable(editor)) return @@ -187,24 +191,55 @@ export const useTransform = () => { const selText = getSelectionText(editor) - const value = nodes.map(([node, _path]) => { - return node - }) const isInline = lowest.length === 1 - const putContent = selText.length > NODE_PATH_CHAR_LENGTH + // Only query for lowest value if selection is inline + const lowestValue = isInline ? getNodeFragment(editor, editor.selection) : [] + const value = isInline + ? lowestValue + : nodes.map(([node, _path]) => { + return node + }) const text = convertContentToRawText(value, NODE_PATH_SPACER) - const parentPath = useEditorStore.getState().node.title - const path = parentPath + SEPARATOR + (isInline ? getSlug(selText) : getSlug(text)) - - const note = createNewNote({ - path, - noteContent: putContent ? value : defaultContent.content, - namespace: node?.namespace, - noRedirect: true - }) - replaceSelectionWithLink(editor, note?.nodeid, isInline) + const editorId = editor.id as string + const nodeid = cleanEditorId(editorId) + + const ilinks = useDataStore.getState().ilinks + const node = ilinks.find((n) => n.nodeid === nodeid) + + if (node) { + const parentPath = node.path + const namespace = node.namespace + const childTitle = title ?? (isInline ? getSlug(selText) : getSlug(text)) + const path = parentPath + SEPARATOR + childTitle + + // mog('selectionToNode ', { + // parentPath, + // lowest, + // lowestValue, + // value, + // childTitle, + // path, + // namespace, + // editorId, + // nodeid + // }) + + const note = createNewNote({ + path, + noteContent: value, + namespace: namespace, + noRedirect: true + }) + + replaceSelectionWithLink(editor, note?.nodeid, isInline) + + if (note) { + // TODO: Add Open Toast + openNoteToast(note.nodeid, note.path) + } + } }) } @@ -235,12 +270,13 @@ export const useTransform = () => { // mog('We are here', { esl: editor.selection, selectionPath, nodes, value, text, path }) }) } + /** * Converts selection to new snippet * Shows notification of snippet creation * @param editor */ - const selectionToSnippet = (editor: TEditor) => { + const selectionToSnippet = (editor: TEditor, title?: string) => { if (!editor.selection) return if (!isConvertable(editor)) return @@ -259,7 +295,7 @@ export const useTransform = () => { }) const snippetId = generateSnippetId() - const snippetTitle = genereateName().dashed + const snippetTitle = title ?? genereateName().dashed const newSnippet = { id: snippetId, title: snippetTitle, @@ -271,8 +307,9 @@ export const useTransform = () => { // addSnippet() // mog('We are here', { esl: editor.selection, selectionPath, nodes, value }) + // TODO: Show toast with open + openSnippetToast(snippetId, snippetTitle) - toast(`Snippet created [[${snippetTitle}]]`, { duration: 5000 }) // setContent(nodeid, value) // saveData() // mog('We are here', { esl: editor.selection, selectionPath, nodes, value, text, path }) diff --git a/apps/webapp/src/Components/Toast/useOpenToast.tsx b/apps/webapp/src/Components/Toast/useOpenToast.tsx new file mode 100644 index 000000000..0067f3586 --- /dev/null +++ b/apps/webapp/src/Components/Toast/useOpenToast.tsx @@ -0,0 +1,45 @@ +import { InteractiveToast } from '@mexit/shared' +import React from 'react' +import toast from 'react-hot-toast' +import { useNavigation } from '../../Hooks/useNavigation' +import { NavigationType, ROUTE_PATHS, useRouting } from '../../Hooks/useRouting' +import { useSnippetStore } from '../../Stores/useSnippetStore' + +export const useOpenToast = () => { + const { push } = useNavigation() + const { goTo } = useRouting() + const loadSnippet = useSnippetStore((store) => store.loadSnippet) + + const openNoteToast = (nodeid: string, title: string) => { + toast.custom((t) => ( + { + push(nodeid) + goTo(ROUTE_PATHS.node, NavigationType.push, nodeid) + // console.log('We are here') + }} + /> + )) + } + + const openSnippetToast = (snippetid: string, title: string) => { + toast.custom((t) => ( + { + loadSnippet(snippetid) + goTo(ROUTE_PATHS.snippet, NavigationType.push, snippetid) + // console.log('We are here') + }} + /> + )) + } + + return { openNoteToast, openSnippetToast } +} + diff --git a/apps/webapp/src/Components/Todo/index.tsx b/apps/webapp/src/Components/Todo/index.tsx index e40dee41e..ba51985d1 100644 --- a/apps/webapp/src/Components/Todo/index.tsx +++ b/apps/webapp/src/Components/Todo/index.tsx @@ -7,7 +7,7 @@ import { NODE_ID_PREFIX, SNIPPET_PREFIX } from '@mexit/core' import { TodoBase } from './Todo' -const cleanEditorId = (editorId: string) => { +export const cleanEditorId = (editorId: string) => { /* * Find substring of form NODE_{} in editorid */ diff --git a/libs/shared/src/Hooks/useBalloonToolbarPopper.ts b/libs/shared/src/Hooks/useBalloonToolbarPopper.ts index d0c31955e..d4a6ca1c6 100644 --- a/libs/shared/src/Hooks/useBalloonToolbarPopper.ts +++ b/libs/shared/src/Hooks/useBalloonToolbarPopper.ts @@ -11,6 +11,7 @@ import { flip, getSelectionBoundingClientRect, offset, + shift, useVirtualFloating, UseVirtualFloatingOptions, UseVirtualFloatingReturn @@ -18,18 +19,30 @@ import { import { useFocused } from 'slate-react' import create from 'zustand' + + +type ToolbarState = 'normal' | 'new-note' | 'new-snippet' + interface BalloonToolbarStore { - isHidden: boolean - setIsHidden: (isHidden: boolean) => void - isFocused: boolean - setIsFocused: (isFocused: boolean) => void + open: boolean + setOpen: (open: boolean) => void + // isHidden: boolean + // setIsHidden: (isHidden: boolean) => void + // isFocused: boolean + // setIsFocused: (isFocused: boolean) => void + toolbarState: ToolbarState + setToolbarState: (state: ToolbarState) => void } export const useBalloonToolbarStore = create((set, get) => ({ - isHidden: true, - setIsHidden: (isHidden) => set({ isHidden }), - isFocused: false, - setIsFocused: (isFocused) => set({ isFocused }) + open: false, + setOpen: (open) => set({ open }), + // isHidden: true, + // setIsHidden: (isHidden) => set({ isHidden }), + // isFocused: false, + // setIsFocused: (isFocused) => set({ isFocused }), + toolbarState: 'normal', + setToolbarState: (state) => set({ toolbarState: state }) })) export const useFloatingToolbar = ({ @@ -42,10 +55,14 @@ export const useFloatingToolbar = ({ const focusedEditorId = useEventEditorSelectors.focus() const editor = useEditorState() const focused = useFocused() + const toolbarState = useBalloonToolbarStore((s) => s.toolbarState) + const setToolbarState = useBalloonToolbarStore((s) => s.setToolbarState) const [waitForCollapsedSelection, setWaitForCollapsedSelection] = useState(false) - const [open, setOpen] = useState(false) + // const [open, setOpen] = useState(false) + const open = useBalloonToolbarStore((s) => s.open) + const setOpen = useBalloonToolbarStore((s) => s.setOpen) const selectionExpanded = editor && isSelectionExpanded(editor) const selectionText = editor && getSelectionText(editor) @@ -63,7 +80,9 @@ export const useFloatingToolbar = ({ }, [focused, selectionExpanded]) useEffect(() => { - if (!selectionExpanded || !selectionText || editor.id !== focusedEditorId) { + if ((!selectionExpanded || !selectionText || editor.id !== focusedEditorId) && toolbarState === 'normal') { + setOpen(false) + } else if (toolbarState !== 'normal' && editor.id === focusedEditorId) { setOpen(false) } else if (selectionText && selectionExpanded && !waitForCollapsedSelection) { setOpen(true) @@ -75,6 +94,7 @@ export const useFloatingToolbar = ({ { middleware: [ offset(12), + shift(), flip({ padding: 150 }) @@ -92,6 +112,12 @@ export const useFloatingToolbar = ({ const selectionTextLength = selectionText?.length ?? 0 + useEffect(() => { + if (!open) { + setToolbarState('normal') + } + }, [open]) + useEffect(() => { if (selectionTextLength > 0) { update?.() @@ -100,3 +126,4 @@ export const useFloatingToolbar = ({ return { ...floatingResult, open } } + diff --git a/libs/shared/src/Style/BalloonToolbar.styles.ts b/libs/shared/src/Style/BalloonToolbar.styles.ts index 213cce0ff..86de07698 100644 --- a/libs/shared/src/Style/BalloonToolbar.styles.ts +++ b/libs/shared/src/Style/BalloonToolbar.styles.ts @@ -135,3 +135,15 @@ export const BalloonToolbarBase = styled(ToolbarBase)` border-radius: ${({ theme }) => theme.borderRadius.tiny}; } ` + +export const BalloonToolbarInputWrapper = styled.div` + display: flex; + align-items: center; + gap: ${({ theme }) => theme.spacing.small}; + padding: ${({ theme }) => theme.spacing.tiny}; + + svg { + width: 1.2rem; + height: 1.2rem; + } +` From 3db24c79229145e01e1a51149a83131ee3f9ee7b Mon Sep 17 00:00:00 2001 From: xypnox Date: Tue, 4 Oct 2022 20:56:31 +0530 Subject: [PATCH 2/3] Remove unused link button --- .../BalloonToolbar/components/LinkButton.tsx | 165 ------------------ .../components/LinkButton.styles.tsx | 61 ------- .../BalloonToolbar/components/LinkButton.tsx | 161 ----------------- libs/shared/src/Style/LinkButton.styles.tsx | 61 ------- 4 files changed, 448 deletions(-) delete mode 100644 apps/extension/src/Components/Editor/BalloonToolbar/components/LinkButton.tsx delete mode 100644 apps/webapp/src/Components/Editor/BalloonToolbar/components/LinkButton.styles.tsx delete mode 100644 apps/webapp/src/Components/Editor/BalloonToolbar/components/LinkButton.tsx delete mode 100644 libs/shared/src/Style/LinkButton.styles.tsx diff --git a/apps/extension/src/Components/Editor/BalloonToolbar/components/LinkButton.tsx b/apps/extension/src/Components/Editor/BalloonToolbar/components/LinkButton.tsx deleted file mode 100644 index 2683ec056..000000000 --- a/apps/extension/src/Components/Editor/BalloonToolbar/components/LinkButton.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import React, { useEffect, useState } from 'react' - -import Tippy, { TippyProps } from '@tippyjs/react' -// optional -import { - ELEMENT_LINK, - getAboveNode, - getPlateEditorRef, - getPluginType, - isCollapsed, - isEditorFocused, - LinkToolbarButtonProps, - someNode, - unwrapNodes -} from '@udecode/plate' -import { useForm } from 'react-hook-form' - -import { mog } from '@mexit/core' -import { - useBalloonToolbarStore, - upsertLinkAtSelection, - clearAllSelection, - HeadlessButton, - LinkButtonStyled -} from '@mexit/shared' - -type LinkButtonProps = LinkToolbarButtonProps - -const LinkButton = ({ getLinkUrl, ...props }: LinkButtonProps) => { - const editor = getPlateEditorRef() - - const type = getPluginType(editor, ELEMENT_LINK) - const isFocused = useBalloonToolbarStore((s) => s.isFocused) - const setIsHidden = useBalloonToolbarStore((s) => s.setIsHidden) - const setIsFocused = useBalloonToolbarStore((s) => s.setIsFocused) - - const isLink = !!editor?.selection && someNode(editor, { match: { type } }) - const [inp, setInp] = useState({ - prev: '' - }) - - const { - register, - handleSubmit, - // watch, - // formState: { errors }, - getValues, - reset - } = useForm() - - useEffect(() => { - if (!editor) return - const linkNode = getAboveNode(editor, { - match: { type } - }) - try { - if (inp.prev === '' && linkNode) { - setInp({ - prev: linkNode[0].url as string - }) - } - } catch (e) { - mog("useEffect couldn't get the input from linkNode", { e }) - } - }, [editor, inp.prev, type]) - - const extractLinkUrl = async (): Promise<{ url: string; linkNode: any }> => { - // Blur focus returns - if (!editor || isEditorFocused(editor)) return - - const linkNode = getAboveNode(editor, { - match: { type } - }) - - let url = '' - if (getLinkUrl) { - const tempUrl = await getLinkUrl(inp.prev) - if (tempUrl) { - url = tempUrl - } - } else { - // Get url from user - const val = getValues() - // console.log({ val }); - - if (val['link-input']) url = val['link-input'] - } - - return { url, linkNode: linkNode } - } - - const onSubmitLink = async () => { - if (!editor) return - const d = await extractLinkUrl() - if (d === undefined) return - const { url, linkNode } = d - - // mog('Insertion Insterion', { url, linkNode }) - // Inserting of the link - const sel = editor.selection - if (url) { - // mog('Insertion Insterion 2', { url, linkNode, sel }) - if (linkNode && sel) { - // mog('Insertion Insterion 3', { url, linkNode, sel }) - unwrapNodes(editor, { - at: sel, - match: { type: getPluginType(editor, ELEMENT_LINK) } - }) - } else { - const shouldWrap: boolean = linkNode !== undefined && isCollapsed(sel) - // mog('Insertion Insterion 4', { url, linkNode, sel, shouldWrap }) - upsertLinkAtSelection(editor, { url, wrap: shouldWrap, at: sel }) - } - } - - clearAllSelection(editor as any) - setInp({ prev: '' }) - reset() - } - - const { icon, tooltip } = props - - const tooltipProps: TippyProps = { - content: '', - arrow: true, - offset: [0, 17], - delay: 0, - duration: [200, 0], - hideOnClick: false, - ...tooltip - } - - const linkInput = ( - -
{ - // When focus is lost, reset the state, hide toolbar - clearAllSelection(editor as any) - setIsFocused(false) - setIsHidden(true) - }} - > - - {icon} - - { - // When mouse click is captured, don't hide the toolbar - setIsFocused(true) - }} - placeholder="Paste link here..." - defaultValue={inp.prev} - type="text" - {...register('link-input')} - /> -
-
- ) - - return tooltip ? {linkInput} : linkInput -} - -export default LinkButton diff --git a/apps/webapp/src/Components/Editor/BalloonToolbar/components/LinkButton.styles.tsx b/apps/webapp/src/Components/Editor/BalloonToolbar/components/LinkButton.styles.tsx deleted file mode 100644 index 36c364047..000000000 --- a/apps/webapp/src/Components/Editor/BalloonToolbar/components/LinkButton.styles.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { HeadlessButton } from '@mexit/shared' -import styled, { css } from 'styled-components' - -export const LinkButtonStyled = styled.span<{ focused: boolean }>` - display: flex; - cursor: pointer; - align-items: center; - justify-content: center; - align-self: middle; - padding: ${({ theme }) => theme.spacing.tiny} 0; - - user-select: all; - - form { - display: flex; - align-items: center; - justify-content: center; - border: 1px solid transparent; - border-radius: ${({ theme }) => theme.borderRadius.tiny}; - - ${HeadlessButton} { - display: flex; - align-items: center; - justify-content: center; - color: ${({ theme }) => theme.colors.text.default}; - border-radius: ${({ theme }) => theme.borderRadius.tiny}; - } - input { - width: 0px; - opacity: 0; - transition: opacity 0.2s ease, width 0.2s ease; - color: ${({ theme }) => theme.colors.text.subheading}; - border: none; - outline: none; - background: transparent; - height: 1.5rem; - &::placeholder { - color: ${({ theme }) => theme.colors.text.fade}; - opacity: 0.5; - } - } - - &:hover { - color: ${({ theme }) => theme.colors.primary}; - background: ${({ theme }) => theme.colors.gray[9]}; - border: 1px solid ${({ theme }) => theme.colors.primary}; - input { - width: inherit; - opacity: 1; - } - } - ${({ focused }) => - focused && - css` - input { - width: inherit; - opacity: 1; - } - `} - } -` diff --git a/apps/webapp/src/Components/Editor/BalloonToolbar/components/LinkButton.tsx b/apps/webapp/src/Components/Editor/BalloonToolbar/components/LinkButton.tsx deleted file mode 100644 index cb740e6c3..000000000 --- a/apps/webapp/src/Components/Editor/BalloonToolbar/components/LinkButton.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import React, { useEffect, useState } from 'react' - -import Tippy, { TippyProps } from '@tippyjs/react' -import { - ELEMENT_LINK, - getAboveNode, - getPlateEditorRef, - getPluginType, - isCollapsed, - isEditorFocused, - LinkToolbarButtonProps, - someNode, - unwrapNodes -} from '@udecode/plate' -import { useForm } from 'react-hook-form' - -import { mog } from '@mexit/core' -import { HeadlessButton, upsertLinkAtSelection, useBalloonToolbarStore } from '@mexit/shared' -import { clearAllSelection } from '@mexit/shared' - -import { LinkButtonStyled } from './LinkButton.styles' - -type LinkButtonProps = LinkToolbarButtonProps - -const LinkButton = ({ getLinkUrl, ...props }: LinkButtonProps) => { - const editor = getPlateEditorRef() - - const type = getPluginType(editor, ELEMENT_LINK) - const isFocused = useBalloonToolbarStore((s) => s.isFocused) - const setIsHidden = useBalloonToolbarStore((s) => s.setIsHidden) - const setIsFocused = useBalloonToolbarStore((s) => s.setIsFocused) - - const isLink = !!editor?.selection && someNode(editor, { match: { type } }) - const [inp, setInp] = useState({ - prev: '' - }) - - const { - register, - handleSubmit, - // watch, - // formState: { errors }, - getValues, - reset - } = useForm() - - useEffect(() => { - if (!editor) return - const linkNode = getAboveNode(editor, { - match: { type } - }) - try { - if (inp.prev === '' && linkNode) { - setInp({ - prev: linkNode[0].url as string - }) - } - } catch (e) { - mog("useEffect couldn't get the input from linkNode", { e }) - } - }, [editor, inp.prev, type]) - - const extractLinkUrl = async (): Promise<{ url: string; linkNode: any }> => { - // Blur focus returns - if (!editor || isEditorFocused(editor)) return - - const linkNode = getAboveNode(editor, { - match: { type } - }) - - let url = '' - if (getLinkUrl) { - const tempUrl = await getLinkUrl(inp.prev) - if (tempUrl) { - url = tempUrl - } - } else { - // Get url from user - const val = getValues() - // console.log({ val }); - - if (val['link-input']) url = val['link-input'] - } - - return { url, linkNode: linkNode } - } - - const onSubmitLink = async () => { - if (!editor) return - const d = await extractLinkUrl() - if (d === undefined) return - const { url, linkNode } = d - - // mog('Insertion Insterion', { url, linkNode }) - // Inserting of the link - const sel = editor.prevSelection - if (url) { - // mog('Insertion Insterion 2', { url, linkNode, sel }) - if (linkNode && sel) { - // mog('Insertion Insterion 3', { url, linkNode, sel }) - unwrapNodes(editor, { - at: sel, - match: { type: getPluginType(editor, ELEMENT_LINK) } - }) - } else { - const shouldWrap: boolean = linkNode !== undefined && isCollapsed(sel) - // mog('Insertion Insterion 4', { url, linkNode, sel, shouldWrap }) - upsertLinkAtSelection(editor, { url, wrap: shouldWrap, at: sel }) - } - } - - clearAllSelection(editor as any) - setInp({ prev: '' }) - reset() - } - - const { icon, tooltip } = props - - const tooltipProps: TippyProps = { - content: '', - arrow: true, - offset: [0, 17], - delay: 0, - duration: [200, 0], - hideOnClick: false, - ...tooltip - } - - const linkInput = ( - -
{ - // When focus is lost, reset the state, hide toolbar - clearAllSelection(editor as any) - setIsFocused(false) - setIsHidden(true) - }} - > - - {icon} - - { - // When mouse click is captured, don't hide the toolbar - setIsFocused(true) - }} - placeholder="Paste link here..." - defaultValue={inp.prev} - type="text" - {...register('link-input')} - /> -
-
- ) - - return tooltip ? {linkInput} : linkInput -} - -export default LinkButton diff --git a/libs/shared/src/Style/LinkButton.styles.tsx b/libs/shared/src/Style/LinkButton.styles.tsx deleted file mode 100644 index 36c364047..000000000 --- a/libs/shared/src/Style/LinkButton.styles.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { HeadlessButton } from '@mexit/shared' -import styled, { css } from 'styled-components' - -export const LinkButtonStyled = styled.span<{ focused: boolean }>` - display: flex; - cursor: pointer; - align-items: center; - justify-content: center; - align-self: middle; - padding: ${({ theme }) => theme.spacing.tiny} 0; - - user-select: all; - - form { - display: flex; - align-items: center; - justify-content: center; - border: 1px solid transparent; - border-radius: ${({ theme }) => theme.borderRadius.tiny}; - - ${HeadlessButton} { - display: flex; - align-items: center; - justify-content: center; - color: ${({ theme }) => theme.colors.text.default}; - border-radius: ${({ theme }) => theme.borderRadius.tiny}; - } - input { - width: 0px; - opacity: 0; - transition: opacity 0.2s ease, width 0.2s ease; - color: ${({ theme }) => theme.colors.text.subheading}; - border: none; - outline: none; - background: transparent; - height: 1.5rem; - &::placeholder { - color: ${({ theme }) => theme.colors.text.fade}; - opacity: 0.5; - } - } - - &:hover { - color: ${({ theme }) => theme.colors.primary}; - background: ${({ theme }) => theme.colors.gray[9]}; - border: 1px solid ${({ theme }) => theme.colors.primary}; - input { - width: inherit; - opacity: 1; - } - } - ${({ focused }) => - focused && - css` - input { - width: inherit; - opacity: 1; - } - `} - } -` From c7583e4089f0dcc96f6559ffcb0051d6306d53d3 Mon Sep 17 00:00:00 2001 From: xypnox Date: Tue, 4 Oct 2022 20:58:42 +0530 Subject: [PATCH 3/3] Remove link button style export --- libs/shared/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/shared/src/index.ts b/libs/shared/src/index.ts index 6b0d10392..d81c81829 100644 --- a/libs/shared/src/index.ts +++ b/libs/shared/src/index.ts @@ -37,7 +37,6 @@ export * from './Style/IconPicker.style' export * from './Style/Infobar' export * from './Style/Integrations' export * from './Style/Layouts' -export * from './Style/LinkButton.styles' export * from './Style/Loading' export * from './Style/Mentions' export * from './Style/Menu'