import { createEffect, on, onMount } from "solid-js";
export function toHtml(raw: string): string {
if (/<\/?[a-z]/i.test(raw)) return raw;
return raw
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/\n/g, "
");
}
const BoldIcon = () => B;
const ItalicIcon = () => I;
const UnderlineIcon = () => U;
const StrikeIcon = () => S;
const HeadingIcon = () => H;
const BulletIcon = () => (
);
const NumberedIcon = () => (
);
const RuleIcon = () => (
);
export type ExecFn = (cmd: string, val?: string) => void;
export function Toolbar(props: { exec: ExecFn; class?: string }) {
const e = props.exec;
function toggleHeading() {
const val = document.queryCommandValue("formatBlock").toLowerCase();
e("formatBlock", val === "h2" ? "p" : "h2");
}
return (
);
}
/* ── Inline editor (Add.tsx, Entry.tsx note view) ── */
interface NoteEditorInlineProps {
initialContent: string;
onContentChange?: (html: string) => void;
onBlur?: (html: string) => void;
onReady?: (el: HTMLDivElement) => void;
autoFocus?: boolean;
/** When this key changes, the editor re-loads initialContent (e.g., switching between vault entries in-place). */
entryKey?: string;
}
export function NoteEditorInline(props: NoteEditorInlineProps) {
let editorRef: HTMLDivElement | undefined;
onMount(() => {
if (!editorRef) return;
editorRef.innerHTML = toHtml(props.initialContent);
if (props.autoFocus !== false) editorRef.focus();
props.onReady?.(editorRef);
});
createEffect(on(() => props.entryKey, (key, prevKey) => {
if (prevKey === undefined || key === prevKey || !editorRef) return;
editorRef.innerHTML = toHtml(props.initialContent);
props.onReady?.(editorRef);
}));
function exec(cmd: string, value?: string) {
document.execCommand(cmd, false, value);
editorRef?.focus();
}
function handleKeyDown(e: KeyboardEvent) {
const mod = e.metaKey || e.ctrlKey;
// Only intercept shortcuts for non-alphanumeric keys to avoid swallowing
// letter input. Letter keys (a–z, etc.) must always pass through freely.
const isLetterKey = e.key.length === 1;
if (isLetterKey) return;
if (mod && e.key === "b") { e.preventDefault(); exec("bold"); }
if (mod && e.key === "i") { e.preventDefault(); exec("italic"); }
if (mod && e.key === "u") { e.preventDefault(); exec("underline"); }
}
return (
props.onContentChange?.(editorRef?.innerHTML ?? "")}
onBlur={() => props.onBlur?.(editorRef?.innerHTML ?? "")}
aria-multiline="true"
aria-label="Note content"
/>
);
}