Socket
Socket
Sign inDemoInstall

forgo-state

Package Overview
Dependencies
Maintainers
2
Versions
96
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

forgo-state - npm Package Compare versions

Comparing version 1.2.0 to 2.0.0-alpha.0

6

dist/index.d.ts

@@ -1,4 +0,4 @@

import { ForgoComponent, ForgoElementProps } from "forgo";
import { Component } from "forgo";
export declare function defineState<TState extends Record<string, any>>(state: TState): TState;
export declare function bindToStates<TState, TProps extends ForgoElementProps>(states: TState[], component: ForgoComponent<TProps>): ForgoComponent<TProps>;
export declare function bindToStateProps<TState, TProps extends ForgoElementProps>(stateBindings: [state: TState, propGetter?: (state: TState) => any[]][], component: ForgoComponent<TProps>): ForgoComponent<TProps>;
export declare function bindToStates<TState>(states: TState[], component: Component<any>): void;
export declare function bindToStateProps<TState>(stateBindings: [state: TState, propGetter?: (state: TState) => any[]][], component: Component<any>): void;

@@ -6,3 +6,3 @@ /*

- They bind this state (the proxy object) to various components via bindToStates() and bindToStateProps() functions.
- Since the proxy let's us capture changes to itself, we trigger component rerenders (on bound components) when that happens.
- Since the proxy lets us capture changes to itself, we trigger component rerenders (on bound components) when that happens.
*/

@@ -14,15 +14,10 @@ import { rerender, getForgoState, } from "forgo";

