import { NodeViewProps, NodeViewWrapper, ReactRenderer } from "@tiptap/react";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@unsend/ui/src/popover";
import { cn } from "@unsend/ui/lib/utils";
import { Input } from "@unsend/ui/src/input";
import { Button } from "@unsend/ui/src/button";
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import { SuggestionOptions } from "@tiptap/suggestion";
import tippy, { GetReferenceClientRect } from "tippy.js";
import { CheckIcon, TriangleAlert } from "lucide-react";
export interface VariableOptions {
name: string;
fallback: string;
}
export const VariableList = forwardRef((props: any, ref) => {
const [selectedIndex, setSelectedIndex] = useState(0);
const selectItem = (index: number) => {
const item = props.items[index];
console.log("item: ", item);
if (item) {
props.command({ id: item, name: item, fallback: "" });
}
};
useEffect(() => setSelectedIndex(0), [props.items]);
useImperativeHandle(ref, () => ({
onKeyDown: ({ event }: { event: KeyboardEvent }) => {
if (event.key === "ArrowUp") {
setSelectedIndex(
(selectedIndex + props.items.length - 1) % props.items.length
);
return true;
}
if (event.key === "ArrowDown") {
setSelectedIndex((selectedIndex + 1) % props.items.length);
return true;
}
if (event.key === "Enter") {
selectItem(selectedIndex);
return true;
}
return false;
},
}));
return (
{props?.items?.length ? (
props?.items?.map((item: string, index: number) => (
))
) : (
)}
);
});
VariableList.displayName = "VariableList";
export function getVariableSuggestions(
variables: Array = []
): Omit {
return {
items: ({ query }) => {
return variables
.concat(query.length > 0 ? [query] : [])
.filter((item) => item.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 5);
},
render: () => {
let component: ReactRenderer;
let popup: InstanceType | null = null;
return {
onStart: (props) => {
component = new ReactRenderer(VariableList, {
props,
editor: props.editor,
});
if (!props.clientRect) {
return;
}
popup = tippy("body", {
getReferenceClientRect: props.clientRect as GetReferenceClientRect,
appendTo: () => document.body,
content: component.element,
showOnCreate: true,
interactive: true,
trigger: "manual",
placement: "bottom-start",
});
},
onUpdate(props) {
component.updateProps(props);
if (!props.clientRect) {
return;
}
popup?.[0]?.setProps({
getReferenceClientRect: props.clientRect as GetReferenceClientRect,
});
},
onKeyDown(props) {
if (props.event.key === "Escape") {
popup?.[0].hide();
return true;
}
return component.ref?.onKeyDown(props);
},
onExit() {
if (!popup || !popup?.[0] || !component) {
return;
}
popup?.[0].destroy();
component.destroy();
},
};
},
};
}
export function VariableComponent(props: NodeViewProps) {
const { name, fallback } = props.node.attrs as VariableOptions;
const [fallbackValue, setFallbackValue] = useState(fallback);
const { getPos, editor } = props;
console.log(props.selected);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
props.updateAttributes({
fallback: fallbackValue,
});
};
return (
e.preventDefault()}
onCloseAutoFocus={(e) => e.preventDefault()}
>
Fallback value will be used if the variable value is empty.
);
}