Last active
August 18, 2022 12:39
-
-
Save diegohaz/c48c82775c0ac36fda45987e73e9787c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type LinkProps = AnchorHTMLAttributes<HTMLAnchorElement>; | |
const Link = createBlock<LinkProps>((props) => { | |
const { onSelectionChange, selectBlockContents } = useEditorState(props); | |
const popover = usePopoverState({ portal: true }); | |
const [href, setHref] = useState(props.href); | |
useEffect(() => { | |
setHref(props.href); | |
}, [props.href]); | |
useEffect(() => { | |
return onSelectionChange((selection) => { | |
if (selection.startContainerIds.includes(props.id) && selection.endContainerIds.includes(props.id)) { | |
popover.show(); | |
} | |
}); | |
}, [onSelect, props.id, popover.show]); | |
return ( | |
<> | |
<PopoverDisclosure | |
as="a" | |
state={popover} | |
{...props} | |
href={href} | |
onClick={(event) => { | |
props.onClick?.(event); | |
if (event.defaultPrevented) return; | |
event.preventDefault(); | |
selectBlockConents(props.id); | |
}} | |
> | |
{(disclosureProps) => ( | |
<Text as="a" {...disclosureProps} /> | |
)} | |
</PopoverDisclosure> | |
<Popover autoFocusOnShow={false} state={popover}> | |
<a href={href} /> | |
<button>Edit</button> | |
</Popover> | |
</> | |
); | |
}); | |
const ListItem = createBlock((props) => { | |
const { value, insertBlock, removeBlock } = useEditorState(props); | |
useEnter((defaultAction) => { | |
if (value.length) { | |
insertBlock("ListItem"); | |
} else { | |
removeBlock(props.id); | |
defaultAction(); | |
} | |
}, [value, insertBlock, removeBlock, props.id]); | |
return <Text as="li" {...props} />; | |
}); | |
const ListItem = createEditorComponent((props) => { | |
const editor = useEditorState(props); | |
useEditorEnter(() => { | |
editor.insertElement("ListItem"); | |
}, [editor.insertElement]); | |
return <Text as="li" {...props} />; | |
}); | |
type ListProps = { | |
inputs: { | |
type: "ordered" | "unordered"; | |
}; | |
}; | |
const List = createEditorComponent<ListProps>((props) => { | |
const editor = useEditorState({ | |
...props, | |
defaultValue: [{ | |
type: "ListItem", | |
id: `${props.id}-1`, | |
}], | |
}); | |
const type = useEditorInput( | |
ToggleGroup, | |
{ | |
...props, | |
name: "type", | |
options: [ | |
{ value: "ordered", label: "Ordered", icon: "Ordered" }, | |
{ value: "unordered", label: "Unordered", icon: "Unordered" }, | |
], | |
} | |
); | |
const component = type === "ordered" ? "ol" : "ul"; | |
// if defaultValue doesn't work | |
useLayoutEffect(() => { | |
if (!editor.value.length) { | |
const selection = { | |
startContainerId: props.id, | |
startOffset: 0, | |
endContainerId: props.id, | |
endOffset: 0, | |
}; | |
editor.insertElement("ListItem", null, selection); | |
} | |
}, [editor.insertElement, editor.value, props.id]); | |
return <EditorComponent as={component} {...props} />; | |
}); | |
type HeadingProps = TextProps & { | |
inputs: { | |
level?: number; | |
}; | |
}; | |
const Heading = createEditorComponent<HeadingProps>((props) => { | |
const level = useEditorInput(HeadingLevel, { ...props, name: "level", label: "Heading level" }); | |
const component = `h${level}`; | |
useEditorReplace("Paragraph"); | |
return <Text as={component} {...props} />; | |
}); | |
Heading.defaultProps = { | |
inputs: { | |
level: 1, | |
}, | |
}; | |
Heading.triggers = { | |
"#{1,6}": (text) => ({ | |
inputs: { | |
level: text.length, | |
}, | |
}); | |
}; | |
const HeadingLevel = createEditorInput<HeadingProps>((props) => { | |
useEditorInputValue(props, "value"); | |
return <div />; | |
}); | |
const defaultComponents = { | |
Paragraph, | |
Bold, | |
Heading, | |
... | |
}; | |
function App() { | |
const editor = useEditorState({ defaultComponents }); | |
editor.getSelection(); // { startContainerId: "id", startOffset: 0, endContainerId: "id", endOffset: 3, collapsed: false } | |
editor.insertElement("Paragraph", null, editor.getSelection()); | |
editor.insertElement(Heading, { inputs: { level: 2 } }); | |
editor.replaceElement(Paragraph); | |
return <Editor state={editor} />; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment