Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize Size #40

Open
wants to merge 5 commits into
base: milestone-1.4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions baact/BaactComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {BaseHTMLElement} from "./BaseHTMLElement";
import {baact, realize, render} from "./baact";

export abstract class BaactComponent<T extends Record<string, any>> extends BaseHTMLElement<T> {
private _shouldRerender: boolean = false
private _children: Node[] = [];
constructor() {
super();
this.attachShadow({ mode: 'open' });
}

public abstract render(): JSX.Element;

private _render() {
//console.log("Rendering", this.tagName)
if (!this.shadowRoot) return
for (const child of this._children) {
super.appendChild(child)
}
while (this.shadowRoot.lastElementChild) this.shadowRoot.removeChild(this.shadowRoot.lastElementChild)
this.shadowRoot.textContent = ''
if (this.styles !== "") this.shadowRoot?.appendChild(realize(<style>{this.styles}</style>))
this.shadowRoot?.append(render(this.render(), this)); // TODO: Fix when everything is transfered to Baact
}

static get observedAttributes(): (keyof any)[] { return [] }

public shouldRerender() {
this._shouldRerender = true
requestAnimationFrame(() => {
if (this._shouldRerender) {
this._shouldRerender = false
this._render()
}
})
}

public setAttribute<S extends keyof T>(qualifiedName: S, value: T[S]) {
super.setAttribute(qualifiedName, value)
const ctor = this["constructor"] as typeof BaactComponent
if (ctor.observedAttributes.includes(qualifiedName)) {
this.shouldRerender()
}
}

public appendChild<T extends Node>(node: T): T {
this._children.push(node)
this.shouldRerender()
return node
}

public removeChild<T extends Node>(node: T): T {
const index = this._children.indexOf(node)
if (index !== -1) this._children.splice(index, 1)
this.shouldRerender()
return node
}

public initialize() {
this.shouldRerender();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { baact } from '../../baact/baact'
import { baact } from './baact'

export abstract class BaseHTMLElement<T extends Record<string, any>> extends HTMLElement {
initialized: boolean = false
Expand All @@ -23,7 +23,6 @@ export abstract class BaseHTMLElement<T extends Record<string, any>> extends HTM

connectedCallback(): void {
if (!this.initialized) {
if (this.styles !== "") this.shadowRoot?.appendChild(<style>{this.styles}</style>)
this.initialize()
this.initialized = true
}
Expand Down
10 changes: 10 additions & 0 deletions baact/Fragment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {BaseHTMLElement} from "./BaseHTMLElement";

export class Fragment extends BaseHTMLElement<any> {
tagName: string = 'fragment';
constructor() {
super();
}
initialize(): void {
}
}
192 changes: 182 additions & 10 deletions baact/baact.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Baact } from './index'
import {BaactComponent} from "./BaactComponent";

const svgTags = [ 'animate', 'animateMotion', 'animateTransform', 'circle', 'clipPath', 'defs', 'desc', 'discard', 'ellipse', 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence', 'filter', 'foreignObject', 'g', 'hatch', 'hatchpath', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'set', 'stop', 'svg', 'switch', 'symbol', 'text', 'textPath', 'title', 'tspan', 'use', 'view' ]

Expand All @@ -7,12 +8,13 @@ function DOMparseChildren(children: Baact.BaactNode[]): any {
if (typeof child === 'string') {
return document.createTextNode(child);
}

return child;
});
}

function DOMparseNode<P>(element: string, properties: Partial<P>, children: Baact.BaactNode[], isHTML: boolean): any {
if (element === undefined) {
return DOMparseChildren(children);
}
const el = svgTags.includes(element) ? document.createElementNS('http://www.w3.org/2000/svg', element) : document.createElement(element);

Object.entries(properties).forEach(([key, value]) => {
Expand All @@ -30,8 +32,12 @@ function DOMparseNode<P>(element: string, properties: Partial<P>, children: Baac
}
if (key === 'style') {
Object.entries(value as Baact.CSSProperties).forEach(([key, value]) => {
// @ts-ignore
el.style[key] = value
if (key.startsWith('--')) {
el.style.setProperty(key, value)
} else {
// @ts-ignore
el.style[key] = value
}
})
return
}
Expand Down Expand Up @@ -65,18 +71,184 @@ function DOMparseNode<P>(element: string, properties: Partial<P>, children: Baac
(el as HTMLTemplateElement).content.appendChild(child)
return
}
el.appendChild(child);

if (!child) return

let children: Node[] = []
if (child instanceof HTMLCollection) {
children = Array.from(child)
} else if(Array.isArray(child)) {
children = child
} else {
children = [child]
}
children.forEach((c) => {
if (!c) return
el.appendChild(c)
})
});

return el;
}

export const baact = <P extends Baact.DOMAttributes<T, R>, T extends Element, R extends any>(element: string, properties: P | null, ...children: Baact.BaactNode[]): any => {
if (typeof element === 'function') {
//@ts-ignore
return DOMparseNode<P>(element.tagName, properties ?? {}, children, false)
export const baact2 = <P extends Baact.DOMAttributes<T, R>, T extends Element, R extends any>(element: string, properties: P | null, ...children: Baact.BaactNode[]): any => {
const isHTML = typeof element !== 'function'
// @ts-ignore
const name = isHTML ? element : element.tagName;
const result = DOMparseNode<P>(name, properties ?? {}, children, isHTML);
return result;
}

export const realize = (vdom: VDOM): Node => {
const el = svgTags.includes(vdom.name) ? document.createElementNS('http://www.w3.org/2000/svg', vdom.name) : document.createElement(vdom.name);
if (!vdom.isHTML) {
// @ts-ignore
vdom.component = el
}
return DOMparseNode<P>(element, properties ?? {}, children, true);
el.vdom = vdom

Object.entries(vdom.properties).forEach(([key, value]) => {
el.setAttribute("cryptoId", crypto.randomUUID())
if (key === 'ref') {
(value as Baact.BaactRef<any>).value = el
return
}
if (key === 'innerHTML') {
el.innerHTML = value as string
return
}
if (key === 'class') { // TODO: className
el.classList.value = value as string;
return
}
if (key === 'style') {
Object.entries(value as Baact.CSSProperties).forEach(([key, value]) => {
if (key.startsWith('--')) {
el.style.setProperty(key, value)
} else {
// @ts-ignore
el.style[key] = value
}
})
return
}
if (key.startsWith('on') && vdom.isHTML) {
// @ts-ignore
el.addEventListener(key.substr(2).toLowerCase(), value)
return
}
if (typeof value === 'boolean' && vdom.isHTML) {
if(value) {
el.setAttribute(key, 'true')
// @ts-ignore
el[key] = 'true'
}
return
}

value = vdom.isHTML ? String(value) : value

// @ts-ignore
el.setAttribute(key, value)
try {
// @ts-ignore
el[key] = value
} catch (e) {}

});

vdom.children.flatMap((child) => {
if (child.name === 'fragment') {
return child.children
}
return child
}).forEach((child) => {
if (child instanceof Node) {
el.appendChild(child)
return
}
if (child instanceof HTMLCollection) {
Array.from(child).forEach((c) => {
el.appendChild(c)
})

return
}
if (vdom.name === 'template') {
(el as HTMLTemplateElement).content.appendChild(child)
return
}

if (!child) return
if (child.name === 'text') {
el.appendChild(document.createTextNode(child.properties.value))
return
}

el.appendChild(realize(child))
});

return el;
}

export const render = (element: JSX.Element, parent?: any): Node => {
if (parent) {
if (!parent.vdom.finalChildren) {
parent.vdom.finalChildren = []
}
parent.vdom.finalChildren.push(element)
} else {
console.log(element)
}
//console.log(element)
// @ts-ignore
const realized = realize(element)
/*if (element.children) {
console.log(element)
}*/

//console.log(realized)
return realized
}

type VDOM = {
name: string
properties: any
children: VDOM[]
isHTML: boolean
key: string | number | undefined
component?: BaactComponent<any>
}

export const baact = <P extends Baact.DOMAttributes<T, R>, T extends Element, R extends any>(element: string, properties: P | null, ...children: VDOM[]): VDOM => {
const isHTML = typeof element !== 'function'
// @ts-ignore
const name = isHTML ? element : element.tagName;

const result = {
name: name ?? 'fragment',
properties: properties ?? {},
children: children.map((child, i) => {
if (typeof child === 'string') {
return {
name: 'text',
properties: { value: child },
children: [],
isHTML: false,
key: `k-text-${i}`
}
}
if (child && !child.key) {
child.key = `k-${name}-${i}`
}
return child
}),
isHTML: isHTML,
key: properties?.key
};

return result;
}


export const createRef = <T>(v?: T): Baact.BaactRef<T> => ({ value: v } as unknown as Baact.BaactRef<T>)
2 changes: 2 additions & 0 deletions baact/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ declare namespace Baact {
}

interface DOMAttributes<T, R> {
key?: string | number | undefined;
ref?: BaactRef<R> | undefined;
children?: BaactNode | undefined;
inert?: boolean | undefined;
innerHTML?: string | undefined;
onCopy?: EventHandler | undefined;
onCopyCapture?: EventHandler | undefined;
Expand Down
3 changes: 3 additions & 0 deletions baact/util/classes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const clx = (classes: (string | false | null | undefined)[]): string => {
return classes.filter(Boolean).join(' ');
}
14 changes: 14 additions & 0 deletions baact/util/register.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {BaactComponent} from "../BaactComponent";
import {BaseHTMLElement} from "../BaseHTMLElement";

interface CustomBaactElementConstructor {
new (...params: any[]): BaseHTMLElement<any>;
}

export const makeRegisterFunction = (tagName: string, ctor: CustomBaactElementConstructor) => {
return () => {
if (!customElements.get(tagName)) {
customElements.define(tagName, ctor)
}
}
}
5 changes: 4 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ gulp.task('transpile-ts', function () {
.pipe(replace('@INFORMATION@', String(process.env.SETTINGS_INFORMATION) !== "" ? String(process.env.SETTINGS_INFORMATION) : "false"))
.pipe(sourcemaps.init())
.pipe(tsProject())
.pipe(sourcemaps.write({
.pipe(sourcemaps.write(".",{
includeContent: false,
sourceRoot: function (file) {
return path.relative(path.dirname(file.path), file.base);
},
sourceMappingURL: function (file) {
return `${file.relative}.map`;
}
}))
.pipe(replace('@VERSION@', String(process.env.npm_package_version)))
Expand Down
Loading