set(target, prop, value) {
const entries = stateToComponentsMap.get(proxy);
// if bound to the state directly, add for updation on any state change.
const stateBoundComponentArgs = entries
? entries
.filter((x) => !x.propGetter)
.map((x) => x.args)
: [];
const propBoundComponents = entries
? entries.filter((x) => x.propGetter)
: [];
var _a;
const entries = (_a = stateToComponentsMap.get(proxy)) !== null && _a !== void 0 ? _a : [];
// If bound to the state directly, mark for update on any state change
const stateBoundComponents = entries.filter((x) => !x.propGetter);
const propBoundComponents = entries.filter((x) => x.propGetter);
// Get the props before update
let propBoundComponentArgs = propBoundComponents.map((x) => ({
args: x.args,
const propBoundComponentProps = propBoundComponents.map((x) => ({
component: x.component,
props: x.propGetter(target),

@@ -32,4 +27,4 @@ }));

// Get the props after update
let updatedProps = propBoundComponents.map((x) => ({
args: x.args,
const propBoundComponentPropsUpdated = propBoundComponents.map((x) => ({
component: x.component,
props: x.propGetter(target),

@@ -40,12 +35,14 @@ }));

// So concat (a) and (b)
const argsListToUpdate = stateBoundComponentArgs.concat(propBoundComponentArgs
.filter((oldProp, i) => oldProp.props.some((p, j) => p !== updatedProps[i].props[j]))
.map((x) => x.args));
// concat latest updates with pending updates.
const componentsToUpdate = stateBoundComponents
.concat(propBoundComponentProps
.filter((oldProp, i) => oldProp.props.some((p, j) => p !== propBoundComponentPropsUpdated[i].props[j]))
.map((x) => x))
.map((x) => x.component);
// Concat latest updates with pending updates.
const argsToUpdatePlusPendingArgs = Array.from(new Set([
...Array.from(argsToRenderInTheNextCycle),
...argsListToUpdate,
...Array.from(componentsToRenderInTheNextCycle),
...componentsToUpdate,
]));
const componentStatesAndArgs = argsToUpdatePlusPendingArgs.map((x) => {
const state = getForgoState(x.element.node);
const componentStatesAndArgs = argsToUpdatePlusPendingArgs.map((component) => {
const state = getForgoState(component.__internal.element.node);
if (!state) {

@@ -55,3 +52,6 @@ throw new Error("Missing state on node.");

else {
return [state.components[x.element.componentIndex], x];
return [
state.components[component.__internal.element.componentIndex],
component,
];
}

@@ -61,7 +61,8 @@ });

// don't queue the child rerender.
const componentsToUpdate = componentStatesAndArgs.filter((item) => {
const [componentState, args] = item;
let node = args.element.node;
const dedupedComponentsToUpdate = componentStatesAndArgs.filter((item) => {
const [componentState, component] = item;
let node = component.__internal.element
.node;
let state = getForgoState(node);
let parentStates = state.components.slice(0, args.element.componentIndex);
let parentStates = state.components.slice(0, component.__internal.element.componentIndex);
while (node && state) {

@@ -81,5 +82,3 @@ if (parentStates.some((x) => componentStatesAndArgs.some(([compStateInArray]) => compStateInArray.component === x.component))) {

});
for (const [, args] of componentsToUpdate) {
argsToRenderInTheNextCycle.add(args);
}
dedupedComponentsToUpdate.forEach(([, component]) => componentsToRenderInTheNextCycle.add(component));
setTimeout(() => {

@@ -97,11 +96,12 @@ doRender();

// had queued, plus everything the subrender enqueues
const argsToRenderInTheNextCycle = new Set();
const componentsToRenderInTheNextCycle = new Set();
function doRender() {
if (argsToRenderInTheNextCycle.size > 0) {
for (const args of argsToRenderInTheNextCycle) {
if (args.element.node && args.element.node.isConnected) {
if (componentsToRenderInTheNextCycle.size > 0) {
for (const component of componentsToRenderInTheNextCycle) {
if (component.__internal.element.node &&
component.__internal.element.node.isConnected) {
// Dequeue the component before the render, so that if the component
// triggers more renders of itself they don't get no-op'd
argsToRenderInTheNextCycle.delete(args);
rerender(args.element);
componentsToRenderInTheNextCycle.delete(component);
rerender(component.__internal.element);
}

@@ -112,48 +112,39 @@ }

export function bindToStates(states, component) {
return bindToStateProps(states.map((state) => [state, undefined]), component);
bindToStateProps(states.map((state) => [state, undefined]), component);
}
export function bindToStateProps(stateBindings, component) {
const wrappedComponent = Object.assign(Object.assign({}, component), { mount(props, args) {
for (const [state, propGetter] of stateBindings) {
let entries = stateToComponentsMap.get(state);
if (!entries) {
entries = [];
stateToComponentsMap.set(state, entries);
}
if (propGetter) {
const newEntry = {
component: wrappedComponent,
propGetter,
args,
};
entries.push(newEntry);
}
else {
const newEntry = {
component: wrappedComponent,
args,
};
entries.push(newEntry);
}
component.addEventListener("mount", () => {
for (const [state, propGetter] of stateBindings) {
let entries = stateToComponentsMap.get(state);
if (!entries) {
entries = [];
stateToComponentsMap.set(state, entries);
}
if (component.mount) {
component.mount(props, args);
if (propGetter) {
const newEntry = {
component,
propGetter,
};
entries.push(newEntry);
}
},
unmount(props, args) {
for (const [state] of stateBindings) {
let entry = stateToComponentsMap.get(state);
if (entry) {
stateToComponentsMap.set(state, entry.filter((x) => x.component !== wrappedComponent));
}
else {
throw new Error("Component entry missing in state map.");
}
else {
const newEntry = {
component,
};
entries.push(newEntry);
}
if (component.unmount) {
component.unmount(props, args);
}
});
component.addEventListener("unmount", () => {
for (const [state] of stateBindings) {
let entry = stateToComponentsMap.get(state);
if (entry) {
stateToComponentsMap.set(state, entry.filter((x) => x.component !== component));
}
} });
return wrappedComponent;
else {
throw new Error("Component entry missing in state map.");
}
}
});
}
//# sourceMappingURL=index.js.map
{
"name": "forgo-state",
"version": "1.2.0",
"version": "2.0.0-alpha.0",
"type": "module",

@@ -13,14 +13,14 @@ "main": "./dist/index.js",

"peerDependencies": {
"forgo": "^3.1.0"
"forgo": "^4.0.0-alpha.0"
},
"devDependencies": {
"@types/jsdom": "^16.2.13",
"@types/mocha": "^9.0.0",
"@types/jsdom": "^16.2.14",
"@types/mocha": "^9.1.0",
"@types/should": "^13.0.0",
"esm": "^3.2.25",
"jsdom": "^17.0.0",
"mocha": "^9.0.3",
"jsdom": "^19.0.0",
"mocha": "^9.2.2",
"rimraf": "^3.0.2",
"should": "^13.2.3",
"typescript": "^4.3.5"
"typescript": "^4.6.3"
},

@@ -27,0 +27,0 @@ "scripts": {

@@ -6,8 +6,7 @@ /*

- They bind this state (the proxy object) to various components via bindToStates() and bindToStateProps() functions.
- Since the proxy let's us capture changes to itself, we trigger component rerenders (on bound components) when that happens.
- Since the proxy lets us capture changes to itself, we trigger component rerenders (on bound components) when that happens.
*/
import {
ForgoRenderArgs,
ForgoComponent,
Component,
ForgoElementProps,

@@ -20,13 +19,11 @@ rerender,

type StateBoundComponentInfo<TProps extends ForgoElementProps> = {
component: ForgoComponent<TProps>;
args: ForgoRenderArgs;
};
interface StateBoundComponentInfo {
component: Component;
}
type PropertyBoundComponentInfo<TState, TProps extends ForgoElementProps> = {
interface PropertyBoundComponentInfo<TState> extends StateBoundComponentInfo {
propGetter: (state: TState) => any[];
} & StateBoundComponentInfo<TProps>;
}
const stateToComponentsMap: Map<any, StateBoundComponentInfo<any>[]> =
new Map();
const stateToComponentsMap: Map<any, StateBoundComponentInfo[]> = new Map();

@@ -38,25 +35,17 @@ export function defineState<TState extends Record<string, any>>(

set(target: TState, prop: string & keyof TState, value: any) {
const entries = stateToComponentsMap.get(proxy);
const entries = stateToComponentsMap.get(proxy) ?? [];
// if bound to the state directly, add for updation on any state change.
const stateBoundComponentArgs: ForgoRenderArgs[] = entries
? entries
.filter(
(x) => !(x as PropertyBoundComponentInfo<TState, any>).propGetter
)
.map((x) => x.args)
: [];
// If bound to the state directly, mark for update on any state change
const stateBoundComponents: StateBoundComponentInfo[] = entries.filter(
(x) => !(x as PropertyBoundComponentInfo<TState>).propGetter
);
const propBoundComponents = entries
? entries.filter(
(x) => (x as PropertyBoundComponentInfo<TState, any>).propGetter
)
: [];
const propBoundComponents = entries.filter(
(x) => (x as PropertyBoundComponentInfo<TState>).propGetter
);
// Get the props before update
let propBoundComponentArgs = propBoundComponents.map((x) => ({
args: x.args,
props: (x as PropertyBoundComponentInfo<TState, any>).propGetter(
target
),
const propBoundComponentProps = propBoundComponents.map((x) => ({
component: x.component,
props: (x as PropertyBoundComponentInfo<TState>).propGetter(target),
}));

@@ -67,7 +56,5 @@

// Get the props after update
let updatedProps = propBoundComponents.map((x) => ({
args: x.args,
props: (x as PropertyBoundComponentInfo<TState, any>).propGetter(
target
),
const propBoundComponentPropsUpdated = propBoundComponents.map((x) => ({
component: x.component,
props: (x as PropertyBoundComponentInfo<TState>).propGetter(target),
}));

@@ -78,15 +65,19 @@

// So concat (a) and (b)
const argsListToUpdate = stateBoundComponentArgs.concat(
propBoundComponentArgs
.filter((oldProp, i) =>
oldProp.props.some((p, j) => p !== updatedProps[i].props[j])
)
.map((x) => x.args)
);
const componentsToUpdate = stateBoundComponents
.concat(
propBoundComponentProps
.filter((oldProp, i) =>
oldProp.props.some(
(p, j) => p !== propBoundComponentPropsUpdated[i].props[j]
)
)
.map((x) => x)
)
.map((x) => x.component);
// concat latest updates with pending updates.
// Concat latest updates with pending updates.
const argsToUpdatePlusPendingArgs = Array.from(
new Set([
...Array.from(argsToRenderInTheNextCycle),
...argsListToUpdate,
new Set<Component>([
...Array.from(componentsToRenderInTheNextCycle),
...componentsToUpdate,
])

@@ -97,9 +88,14 @@ );

NodeAttachedComponentState<any>,
ForgoRenderArgs
][] = argsToUpdatePlusPendingArgs.map((x) => {
const state = getForgoState(x.element.node as ChildNode);
Component
][] = argsToUpdatePlusPendingArgs.map((component) => {
const state = getForgoState(
component.__internal.element.node as ChildNode
);
if (!state) {
throw new Error("Missing state on node.");
} else {
return [state.components[x.element.componentIndex], x];
return [
state.components[component.__internal.element.componentIndex],
component,
];
}

@@ -110,38 +106,41 @@ });

// don't queue the child rerender.
const componentsToUpdate = componentStatesAndArgs.filter((item) => {
const [componentState, args] = item;
const dedupedComponentsToUpdate = componentStatesAndArgs.filter(
(item) => {
const [componentState, component] = item;
let node: ChildNode | null = args.element.node as ChildNode;
let state: NodeAttachedState | undefined = getForgoState(node);
let parentStates = (state as NodeAttachedState).components.slice(
0,
args.element.componentIndex
);
while (node && state) {
if (
parentStates.some((x) =>
componentStatesAndArgs.some(
([compStateInArray]) =>
compStateInArray.component === x.component
let node: ChildNode | null = component.__internal.element
.node as ChildNode;
let state: NodeAttachedState | undefined = getForgoState(node);
let parentStates = (state as NodeAttachedState).components.slice(
0,
component.__internal.element.componentIndex
);
while (node && state) {
if (
parentStates.some((x) =>
componentStatesAndArgs.some(
([compStateInArray]) =>
compStateInArray.component === x.component
)
)
)
) {
return false;
}
node = node.parentElement;
if (node) {
state = getForgoState(node);
if (state) {
parentStates = state.components.filter(
(x) => x !== componentState
);
) {
return false;
}
node = node.parentElement;
if (node) {
state = getForgoState(node);
if (state) {
parentStates = state.components.filter(
(x) => x !== componentState
);
}
}
}
return true;
}
return true;
});
);
for (const [, args] of componentsToUpdate) {
argsToRenderInTheNextCycle.add(args);
}
dedupedComponentsToUpdate.forEach(([, component]) =>
componentsToRenderInTheNextCycle.add(component)
);

@@ -164,13 +163,16 @@ setTimeout(() => {

// had queued, plus everything the subrender enqueues
const argsToRenderInTheNextCycle = new Set<ForgoRenderArgs>();
const componentsToRenderInTheNextCycle = new Set<Component>();
function doRender() {
if (argsToRenderInTheNextCycle.size > 0) {
for (const args of argsToRenderInTheNextCycle) {
if (args.element.node && args.element.node.isConnected) {
if (componentsToRenderInTheNextCycle.size > 0) {
for (const component of componentsToRenderInTheNextCycle) {
if (
component.__internal.element.node &&
component.__internal.element.node.isConnected
) {
// Dequeue the component before the render, so that if the component
// triggers more renders of itself they don't get no-op'd
argsToRenderInTheNextCycle.delete(args);
componentsToRenderInTheNextCycle.delete(component);
rerender(args.element);
rerender(component.__internal.element);
}

@@ -181,7 +183,7 @@ }

export function bindToStates<TState, TProps extends ForgoElementProps>(
export function bindToStates<TState>(
states: TState[],
component: ForgoComponent<TProps>
): ForgoComponent<TProps> {
return bindToStateProps(
component: Component<any>
): void {
bindToStateProps(
states.map((state) => [state, undefined]),

@@ -192,60 +194,46 @@ component

export function bindToStateProps<TState, TProps extends ForgoElementProps>(
export function bindToStateProps<TState>(
stateBindings: [state: TState, propGetter?: (state: TState) => any[]][],
component: ForgoComponent<TProps>
): ForgoComponent<TProps> {
const wrappedComponent = {
...component,
mount(props: TProps, args: ForgoRenderArgs) {
for (const [state, propGetter] of stateBindings) {
let entries = stateToComponentsMap.get(state);
component: Component<any>
): void {
component.addEventListener("mount", () => {
for (const [state, propGetter] of stateBindings) {
let entries = stateToComponentsMap.get(state);
if (!entries) {
entries = [];
stateToComponentsMap.set(state, entries);
}
if (!entries) {
entries = [];
stateToComponentsMap.set(state, entries);
}
if (propGetter) {
const newEntry: PropertyBoundComponentInfo<TState, TProps> = {
component: wrappedComponent,
propGetter,
args,
};
if (propGetter) {
const newEntry: PropertyBoundComponentInfo<TState> = {
component,
propGetter,
};
entries.push(newEntry);
} else {
const newEntry: StateBoundComponentInfo<TProps> = {
component: wrappedComponent,
args,
};
entries.push(newEntry);
} else {
const newEntry: StateBoundComponentInfo = {
component,
};
entries.push(newEntry);
}
entries.push(newEntry);
}
}
});
if (component.mount) {
component.mount(props, args);
}
},
unmount(props: TProps, args: ForgoRenderArgs) {
for (const [state] of stateBindings) {
let entry = stateToComponentsMap.get(state);
component.addEventListener("unmount", () => {
for (const [state] of stateBindings) {
let entry = stateToComponentsMap.get(state);
if (entry) {
stateToComponentsMap.set(
state,
entry.filter((x) => x.component !== wrappedComponent)
);
} else {
throw new Error("Component entry missing in state map.");
}
if (entry) {
stateToComponentsMap.set(
state,
entry.filter((x) => x.component !== component)
);
} else {
throw new Error("Component entry missing in state map.");
}
if (component.unmount) {
component.unmount(props, args);
}
},
};
return wrappedComponent;
}
});
}

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