UNPKG

@empoleon/tiptap

Version:

Rich text editor based on tiptap

181 lines (178 loc) 6.4 kB
import { createComponent, mergeProps, template, spread, insert } from 'solid-js/web'; import { factory, useProps, useResolvedStylesApi, Popover, TextInput, Tooltip, UnstyledButton, rem, Button } from '@empoleon/core'; import { useInputState, useDisclosure, useWindowEvent } from '@empoleon/hooks'; import { IconExternalLink, IconLink } from '../icons/Icons.mjs'; import { useRichTextEditorContext } from '../RichTextEditor.context.mjs'; import { RichTextEditorControlBase } from './RichTextEditorControl.mjs'; import classes from '../RichTextEditor.module.css.mjs'; import { splitProps, createSignal } from 'solid-js'; var _tmpl$ = /*#__PURE__*/template(`<div>`); const LinkIcon = props => createComponent(IconLink, props); const defaultProps = {}; const RichTextEditorLinkControl = factory(_props => { const props = useProps("RichTextEditorLinkControl", defaultProps, _props); const [local, others] = splitProps(props, ["classNames", "className", "style", "styles", "vars", "icon", "popoverProps", "disableTooltips", "initialExternal", "ref"]); const ctx = useRichTextEditorContext(); const stylesApiProps = { classNames: local.classNames, styles: local.styles }; const [url, setUrl] = useInputState(""); const [external, setExternal] = createSignal(local.initialExternal); const [opened, { open, close }] = useDisclosure(false); const handleOpen = () => { open(); const linkData = ctx.editor?.getAttributes("link"); setUrl(linkData?.href || ""); setExternal(linkData?.href ? linkData?.target === "_blank" : local.initialExternal); }; const handleClose = () => { close(); setUrl(""); setExternal(local.initialExternal); }; const setLink = () => { handleClose(); url() === "" ? ctx.editor?.chain().focus().extendMarkRange("link").unsetLink().run() : ctx.editor?.chain().focus().extendMarkRange("link").setLink({ href: url(), target: external() ? "_blank" : null }).run(); }; const handleInputKeydown = event => { if (event.key === "Enter") { event.preventDefault(); setLink(); } }; useWindowEvent("edit-link", handleOpen, false); const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi({ classNames: local.classNames, styles: local.styles, props }); return createComponent(Popover, mergeProps({ trapFocus: true, shadow: "md", withinPortal: true, get opened() { return opened(); }, onChange: _opened => !_opened && handleClose(), offset: -44, zIndex: 1e4 }, () => local.popoverProps, { get children() { return [createComponent(Popover.Target, { get children() { return createComponent(RichTextEditorControlBase, mergeProps({ get icon() { return local.icon || LinkIcon; } }, others, { get ["aria-label"]() { return ctx.labels.linkControlLabel; }, get title() { return ctx.labels.linkControlLabel; }, onClick: handleOpen, get active() { return ctx.editor?.isActive("link"); }, ref(r$) { var _ref$ = local.ref; typeof _ref$ === "function" ? _ref$(r$) : local.ref = r$; }, classNames: resolvedClassNames, styles: resolvedStyles, get className() { return local.className; }, get style() { return local.style; }, get variant() { return ctx.variant; } })); } }), createComponent(Popover.Dropdown, mergeProps(() => ctx.getStyles("linkEditorDropdown", stylesApiProps), { get children() { var _el$ = _tmpl$(); spread(_el$, mergeProps(() => ctx.getStyles("linkEditor", stylesApiProps)), false, true); insert(_el$, createComponent(TextInput, { get placeholder() { return ctx.labels.linkEditorInputPlaceholder; }, get ["aria-label"]() { return ctx.labels.linkEditorInputLabel; }, type: "url", get value() { return url(); }, onChange: setUrl, get classNames() { return { input: ctx.getStyles("linkEditorInput", stylesApiProps).className }; }, onKeyDown: handleInputKeydown, get rightSection() { return createComponent(Tooltip, { get label() { return external() ? ctx.labels.linkEditorExternalLink : ctx.labels.linkEditorInternalLink; }, events: { hover: true, focus: true, touch: true }, withinPortal: true, withArrow: true, get disabled() { return local.disableTooltips; }, zIndex: 1e4, children: props2 => createComponent(UnstyledButton, mergeProps({ onClick: () => setExternal(e => !e), "data-active": external || void 0 }, () => ctx.getStyles("linkEditorExternalControl", stylesApiProps), props2, { get children() { return createComponent(IconExternalLink, { get style() { return { width: rem(14), height: rem(14) }; } }); } })) }); } }), null); insert(_el$, createComponent(Button, mergeProps({ variant: "default", onClick: setLink }, () => ctx.getStyles("linkEditorSave", stylesApiProps), { get children() { return ctx.labels.linkEditorSave; } })), null); return _el$; } }))]; } })); }); RichTextEditorLinkControl.classes = classes; RichTextEditorLinkControl.displayName = "@empoleon/tiptap/RichTextEditorLinkControl"; export { RichTextEditorLinkControl }; //# sourceMappingURL=RichTextEditorLinkControl.mjs.map