From c63738e17df4d5bfff2049a6d1c445c609c2189e Mon Sep 17 00:00:00 2001 From: Sam Nystrom Date: Thu, 14 Mar 2024 19:29:29 -0400 Subject: fix: fix lots of type errors --- src/NodeEditor.tsx | 32 +++++++++++++++++++++++--------- src/components/ArrowButton.tsx | 4 +++- src/components/Button.tsx | 2 +- src/components/Header.tsx | 4 ++-- src/components/TextInput.tsx | 4 ++-- src/components/index.ts | 35 ++++++++++++++++++++++++----------- src/components/nodes/Input.tsx | 5 +++-- src/components/nodes/Socket.tsx | 2 +- src/components/nodes/index.ts | 9 ++++++--- src/context.ts | 4 ++-- src/index.tsx | 5 ++--- src/node.ts | 1 + src/nodes/Fourier.tsx | 2 +- src/nodes/Intersperse.tsx | 8 ++++---- src/nodes/Linspace.tsx | 2 +- src/nodes/Plot.tsx | 4 ++-- src/nodes/Unzip.tsx | 10 +++++----- src/nodes/Viewer.tsx | 2 +- src/nodes/index.ts | 4 ++-- src/pages/LogIn.tsx | 4 ++-- src/pages/ProjectsList.tsx | 22 +++++++++++++--------- src/pages/SignUp.tsx | 4 ++-- src/types.ts | 18 ++++++++++++++++++ src/wasm.ts | 4 ++-- tsconfig.json | 3 +-- 25 files changed, 124 insertions(+), 70 deletions(-) create mode 100644 src/types.ts diff --git a/src/NodeEditor.tsx b/src/NodeEditor.tsx index a9e7c83..781e64b 100644 --- a/src/NodeEditor.tsx +++ b/src/NodeEditor.tsx @@ -1,16 +1,25 @@ import { useContext, useEffect, useMemo, useCallback, useRef } from 'preact/hooks'; import { signal, computed, batch, useSignal, useComputed, Signal } from '@preact/signals'; import { Pb } from './context.ts'; -import { SocketHandlers } from './node.ts'; +import { NodeComponent, SocketHandlers } from './node.ts'; import { nodeRegistry } from './nodes'; -import type { SocketHandler, NodeInfo } from './node.tsx'; +import type { SocketHandler, NodeInfo } from './node.ts'; import { InputSocket } from './dataflow.ts'; import { Toolbar, ButtonMenu, MenuItem } from './components'; import './NodeEditor.css'; -export const nodeFactory = () => { +interface NodeInstance { + id: number; + component: NodeComponent; + x: Signal; + y: Signal; + inputs: Record>; + outputs: Record>; +} + +const nodeFactory = () => { let nextNodeId = 0; - return (x: number, y: number, { component, func, inputs }: NodeInfo) => { + return (x: number, y: number, { component, func, inputs }: NodeInfo): NodeInstance => { const mapEntries = (obj: {}, f: (x: [string, any]) => [string, any]) => ( Object.fromEntries(Object.entries(obj).map(f)) ); @@ -54,17 +63,22 @@ interface LinkData extends LinkProps { to: { nodeId: number, socket: string }; } -const NodeEditor = ({ user, project }) => { - const pb = useContext(Pb); +export interface NodeEditorProps { + user: string; + project: string; +} + +const NodeEditor = ({ user, project }: NodeEditorProps) => { + const pb = useContext(Pb)!; const offsetX = useSignal(0); const offsetY = useSignal(0); const scale = useSignal(1); const instantiateNode = useMemo(nodeFactory, []); - const svgRef = useRef(null); + const svgRef = useRef(null); - const nodes = useSignal([]); + const nodes = useSignal([]); const currentLink = useSignal>(null); const links = useSignal([]); @@ -225,7 +239,7 @@ const NodeEditor = ({ user, project }) => { scale.value *= 1 + delta; }), []); - const addNode = useCallback((node: NodeInfo) => { + const addNode = useCallback((node: NodeInfo) => { nodes.value = nodes.value.concat(instantiateNode(100, 100, node)); }, []); diff --git a/src/components/ArrowButton.tsx b/src/components/ArrowButton.tsx index ce0c898..a95964e 100644 --- a/src/components/ArrowButton.tsx +++ b/src/components/ArrowButton.tsx @@ -1,7 +1,9 @@ import Button, { ButtonProps } from './Button.tsx'; import './ArrowButton.css'; -const ArrowButton = ({ children, ...props }: ButtonProps) => { +export type ArrowButtonProps = ButtonProps; + +const ArrowButton = ({ children, ...props }: ArrowButtonProps) => { return ( } + {!!title && } diff --git a/src/components/TextInput.tsx b/src/components/TextInput.tsx index 026b062..c74828d 100644 --- a/src/components/TextInput.tsx +++ b/src/components/TextInput.tsx @@ -4,12 +4,12 @@ import './TextInput.css'; export interface TextInputProps { signal?: Signal; - props: Record; + [prop: string]: any; } const TextInput = ({ signal, ...props }: TextInputProps) => { const onInputSignal = useCallback((event: InputEvent) => { - signal.value = event.target.value; + if (signal) signal.value = (event.target as HTMLInputElement).value; }, [signal]); return ( diff --git a/src/components/index.ts b/src/components/index.ts index c9c3625..badd32e 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,12 +1,25 @@ -export { default as ArrowButton } from './ArrowButton.tsx'; -export { default as Button } from './Button.tsx'; -export { default as ButtonMenu } from './ButtonMenu.tsx'; +export { default as ArrowButton } from './ArrowButton.tsx'; +export { default as Button } from './Button.tsx'; +export { default as ButtonMenu } from './ButtonMenu.tsx'; export { default as ContainedList } from './ContainedList.tsx'; -export { default as Content } from './Content.tsx'; -export { default as Form } from './Form.tsx'; -export { default as FormLabel } from './FormLabel.tsx'; -export { default as Header } from './Header.tsx'; -export { default as Menu } from './Menu.tsx'; -export { default as MenuItem } from './MenuItem.tsx'; -export { default as TextInput } from './TextInput.tsx'; -export { default as Toolbar } from './Toolbar.tsx'; +export { default as Content } from './Content.tsx'; +export { default as Form } from './Form.tsx'; +export { default as FormLabel } from './FormLabel.tsx'; +export { default as Header } from './Header.tsx'; +export { default as Menu } from './Menu.tsx'; +export { default as MenuItem } from './MenuItem.tsx'; +export { default as TextInput } from './TextInput.tsx'; +export { default as Toolbar } from './Toolbar.tsx'; + +export type { ArrowButtonProps } from './ArrowButton.tsx'; +export type { ButtonMenuProps } from './ButtonMenu.tsx'; +export type { ButtonProps } from './Button.tsx'; +export type { ContainedListProps } from './ContainedList.tsx'; +export type { ContentProps } from './Content.tsx'; +export type { FormLabelProps } from './FormLabel.tsx'; +export type { FormProps } from './Form.tsx'; +export type { HeaderProps } from './Header.tsx'; +export type { MenuItemProps } from './MenuItem.tsx'; +export type { MenuProps } from './Menu.tsx'; +export type { TextInputProps } from './TextInput.tsx'; +export type { ToolbarProps } from './Toolbar.tsx'; diff --git a/src/components/nodes/Input.tsx b/src/components/nodes/Input.tsx index c32b32d..4bd7751 100644 --- a/src/components/nodes/Input.tsx +++ b/src/components/nodes/Input.tsx @@ -1,3 +1,4 @@ +import type { ComponentChildren } from 'preact'; import { useCallback } from 'preact/hooks'; import { InputSocket } from '../../dataflow.ts'; import { InSocket } from './Socket.tsx'; @@ -37,7 +38,7 @@ export const InputArray = ({ name, label }: Omit, 'value'>) => { ); }; -const InputNum = (parseFunc: (string) => number) => ({ name, label, value }: InputProps) => { +const InputNum = (parseFunc: (_: string) => number) => ({ name, label, value }: InputProps) => { const onInput = useCallback((event: InputEvent) => { value.value = parseFunc((event.target as HTMLInputElement).value); }, [value]); @@ -77,7 +78,7 @@ export interface InputSelectProps extends InputProps { } export const InputSelect = ({ name, label, value, options }: InputSelectProps) => { - const onChange = useCallback((event: InputEvent) => { + const onChange = useCallback((event: Event) => { value.value = (event.target as HTMLSelectElement).value; }, [value]); return ( diff --git a/src/components/nodes/Socket.tsx b/src/components/nodes/Socket.tsx index a4f38e1..6a958c5 100644 --- a/src/components/nodes/Socket.tsx +++ b/src/components/nodes/Socket.tsx @@ -1,5 +1,5 @@ import { useContext } from 'preact/hooks'; -import { NodeId, SocketHandlers } from '../../node.ts'; +import { NodeId, SocketHandlers, SocketHandler } from '../../node.ts'; import './Socket.css'; interface SocketProps { diff --git a/src/components/nodes/index.ts b/src/components/nodes/index.ts index d29f39f..b5ca5fc 100644 --- a/src/components/nodes/index.ts +++ b/src/components/nodes/index.ts @@ -1,3 +1,6 @@ -export { default as NodeShell, NodeShellProps } from './NodeShell.tsx'; -export { OutputNumber, OutputVector, OutputProps } from './Output.tsx'; -export { InputAny, InputArray, InputInteger, InputNumber, InputVector, InputSelect, InputProps, InputSelectProps } from './Input.tsx'; +export { InputAny, InputArray, InputInteger, InputNumber, InputVector, InputSelect } from './Input.tsx'; +export { default as NodeShell } from './NodeShell.tsx'; +export { OutputNumber, OutputVector } from './Output.tsx'; +export type { InputProps, InputSelectProps } from './Input.tsx'; +export type { NodeShellProps } from './NodeShell.tsx'; +export type { OutputProps } from './Output.tsx'; diff --git a/src/context.ts b/src/context.ts index 054d796..dd7bb51 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,4 +1,4 @@ import { createContext } from 'preact'; -import type { PocketBase } from 'pocketbase'; +import PocketBase from 'pocketbase'; -export const Pb = createContext(); +export const Pb = createContext(null); diff --git a/src/index.tsx b/src/index.tsx index ff833cc..6fdf07e 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,15 +1,14 @@ import { render } from 'preact'; -import { useEffect, useMemo } from 'preact/hooks'; +import { useMemo } from 'preact/hooks'; import { Router } from 'preact-router'; import PocketBase from 'pocketbase'; import { Pb } from './context.ts'; import { Home, SignUp, LogIn, ProjectsList } from './pages'; import NodeEditor from './NodeEditor.tsx'; -import { Header, Button } from './components'; import './index.css'; export const App = () => { - const pb = useMemo(() => new PocketBase(`/`)); + const pb = useMemo(() => new PocketBase(`/`), []); return ( diff --git a/src/node.ts b/src/node.ts index 1f4d5eb..76ed42b 100644 --- a/src/node.ts +++ b/src/node.ts @@ -1,4 +1,5 @@ import { createContext, FunctionComponent } from 'preact'; +import type { Signal } from '@preact/signals'; import { InputSocket } from './dataflow.ts'; export type SocketHandler = (nodeId: number, socket: string, event: MouseEvent) => void; diff --git a/src/nodes/Fourier.tsx b/src/nodes/Fourier.tsx index f33768f..e5a81f0 100644 --- a/src/nodes/Fourier.tsx +++ b/src/nodes/Fourier.tsx @@ -21,6 +21,6 @@ export const Fourier = ({ id, x, y, inputs }: NodeComponentProps) export const FourierNode: NodeInfo = { component: Fourier, - func: ({ data }) => ({ data: data ? fft(data) : null }), + func: ({ data }) => ({ data: data ? fft(data) as Float32Array : null }), inputs: { data: null }, }; diff --git a/src/nodes/Intersperse.tsx b/src/nodes/Intersperse.tsx index 0c7e271..3b0e3a6 100644 --- a/src/nodes/Intersperse.tsx +++ b/src/nodes/Intersperse.tsx @@ -3,12 +3,12 @@ import type { NodeComponentProps, NodeInfo } from '../node.ts'; import { intersperse } from '../wasm.ts'; export interface IntersperseInputs { - a: Float32Array, - b: Float32Array, + a: Float32Array | null, + b: Float32Array | null, } export interface IntersperseOutputs { - out: Float32Array, + out: Float32Array | null, } export const Intersperse = ({ id, x, y, inputs }: NodeComponentProps) => { @@ -23,6 +23,6 @@ export const Intersperse = ({ id, x, y, inputs }: NodeComponentProps = { component: Intersperse, - func: ({ a, b }) => ({ out: a && b ? intersperse(a, b) : null }), + func: ({ a, b }) => ({ out: a && b ? intersperse(a, b) as Float32Array : null }), inputs: { a: null, b: null }, }; \ No newline at end of file diff --git a/src/nodes/Linspace.tsx b/src/nodes/Linspace.tsx index b8239a1..7ae6db6 100644 --- a/src/nodes/Linspace.tsx +++ b/src/nodes/Linspace.tsx @@ -25,6 +25,6 @@ export const Linspace = ({ id, x, y, inputs }: NodeComponentProps = { component: Linspace, - func: ({ start, stop, n }) => ({ data: linspace(start, stop, Math.floor(n)) }), + func: ({ start, stop, n }) => ({ data: linspace(start, stop, Math.floor(n)) as Float32Array }), inputs: { start: 0, stop: 1, n: 10 }, }; \ No newline at end of file diff --git a/src/nodes/Plot.tsx b/src/nodes/Plot.tsx index d87fb72..0f303fa 100644 --- a/src/nodes/Plot.tsx +++ b/src/nodes/Plot.tsx @@ -32,11 +32,11 @@ export const Plot = ({ id, x, y, inputs }: NodeComponentProps) => { } } - let xticks = []; + let xticks: [string, number][] = []; for (let x = minX.value; x <= maxX.value; x += dx.value / xtickCount) { xticks.push([x.toFixed(1), (x - minX.value) / dx.value * width]); } - let yticks = []; + let yticks: [string, number][] = []; for (let y = minY.value; y <= maxY.value; y += dy.value / ytickCount) { yticks.push([y.toFixed(1), height - (y - minY.value) / dy.value * height]); } diff --git a/src/nodes/Unzip.tsx b/src/nodes/Unzip.tsx index 5bcb477..4afdf60 100644 --- a/src/nodes/Unzip.tsx +++ b/src/nodes/Unzip.tsx @@ -3,12 +3,12 @@ import type { NodeComponentProps, NodeInfo } from '../node.ts'; import { unzip } from '../wasm.ts'; export interface UnzipInputs { - data: Float32Array, + data: Float32Array | null, } export interface UnzipOutputs { - a: Float32Array, - b: Float32Array, + a: Float32Array | null, + b: Float32Array | null, } export const Unzip = ({ id, x, y, inputs }: NodeComponentProps) => { @@ -24,8 +24,8 @@ export const Unzip = ({ id, x, y, inputs }: NodeComponentProps) => export const UnzipNode: NodeInfo = { component: Unzip, func: ({ data }) => { - const out = data ? unzip(data) : null; - return { a: out?.slice(0, out.length/2), b: out?.slice(out.length/2) }; + const out = data ? unzip(data) as Float32Array : null; + return { a: out?.slice(0, out.length/2) || null, b: out?.slice(out.length/2) || null }; }, inputs: { data: null }, }; \ No newline at end of file diff --git a/src/nodes/Viewer.tsx b/src/nodes/Viewer.tsx index d92da3c..c21fd8f 100644 --- a/src/nodes/Viewer.tsx +++ b/src/nodes/Viewer.tsx @@ -10,7 +10,7 @@ export interface ViewerOutputs {} export const Viewer = ({ id, x, y, inputs }: NodeComponentProps) => { let data = inputs.value.value; if (ArrayBuffer.isView(data)) { - data = Array.from(data); + data = Array.from(data as Float32Array); } return ( diff --git a/src/nodes/index.ts b/src/nodes/index.ts index 09310bb..f7a153a 100644 --- a/src/nodes/index.ts +++ b/src/nodes/index.ts @@ -1,4 +1,4 @@ -import type { NodeInfo } from '../node.tsx'; +import type { NodeInfo } from '../node.ts'; import { CombineXYZNode } from './CombineXYZ.tsx'; import { SeparateXYZNode } from './SeparateXYZ.tsx'; import { ViewerNode } from './Viewer.tsx'; @@ -11,7 +11,7 @@ import { PlotNode } from './Plot.tsx'; // TODO: ComplexMath -const nodeRegistry: Record> = { +const nodeRegistry: Record> = { 'Combine XYZ': CombineXYZNode, 'Separate XYZ': SeparateXYZNode, 'Viewer': ViewerNode, diff --git a/src/pages/LogIn.tsx b/src/pages/LogIn.tsx index 296a499..5820cb6 100644 --- a/src/pages/LogIn.tsx +++ b/src/pages/LogIn.tsx @@ -5,7 +5,7 @@ import { Pb } from '../context.ts'; import { Header, Content, Form, TextInput, Button, ArrowButton, FormLabel } from '../components'; const LogIn = () => { - const pb = useContext(Pb); + const pb = useContext(Pb)!; const email = useSignal(''); const password = useSignal(''); @@ -14,7 +14,7 @@ const LogIn = () => { event.preventDefault(); await pb.collection('users').authWithPassword(email.value, password.value); if (pb.authStore.isValid) { - route('/' + pb.authStore.model.username); + route('/' + pb.authStore.model!.username); } }, []); diff --git a/src/pages/ProjectsList.tsx b/src/pages/ProjectsList.tsx index a7e3bed..13dd5d6 100644 --- a/src/pages/ProjectsList.tsx +++ b/src/pages/ProjectsList.tsx @@ -1,26 +1,30 @@ import { useContext, useEffect, useCallback } from 'preact/hooks'; import { useSignal } from '@preact/signals'; import { route } from 'preact-router'; +import type { ListResult } from 'pocketbase'; +import type { Project } from '../types.ts'; import { Pb } from '../context.ts'; import { logOut } from '../util.ts'; import { Header, Content, ContainedList, Form, FormLabel, TextInput, Button } from '../components'; -const ProjectsList = ({ user }) => { - const pb = useContext(Pb); - const projects = useSignal(null); +export interface ProjectsListProps { + user: string; +} + +const ProjectsList = ({ user }: ProjectsListProps) => { + const pb = useContext(Pb)!; + const projects = useSignal | null>(null); const projectName = useSignal(''); - useEffect(() => { - pb.collection('projects') - .getList(1, 20, { sort: '-mtime' }) - .then(p => projects.value = p); + useEffect(async () => { + projects.value = await pb.collection('projects').getList(1, 20, { sort: '-mtime' }); }, []); - const onCreateProject = useCallback(async (event: FormEvent) => { + const onCreateProject = useCallback(async (event: SubmitEvent) => { event.preventDefault(); const project = await pb.collection('projects').create({ name: projectName.value, - owner: pb.authStore.model.id, + owner: pb.authStore.model!.id, }); route(`/${user}/${project.name}`); }, [user]); diff --git a/src/pages/SignUp.tsx b/src/pages/SignUp.tsx index 22e1512..e1cee3c 100644 --- a/src/pages/SignUp.tsx +++ b/src/pages/SignUp.tsx @@ -5,7 +5,7 @@ import { Pb } from '../context.ts'; import { Header, Content, Form, FormLabel, TextInput, Button, ArrowButton } from '../components'; const SignUp = () => { - const pb = useContext(Pb); + const pb = useContext(Pb)!; const username = useSignal(''); const email = useSignal(''); @@ -22,7 +22,7 @@ const SignUp = () => { passwordConfirm: confirm.value, }); if (pb.authStore.isValid) { - route('/' + pb.authStore.model.username); + route('/' + pb.authStore.model!.username); } }, []); diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..29d14a3 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,18 @@ +export interface Project { + id: string; + owner: string; + name: string; +} + +export interface Node { + id: string; + x: number; + y: number; + name: string; +} + +export interface Link { + id: string; + from: string; + to: string; +} diff --git a/src/wasm.ts b/src/wasm.ts index cf7b552..4a8d3c8 100644 --- a/src/wasm.ts +++ b/src/wasm.ts @@ -1,5 +1,5 @@ import { instantiate } from '../build/out.js'; -import url from '../build/out.wasm'; +import module from '../build/out.wasm'; export const { memory, mathS, mathV, mathSS, mathSV, mathVS, mathVV, @@ -7,4 +7,4 @@ export const { intersperse, unzip, fft, -} = await instantiate(await WebAssembly.compileStreaming(fetch(url)), {}); \ No newline at end of file +} = await instantiate(await WebAssembly.compileStreaming(fetch(module)), { env: {} }); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 2a94c31..3d1bebf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,8 +15,7 @@ "allowJs": false, "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedLocals": true }, "include": ["src"] } -- cgit v1.2.3