strict typechecking
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Cat /dev/Nulo 2023-04-18 14:18:15 -03:00
parent 2d40d7f9a0
commit 3f9a2f0603
16 changed files with 52 additions and 68 deletions

View file

@ -1,7 +1,7 @@
<script lang="ts">
export let onClose: () => void;
function click(event: Event) {
function click(this: Element, event: Event) {
if (event.target !== this) return;
onClose();
}

View file

@ -1,5 +1,4 @@
<script lang="ts">
import type { Readable } from "svelte/store";
import { yDocToProsemirrorJSON } from "y-prosemirror";
import { Node } from "prosemirror-model";
import type { Doc } from "yjs";
@ -29,7 +28,7 @@
}
});
docs.push({
title: titleNode?.textContent,
title: titleNode ? (titleNode as Node).textContent : undefined,
id: name.replace(/^page\//, ""),
name,
});
@ -45,7 +44,7 @@
$: entries = deriveEntries(ydoc);
$: lastU = lastUpdated(ydoc);
$: sortedEntries = $entries
.sort((a, b) => +$lastU.get(b.name) - +$lastU.get(a.name))
.sort((a, b) => +($lastU.get(b.name) || 0) - +($lastU.get(a.name) || 0))
// TODO: FTS
.filter((x) => (x.title ?? x.id).includes(filter));
// $: console.debug($lastU);

View file

@ -19,7 +19,6 @@
getFirstMarkInSelection,
} from "./ps-utils";
import SimpleMarkItem from "./bubblemenu/SimpleMarkItem.svelte";
import { nanoid } from "nanoid";
import Button from "./bubblemenu/Button.svelte";
import Modal from "../components/Modal.svelte";
import PagePicker from "../components/PagePicker.svelte";
@ -105,7 +104,7 @@
/* https://wicg.github.io/visual-viewport/examples/fixed-to-keyboard.html */
let barStyle = "";
function updateBar() {
const viewport = window.visualViewport;
const viewport = window.visualViewport!;
// Since the bar is position: fixed we need to offset it by the
// visual viewport's offset from the layout viewport origin.
const offsetY = window.innerHeight - viewport.height - viewport.offsetTop;
@ -118,12 +117,12 @@ transform: scale(${1 / viewport.scale});
}
onMount(() => {
window.visualViewport.addEventListener("resize", updateBar);
window.visualViewport.addEventListener("scroll", updateBar);
window.visualViewport!.addEventListener("resize", updateBar);
window.visualViewport!.addEventListener("scroll", updateBar);
});
onDestroy(() => {
window.visualViewport.removeEventListener("resize", updateBar);
window.visualViewport.removeEventListener("scroll", updateBar);
window.visualViewport!.removeEventListener("resize", updateBar);
window.visualViewport!.removeEventListener("scroll", updateBar);
});
</script>

View file

@ -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,
],
});
}

View file

@ -15,7 +15,7 @@
$: isActive = nodeIsActiveFn(type, null, true);
$: command = wrapIn(type);
$: isPossible = command(state, null);
$: isPossible = command(state);
$: actionListener = commandListener(view, command);
</script>

View file

@ -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,

View file

@ -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);
</script>

View file

@ -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;
};
}

View file

@ -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;
},

View file

@ -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;
}

View file

@ -2,7 +2,12 @@ import type { Readable } from "svelte/store";
import type { Doc, Transaction } from "yjs";
export function makeYdocStore<T>(
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<T> => {
@ -10,10 +15,10 @@ export function makeYdocStore<T>(
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));
}

View file

@ -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;

View file

@ -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);

View file

@ -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}`;

View file

@ -13,6 +13,7 @@
*/
"allowJs": true,
"checkJs": true,
"strict": true,
"isolatedModules": true
},
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],