Socket
Socket
Sign inDemoInstall

forgo

Package Overview
Dependencies
Maintainers
1
Versions
140
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

forgo - npm Package Compare versions

Comparing version 0.0.8 to 0.0.9

2

dist/index.d.ts

@@ -43,2 +43,2 @@ export declare type ForgoRef<T> = {

export declare function mount(forgoNode: ForgoNode, parentElement: HTMLElement | null): void;
export declare function rerender(element: ForgoElementArg | undefined): void;
export declare function rerender(element: ForgoElementArg | undefined, props?: undefined, fullRerender?: boolean): void;

@@ -30,10 +30,10 @@ "use strict";

*/
function render(forgoNode, node, pendingAttachStates) {
function render(forgoNode, node, pendingAttachStates, fullRerender) {
// Just a string
if (!isForgoElement(forgoNode)) {
return renderString(stringOfPrimitiveNode(forgoNode), node, pendingAttachStates);
return renderString(stringOfPrimitiveNode(forgoNode), node, pendingAttachStates, fullRerender);
}
// HTML Element
else if (typeof forgoNode.type === "string") {
return renderDOMElement(forgoNode, node, pendingAttachStates);
return renderDOMElement(forgoNode, node, pendingAttachStates, fullRerender);
}

@@ -43,3 +43,3 @@ // Custom Component.

else {
return renderCustomComponent(forgoNode, node, pendingAttachStates);
return renderCustomComponent(forgoNode, node, pendingAttachStates, fullRerender);
}

@@ -59,3 +59,3 @@ }

*/
function renderString(text, node, pendingAttachStates) {
function renderString(text, node, pendingAttachStates, fullRerender) {
var _a;

@@ -88,3 +88,3 @@ // Text nodes will always be recreated

*/
function renderDOMElement(forgoElement, node, pendingAttachStates) {
function renderDOMElement(forgoElement, node, pendingAttachStates, fullRerender) {
var _a;

@@ -111,3 +111,3 @@ if (node) {

attachProps(forgoElement, nodeToBindTo, pendingAttachStates);
renderChildNodes(forgoElement, nodeToBindTo);
renderChildNodes(forgoElement, nodeToBindTo, fullRerender);
return { node: nodeToBindTo };

@@ -122,3 +122,3 @@ }

attachProps(forgoElement, newElement, pendingAttachStates);
renderChildNodes(forgoElement, newElement);
renderChildNodes(forgoElement, newElement, fullRerender);
return { node: newElement };

@@ -131,3 +131,3 @@ }

*/
function renderCustomComponent(forgoElement, node, pendingAttachStates) {
function renderCustomComponent(forgoElement, node, pendingAttachStates, fullRerender) {
if (node) {

@@ -156,14 +156,22 @@ const state = getExistingForgoState(node);

// Pass it on for rendering...
return render(newForgoElement, node, statesToAttach);
return render(newForgoElement, node, statesToAttach, fullRerender);
}
// We have compatible state, and this is a rerender
else {
const args = { element: { componentIndex: pendingAttachStates.length } };
// Since we have compatible state already stored,
// we'll push the savedComponentState into pending states for later attachment.
const statesToAttach = pendingAttachStates.concat(Object.assign(Object.assign({}, savedComponentState), { props: forgoElement.props }));
// Get a new element by calling render on existing component.
const newForgoElement = savedComponentState.component.render(forgoElement.props, args);
// Pass it on for rendering...
return render(newForgoElement, node, statesToAttach);
if (fullRerender ||
havePropsChanged(savedComponentState.props, forgoElement.props)) {
const args = {
element: { componentIndex: pendingAttachStates.length },
};
// Since we have compatible state already stored,
// we'll push the savedComponentState into pending states for later attachment.
const statesToAttach = pendingAttachStates.concat(Object.assign(Object.assign({}, savedComponentState), { props: forgoElement.props }));
// Get a new element by calling render on existing component.
const newForgoElement = savedComponentState.component.render(forgoElement.props, args);
// Pass it on for rendering...
return render(newForgoElement, node, statesToAttach, fullRerender);
}
else {
return { node };
}
}

@@ -188,3 +196,3 @@ }

// We have no node to render to yet. So pass undefined for the node.
return render(newForgoElement, undefined, statesToAttach);
return render(newForgoElement, undefined, statesToAttach, fullRerender);
}

@@ -205,3 +213,3 @@ }

*/
function renderChildNodes(forgoElement, parentElement) {
function renderChildNodes(forgoElement, parentElement, fullRerender) {
const { children: forgoChildrenObj } = forgoElement.props;

@@ -225,7 +233,7 @@ const childNodes = parentElement.childNodes;

childNodes[forgoChildIndex].nodeType === TEXT_NODE_TYPE) {
render(stringOfPrimitiveNode(forgoChild), childNodes[forgoChildIndex], []);
render(stringOfPrimitiveNode(forgoChild), childNodes[forgoChildIndex], [], fullRerender);
}
// But otherwise, don't pass a replacement node. Just insert instead.
else {
const { node } = render(stringOfPrimitiveNode(forgoChild), undefined, []);
const { node } = render(stringOfPrimitiveNode(forgoChild), undefined, [], fullRerender);
parentElement.insertBefore(node, childNodes[forgoChildIndex]);

@@ -242,6 +250,6 @@ }

}
render(forgoChild, childNodes[forgoChildIndex], []);
render(forgoChild, childNodes[forgoChildIndex], [], fullRerender);
}
else {
const { node } = render(forgoChild, undefined, []);
const { node } = render(forgoChild, undefined, [], fullRerender);
if (childNodes.length > forgoChildIndex) {

@@ -401,2 +409,12 @@ parentElement.insertBefore(node, childNodes[forgoChildIndex]);

/*
Compare old props and new props.
We don't rerender if props remain the same.
*/
function havePropsChanged(oldProps, newProps) {
const oldKeys = Object.keys(oldProps);
const newKeys = Object.keys(newProps);
return (oldKeys.length !== newKeys.length ||
oldKeys.some((key) => oldProps[key] !== newProps[key]));
}
/*
Mount will render the DOM as a child of the specified container element.

@@ -406,3 +424,3 @@ */

if (parentElement) {
const { node } = render(forgoNode, undefined, []);
const { node } = render(forgoNode, undefined, [], true);
parentElement.appendChild(node);

@@ -424,3 +442,3 @@ }

*/
function rerender(element) {
function rerender(element, props = undefined, fullRerender = true) {
if (element && element.node) {

@@ -430,5 +448,8 @@ const state = getForgoState(element.node);

const component = state.components[element.componentIndex];
const forgoNode = component.component.render(component.props, component.args);
const statesToAttach = state.components.slice(0, element.componentIndex + 1);
render(forgoNode, element.node, statesToAttach);
const effectiveProps = typeof props !== "undefined" ? props : component.props;
const forgoNode = component.component.render(effectiveProps, component.args);
const statesToAttach = state.components
.slice(0, element.componentIndex)
.concat(Object.assign(Object.assign({}, component), { props: effectiveProps }));
render(forgoNode, element.node, statesToAttach, fullRerender);
}

@@ -435,0 +456,0 @@ else {

{
"name": "forgo",
"version": "0.0.8",
"version": "0.0.9",
"main": "./dist",

@@ -5,0 +5,0 @@ "devDependencies": {

@@ -5,3 +5,3 @@ # forgo

Unlike React, apps are plain JS with very little framework specific code. Everything you already know about DOM APIs and JavaScript will easily carry over.
Unlike React, there are very few framework specific patterns and lingo to learn. Everything you already know about DOM APIs and JavaScript will easily carry over.

@@ -11,7 +11,9 @@ - Use HTML DOM APIs for accessing elements

- Use closures for maintaining component state
- Use any singleton pattern for managing app-wide state
- There's no vDOM or DOM diffing. Renders are manually triggered
- There's no vDOM or DOM diffing
- Renders are manually triggered
Forgo is basically just one small JS file (actually TypeScript). It's somewhat decently documented, but I could use some help here. A stated goal of the project is to always remain within that single file.
## We'll be tiny. Always.
All of Forgo is in one small JS file (actually it's TypeScript). It is a goal of the project is to remain within that single file.
## Installation

@@ -87,7 +89,7 @@

You're expected to read form input control values with regular DOM APIs.
You can read form input element values with regular DOM APIs.
There's a small hurdle though - how do you we get a reference to these nodes? Well, that's where the ref attribute comes in. An object bound to the ref attribute in the markup will have its value property set to the DOM element.
There's a small hurdle though - how do we get a reference to the actual DOM element? That's where the ref attribute comes in. An object referenced by the ref attribute in an element's markup will have its value property set to the actual DOM element.
See the usage below:
Better explained with an example:

@@ -116,4 +118,54 @@ ```jsx

## Multiple Components, passing props etc.
## Unmount
When a component is unmounted, Forgo will invoke the unmount() function if defined for a component. This is of course, totally optional.
```jsx
function Greeter(props) {
return {
render(props, args) {
return <div>Hello {props.firstName}</div>;
},
unmount() {
console.log("Got unloaded.");
},
};
}
```
## Additional Rerender options
The most straight forward way to do rerender is by invoking it with `args.element` as follows.
```tsx
function TodoList(props) {
let todos = [];
return {
render(props, args) {
function addTodos(text) {
todos.push(text);
rerender(args.element);
}
return <div>markup goes here...</div>;
},
};
}
```
But there are a couple of handy options to rerender, 'newProps' and 'forceRerender'.
newProps let you pass a new set of props while rerendering. If you'd like previous props to be used, pass undefined here.
forceRerender defaults to true, but when set to false skips child component rendering if props haven't changed.
```js
const newProps = { name: "Kai" };
const forceRerender = false;
rerender(args.element, newProps, forceRerender);
```
## Recap with a complete example
Finally, let's do a recap with a more complete example. Let's make a Todo List app in TypeScript.

@@ -137,3 +189,3 @@

render(props: TodoListProps, args: ForgoRenderArgs) {
function onTodoAdd(text: string) {
function addTodos(text: string) {
todos.push(text);

@@ -151,3 +203,3 @@ rerender(args.element);

</ul>
<AddTodo onAdd={onTodoAdd} />
<AddTodo onAdd={addTodos} />
</div>

@@ -160,3 +212,3 @@ );

Here's the TodoList item, which simply displays a Todo.
Here's the TodoListItem component, which simply displays a Todo.

@@ -187,3 +239,3 @@ ```tsx

function onClick() {
function saveTodo() {
const inputEl = input.value;

@@ -197,2 +249,9 @@ if (inputEl) {

// Add the todo when Enter is pressed
function onKeyPress(e: KeyboardEvent) {
if (e.key === "Enter") {
saveTodo();
}
}
return {

@@ -202,4 +261,4 @@ render() {

<div>
<input type="text" ref={input} />
<button onclick={onClick}>Add me!</button>
<input onkeypress={onKeyPress} type="text" ref={input} />
<button onclick={saveTodo}>Add me!</button>
</div>

@@ -251,1 +310,5 @@ );

```
## Getting Help
You can reach out to me via twitter or email. If you find issues, please file a bug on [Github](https://github.com/forgojs/forgo/issues).

@@ -145,3 +145,4 @@ /*

node: ChildNode | undefined,
pendingAttachStates: NodeAttachedComponentState<any>[]
pendingAttachStates: NodeAttachedComponentState<any>[],
fullRerender: boolean
): { node: ChildNode } {

@@ -153,3 +154,4 @@ // Just a string

node,
pendingAttachStates
pendingAttachStates,
fullRerender
);

@@ -162,3 +164,4 @@ }

node,
pendingAttachStates
pendingAttachStates,
fullRerender
);

@@ -172,3 +175,4 @@ }

node,
pendingAttachStates
pendingAttachStates,
fullRerender
);

@@ -193,3 +197,4 @@ }

node: ChildNode | undefined,
pendingAttachStates: NodeAttachedComponentState<any>[]
pendingAttachStates: NodeAttachedComponentState<any>[],
fullRerender: boolean
): { node: ChildNode } {

@@ -227,3 +232,4 @@ // Text nodes will always be recreated

node: ChildNode | undefined,
pendingAttachStates: NodeAttachedComponentState<any>[]
pendingAttachStates: NodeAttachedComponentState<any>[],
fullRerender: boolean
): { node: ChildNode } {

@@ -254,3 +260,3 @@ if (node) {

renderChildNodes(forgoElement, nodeToBindTo as HTMLElement);
renderChildNodes(forgoElement, nodeToBindTo as HTMLElement, fullRerender);
return { node: nodeToBindTo };

@@ -264,3 +270,3 @@ } else {

attachProps(forgoElement, newElement, pendingAttachStates);
renderChildNodes(forgoElement, newElement);
renderChildNodes(forgoElement, newElement, fullRerender);
return { node: newElement };

@@ -277,3 +283,4 @@ }

node: ChildNode | undefined,
pendingAttachStates: NodeAttachedComponentState<any>[]
pendingAttachStates: NodeAttachedComponentState<any>[],
fullRerender: boolean
): { node: ChildNode } {

@@ -309,23 +316,32 @@ if (node) {

// Pass it on for rendering...
return render(newForgoElement, node, statesToAttach);
return render(newForgoElement, node, statesToAttach, fullRerender);
}
// We have compatible state, and this is a rerender
else {
const args = { element: { componentIndex: pendingAttachStates.length } };
if (
fullRerender ||
havePropsChanged(savedComponentState.props, forgoElement.props)
) {
const args = {
element: { componentIndex: pendingAttachStates.length },
};
// Since we have compatible state already stored,
// we'll push the savedComponentState into pending states for later attachment.
const statesToAttach = pendingAttachStates.concat({
...savedComponentState,
props: forgoElement.props,
});
// Since we have compatible state already stored,
// we'll push the savedComponentState into pending states for later attachment.
const statesToAttach = pendingAttachStates.concat({
...savedComponentState,
props: forgoElement.props,
});
// Get a new element by calling render on existing component.
const newForgoElement = savedComponentState.component.render(
forgoElement.props,
args
);
// Get a new element by calling render on existing component.
const newForgoElement = savedComponentState.component.render(
forgoElement.props,
args
);
// Pass it on for rendering...
return render(newForgoElement, node, statesToAttach);
// Pass it on for rendering...
return render(newForgoElement, node, statesToAttach, fullRerender);
} else {
return { node };
}
}

@@ -353,3 +369,3 @@ }

// We have no node to render to yet. So pass undefined for the node.
return render(newForgoElement, undefined, statesToAttach);
return render(newForgoElement, undefined, statesToAttach, fullRerender);
}

@@ -373,3 +389,4 @@ }

forgoElement: ForgoElement<string | ForgoComponentCtor<TProps>, TProps>,
parentElement: HTMLElement
parentElement: HTMLElement,
fullRerender: boolean
) {

@@ -407,3 +424,4 @@ const { children: forgoChildrenObj } = forgoElement.props;

childNodes[forgoChildIndex],
[]
[],
fullRerender
);

@@ -416,3 +434,4 @@ }

undefined,
[]
[],
fullRerender
);

@@ -439,5 +458,5 @@ parentElement.insertBefore(node, childNodes[forgoChildIndex]);

}
render(forgoChild, childNodes[forgoChildIndex], []);
render(forgoChild, childNodes[forgoChildIndex], [], fullRerender);
} else {
const { node } = render(forgoChild, undefined, []);
const { node } = render(forgoChild, undefined, [], fullRerender);
if (childNodes.length > forgoChildIndex) {

@@ -625,2 +644,15 @@ parentElement.insertBefore(node, childNodes[forgoChildIndex]);

/*
Compare old props and new props.
We don't rerender if props remain the same.
*/
function havePropsChanged(oldProps: any, newProps: any) {
const oldKeys = Object.keys(oldProps);
const newKeys = Object.keys(newProps);
return (
oldKeys.length !== newKeys.length ||
oldKeys.some((key) => oldProps[key] !== newProps[key])
);
}
/*
Mount will render the DOM as a child of the specified container element.

@@ -630,3 +662,3 @@ */

if (parentElement) {
const { node } = render(forgoNode, undefined, []);
const { node } = render(forgoNode, undefined, [], true);
parentElement.appendChild(node);

@@ -647,3 +679,7 @@ } else {

*/
export function rerender(element: ForgoElementArg | undefined) {
export function rerender(
element: ForgoElementArg | undefined,
props = undefined,
fullRerender = true
) {
if (element && element.node) {

@@ -653,11 +689,19 @@ const state = getForgoState(element.node);

const component = state.components[element.componentIndex];
const effectiveProps =
typeof props !== "undefined" ? props : component.props;
const forgoNode = component.component.render(
component.props,
effectiveProps,
component.args
);
const statesToAttach = state.components.slice(
0,
element.componentIndex + 1
);
render(forgoNode, element.node, statesToAttach);
const statesToAttach = state.components
.slice(0, element.componentIndex)
.concat({
...component,
props: effectiveProps,
});
render(forgoNode, element.node, statesToAttach, fullRerender);
} else {

@@ -664,0 +708,0 @@ throw new Error(

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc