@empoleon/tiptap
Version:
Rich text editor based on tiptap
181 lines (178 loc) • 6.4 kB
JavaScript
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