diff --git a/src/components/Modal.svelte b/src/components/Modal.svelte index 72320a1..beb2cf2 100644 --- a/src/components/Modal.svelte +++ b/src/components/Modal.svelte @@ -1,7 +1,7 @@ diff --git a/src/editor/Editor.svelte b/src/editor/Editor.svelte index 4051cb8..6b855e8 100644 --- a/src/editor/Editor.svelte +++ b/src/editor/Editor.svelte @@ -5,14 +5,14 @@ import { dropCursor } from "prosemirror-dropcursor"; import { gapCursor } from "prosemirror-gapcursor"; import type { XmlFragment } from "yjs"; - import { ySyncPlugin, yCursorPlugin, yUndoPlugin } from "y-prosemirror"; + import { ySyncPlugin, yUndoPlugin } from "y-prosemirror"; import "./editor.css"; import { schema } from "./schema"; import BubbleMenu from "./BubbleMenu.svelte"; import MenuBar from "./MenuBar.svelte"; - import { placeholderPlugin } from "./upload"; + // import { placeholderPlugin } from "./upload"; import { baseKeymap } from "./keymap"; import type { WorldY } from "../lib/doc"; @@ -26,7 +26,7 @@ schema, plugins: [ new Plugin({ - view: (editorView) => { + view: () => { // editorView.dom.parentElement?.replaceWith(editorView.dom); return { update(view, lastState) { @@ -50,7 +50,7 @@ // yCursorPlugin(doc.webrtcProvider.awareness), yUndoPlugin(), keymap(baseKeymap), - placeholderPlugin, + // placeholderPlugin, ], }); } diff --git a/src/editor/menubar/BlockQuoteItem.svelte b/src/editor/menubar/BlockQuoteItem.svelte index f80d221..0441de1 100644 --- a/src/editor/menubar/BlockQuoteItem.svelte +++ b/src/editor/menubar/BlockQuoteItem.svelte @@ -15,7 +15,7 @@ $: isActive = nodeIsActiveFn(type, null, true); $: command = wrapIn(type); - $: isPossible = command(state, null); + $: isPossible = command(state); $: actionListener = commandListener(view, command); diff --git a/src/editor/menubar/BlockSelect.svelte b/src/editor/menubar/BlockSelect.svelte index 9b75423..240c828 100644 --- a/src/editor/menubar/BlockSelect.svelte +++ b/src/editor/menubar/BlockSelect.svelte @@ -10,7 +10,7 @@ const paragraphType = state.schema.nodes.paragraph; const headingType = state.schema.nodes.heading; - $: isPossible = setBlockType(headingType, { level: 1 })(state, null); + $: isPossible = setBlockType(headingType, { level: 1 })(state); $: currentValue = state.selection.to <= state.selection.$from.end() && (state.selection.$from.parent.type == headingType @@ -19,10 +19,12 @@ ? "paragraph" : null); - const onChange = (event) => { + const onChange = ( + event: Event & { currentTarget: EventTarget & HTMLSelectElement } + ) => { event.preventDefault(); - const [type, param] = event.target.value.split(":"); + const [type, param] = event.currentTarget.value.split(":"); if (type === "paragraph") { setBlockType(paragraphType, { align: state.selection.$from.parent.attrs.align, diff --git a/src/editor/menubar/ListItem.svelte b/src/editor/menubar/ListItem.svelte index f90d73a..db6bc68 100644 --- a/src/editor/menubar/ListItem.svelte +++ b/src/editor/menubar/ListItem.svelte @@ -21,7 +21,7 @@ ? state.schema.nodes.bullet_list : kind === ListKind.Ordered ? state.schema.nodes.ordered_list - : null; + : (null as never); const listItemType = state.schema.nodes.list_item; $: iconComponent = kind === ListKind.Unordered @@ -32,7 +32,7 @@ $: isActive = nodeIsActiveFn(type, null, true); $: command = chainCommands(liftListItem(listItemType), wrapInList(type)); - $: isPossible = command(state, null); + $: isPossible = command(state); $: actionListener = commandListener(view, command); diff --git a/src/editor/menubar/UploadItem.svelte b/src/editor/menubar/UploadItem.sveltehold similarity index 100% rename from src/editor/menubar/UploadItem.svelte rename to src/editor/menubar/UploadItem.sveltehold diff --git a/src/editor/ps-utils.ts b/src/editor/ps-utils.ts index 06381d1..7ef25f7 100644 --- a/src/editor/ps-utils.ts +++ b/src/editor/ps-utils.ts @@ -6,11 +6,9 @@ import type { ResolvedPos, Node as ProsemirrorNode, } from "prosemirror-model"; -import type { EditorState, Selection } from "prosemirror-state"; +import type { EditorState } from "prosemirror-state"; import type { EditorView } from "prosemirror-view"; -import type { Align } from "./schema"; - export type Command = ( state: EditorState, dispatch?: EditorView["dispatch"] @@ -176,7 +174,7 @@ export function getAttrFn(attrKey: string): (state: EditorState) => any { return (state) => { let { from, to } = state.selection; let value: any = undefined; - state.doc.nodesBetween(from, to, (node, pos) => { + state.doc.nodesBetween(from, to, (node) => { if (value !== undefined) return false; if (!node.isTextblock) return; if (attrKey in node.attrs) value = node.attrs[attrKey]; @@ -199,10 +197,10 @@ export interface MarkMatch { export function getFirstMarkInSelection( state: EditorState, type: MarkType -): MarkMatch { +): MarkMatch | null { const { to, from } = state.selection; - let match: MarkMatch; + let match: MarkMatch | null = null; state.selection.$from.doc.nodesBetween(from, to, (node, position) => { if (!match) { const mark = type.isInSet(node.marks); @@ -213,25 +211,3 @@ export function getFirstMarkInSelection( return match; } - -export function setAlign(align: Align): Command { - return (state, dispatch) => { - let { from, to } = state.selection; - let node: ProsemirrorNode | null = null; - state.doc.nodesBetween(from, to, (_node, pos) => { - if (node) return false; - if (!_node.isTextblock) return; - if ( - _node.type == state.schema.nodes.paragraph || - _node.type == state.schema.nodes.heading - ) { - node = _node; - } - }); - if (!node) return false; - if (dispatch) - return setBlockType(node.type, { ...node.attrs, align })(state, dispatch); - - return true; - }; -} diff --git a/src/editor/schema.ts b/src/editor/schema.ts index 3d37862..5c137dc 100644 --- a/src/editor/schema.ts +++ b/src/editor/schema.ts @@ -101,8 +101,9 @@ export const schema = new Schema({ tag: "ol", getAttrs(dom) { dom = dom as HTMLElement; + const start = dom.getAttribute("start"); return { - order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1, + order: start ? +start : 1, }; }, }, @@ -141,11 +142,12 @@ export const schema = new Schema({ { tag: "figure", getAttrs(dom) { - const child: HTMLElement = + const child: HTMLElement | null = (dom as Element).querySelector("img") || (dom as Element).querySelector("video") || (dom as Element).querySelector("audio") || (dom as Element).querySelector("iframe"); + if (!child) return false; if (child instanceof HTMLImageElement) { return { src: child.src, kind: "img" }; @@ -156,6 +158,7 @@ export const schema = new Schema({ } else if (child instanceof HTMLIFrameElement) { return { src: child.src, kind: "iframe" }; } + return false; }, }, { @@ -308,9 +311,11 @@ export const schema = new Schema({ getAttrs(dom) { dom = dom as HTMLElement; const href = dom.getAttribute("href"); - if (href.startsWith("/w/")) { + if (href?.startsWith("/w/")) { + const matches = parse(routes.Page).pattern.exec(href); + if (!matches) return false; return { - id: parse(routes.Page).pattern.exec(href)[1], + id: matches[1], }; } else return false; }, diff --git a/src/editor/upload.ts b/src/editor/upload.tshold similarity index 87% rename from src/editor/upload.ts rename to src/editor/upload.tshold index d394726..c86f756 100644 --- a/src/editor/upload.ts +++ b/src/editor/upload.tshold @@ -42,7 +42,7 @@ export const placeholderPlugin = new Plugin({ }); export function findPlaceholder(state: EditorState, id: any): number | null { - const decos: DecorationSet = placeholderPlugin.getState(state); - const found = decos.find(undefined, undefined, (spec) => spec.id == id); - return found.length ? found[0].from : null; + const decos = placeholderPlugin.getState(state); + const found = decos?.find(undefined, undefined, (spec) => spec.id == id); + return found?.length ? found[0].from : null; } diff --git a/src/lib/makeYdocStore.ts b/src/lib/makeYdocStore.ts index 424ecfd..7d527f2 100644 --- a/src/lib/makeYdocStore.ts +++ b/src/lib/makeYdocStore.ts @@ -2,7 +2,12 @@ import type { Readable } from "svelte/store"; import type { Doc, Transaction } from "yjs"; export function makeYdocStore( - handler: (update: Uint8Array, origin: any, ydoc: Doc, tr: Transaction) => T, + handler: ( + update: Uint8Array | null, + origin: any, + ydoc: Doc, + tr: Transaction | null + ) => T, unhandler?: () => void ) { return (ydoc: Doc): Readable => { @@ -10,10 +15,10 @@ export function makeYdocStore( return { subscribe: (run) => { function updateHandler( - update: Uint8Array, + update: Uint8Array | null, origin: any, ydoc: Doc, - tr: Transaction + tr: Transaction | null ) { run(handler(update, origin, ydoc, tr)); } diff --git a/src/main.ts b/src/main.ts index 8a909a1..e736285 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,8 @@ -import './app.css' -import App from './App.svelte' +import "./app.css"; +import App from "./App.svelte"; const app = new App({ - target: document.getElementById('app'), -}) + target: document.getElementById("app")!, +}); -export default app +export default app; diff --git a/src/views/CreateWorld.svelte b/src/views/CreateWorld.svelte index 3d1efae..42ef5df 100644 --- a/src/views/CreateWorld.svelte +++ b/src/views/CreateWorld.svelte @@ -4,11 +4,7 @@ import { router } from "../lib/router"; import { writeWorlds } from "../lib/worldStorage"; - function crear( - event: Event & { readonly submitter: HTMLElement } & { - currentTarget: EventTarget & HTMLFormElement; - } - ) { + function crear(event: Event) { event.preventDefault(); writeWorlds((worlds) => [...worlds, generateNewWorld()]); router.run(routes.ChooseWorld); diff --git a/src/views/ShareWorld.svelte b/src/views/ShareWorld.svelte index 9cd7ff8..8278a44 100644 --- a/src/views/ShareWorld.svelte +++ b/src/views/ShareWorld.svelte @@ -8,6 +8,7 @@ async function joinWorldLink() { const worlds = await loadWorlds(); const worldIdentifier = worlds.find((w) => w.room === worldId); + if (!worldIdentifier) throw new Error("No tenés ese mundo para compartir."); return `${location.origin}${inject(routes.JoinWorld, { worldId: worldIdentifier.room, })}#${worldIdentifier.password}`; diff --git a/tsconfig.json b/tsconfig.json index c4e1c5f..f52d57a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,6 +13,7 @@ */ "allowJs": true, "checkJs": true, + "strict": true, "isolatedModules": true }, "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],