Skip to content

Commit

Permalink
FEAT/typescript supports added
Browse files Browse the repository at this point in the history
  • Loading branch information
AugustinSorel committed Dec 31, 2023
1 parent 4add426 commit 511b4d7
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 3,735 deletions.
33 changes: 25 additions & 8 deletions packages/runtime/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
import { destroyDom } from "./destroy-dom";
import { Dispatcher } from "./dispatcher";
import { VNodes } from "./h";
import { VNodes, h, hString } from "./h";
import { mountDOM } from "./mount-dom";

type Props = {
state: any;
view: (state: any, emit: any) => VNodes;
reducers: Record<string, Function>;
export type Reducer<TState> = Record<
string,
<TPayload = unknown>(state: TState, payload?: TPayload) => TState
>;

export type View<TState> = (
state: TState,
emit: <TPayload = unknown>(name: string, payload?: TPayload) => void,
) => VNodes;

type Props<TState, TReducers extends Reducer<TState>> = {
state: TState;
view: View<TState>;
reducers: TReducers;
};

export function createApp({ state, view, reducers }: Props) {
export const createApp = <TState, TReducers extends Reducer<TState>>({
state,
view,
reducers,
}: Props<TState, TReducers>) => {
let parentEl: HTMLElement | null = null;
let vdom: VNodes | null = null;

const dispatcher = new Dispatcher();

const emit = (eventName: string, payload: any) => {
const emit = <TPayload extends unknown>(
eventName: string,
payload?: TPayload,
) => {
dispatcher.dispatch(eventName, payload);
};

Expand Down Expand Up @@ -59,4 +76,4 @@ export function createApp({ state, view, reducers }: Props) {
}
},
};
}
};
59 changes: 59 additions & 0 deletions packages/runtime/src/attributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
export function setAttributes(el: HTMLElement, attrs: any) {
const { class: className, style, ...otherAttrs } = attrs;

delete otherAttrs.key;

if (className) {
setClass(el, className);
}

if (style) {
Object.entries(style).forEach(([prop, value]) => {
setStyle(el, prop, value);
});
}

for (const [name, value] of Object.entries(otherAttrs)) {
setAttribute(el, name, value);
}
}

export function setAttribute(el: HTMLElement, name: string, value: any) {
if (!value) {
removeAttribute(el, name);
} else {
el.setAttribute(name, value);
}
}

export function removeAttribute(el: HTMLElement, name: string) {
try {
//@ts-expect-error
el[name] = null;
} catch {
console.warn(`Failed to set "${name}" to null on ${el.tagName}`);
}

el.removeAttribute(name);
}

export function setStyle(el: HTMLElement, name: any, value: any) {
el.style[name] = value;
}

export function removeStyle(el: HTMLElement, name: string) {
//@ts-expect-error
el.style[name] = null;
}

function setClass(el: HTMLElement, className: string | string[]) {
el.className = "";

if (typeof className === "string") {
el.className = className;
}

if (Array.isArray(className)) {
el.classList.add(...className);
}
}
1 change: 0 additions & 1 deletion packages/runtime/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from "./h";
export * from "./mount-dom";
export * from "./app";
65 changes: 10 additions & 55 deletions packages/runtime/src/mount-dom.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { setAttributes } from "./attributes";
import { addEventListeners } from "./events";
import type { H, HFragment, HString, VNodes } from "./h";
import { HString, VNodes, H, HFragment } from "./h";

export const mountDOM = (vdom: VNodes, parentEl: HTMLElement) => {
if (vdom.type === "text") {
Expand Down Expand Up @@ -37,65 +38,19 @@ const createFragmentNode = (vdom: HFragment, parentEl: HTMLElement) => {
};

const createElementNode = (vdom: H, parentEl: HTMLElement) => {
const element = document.createElement(vdom.tagName);
const { tagName, props, children } = vdom;
const { on: events, ...attrs } = props;

const { class: className, style, on, ...otherProps } = vdom.props;
vdom.listeners = addEventListeners(on ?? {}, parentEl);
vdom.domPointer = element;
const element = document.createElement(tagName);

if (className) {
setClass(element, className);
}
vdom.listeners = addEventListeners(events ?? {}, element);
setAttributes(element, attrs);

if (style) {
for (const [prop, value] of Object.entries(style)) {
setStyle(element, prop, value);
}
}
vdom.domPointer = element;

for (const [name, value] of Object.entries(otherProps)) {
setAttribute(element, name, value);
}

for (const children of vdom.children) {
mountDOM(children, element);
for (const child of children) {
mountDOM(child, element);
}

parentEl.append(element);
};

const setClass = (element: HTMLElement, className: string | string[]) => {
element.className = "";

if (typeof className === "string") {
element.className = className;
}

if (Array.isArray(className)) {
element.classList.add(...className);
}
};

const setStyle = (element: HTMLElement, prop: string, value: any) => {
//@ts-ignore
element.style[prop] = value;
};

const removeStyle = (element: HTMLElement, name: string) => {
//@ts-ignore
element.style[name] = null;
};

const setAttribute = (element: HTMLElement, name: string, value: any) => {
if (!value) {
removeAttribute(element, name);
} else {
element.setAttribute(name, value);
}
};

const removeAttribute = (element: HTMLElement, name: string) => {
//@ts-ignore
element[name] = null;
element.removeAttribute(name);
};
Loading

0 comments on commit 511b4d7

Please sign in to comment.