@jay-js/system
Version:
A powerful and flexible TypeScript library for UI, state management, lazy loading, routing and managing draggable elements in modern web applications.
129 lines • 4.58 kB
JavaScript
import { state } from "../core/state.js";
import { subscriberManager } from "../core/subscriber.js";
export const REACTIVE_MARKER = Symbol("reactive");
export const SETVALUE_MARKER = Symbol("setValue");
export const SETCHILD_MARKER = Symbol("setChildren");
export const DERIVED_MARKER = Symbol("derived");
let derivedIdCounter = 0;
/**
* Creates a derived state that automatically recalculates whenever states
* accessed within the function change
*
* @template T Type of derived value
* @param fn Function that calculates the derived value
* @returns A state that updates when any dependency changes
*/
export function derived(fn) {
const derivedState = state(fn());
const derivedId = ++derivedIdCounter;
const effectFn = () => {
derivedState.set(fn());
};
// Adiciona metadados à função para gerar hash único
effectFn[DERIVED_MARKER] = true;
effectFn._derivedId = derivedId;
effect(effectFn);
return derivedState;
}
/**
* Executes a function and automatically monitors any state access
* to create a reactive effect. The function will be executed again when
* any accessed state changes.
*
* @param fn Function to be executed as an effect
*/
export function effect(fn) {
subscriberManager.setSubscriber(fn);
fn();
subscriberManager.clearSubscriber();
}
/**
* Creates a helper for setting values in objects reactively.
* When a state is accessed within the function, a subscription is automatically
* created to update the value when the state changes.
*
* @param fn Function that returns the value to be set
* @param element Optional HTMLElement to track subscriptions for automatic cleanup
* @returns Function for setting values in objects
*/
export function values(fn, element) {
const _set_value = Object.assign(() => {
if (_set_value._path.length > 0) {
let target = _set_value._object_ref;
for (let i = 0; i < _set_value._path.length - 1; i++) {
if (!target[_set_value._path[i]]) {
target[_set_value._path[i]] = {};
}
target = target[_set_value._path[i]];
}
const lastKey = _set_value._path[_set_value._path.length - 1];
target[lastKey] = _set_value._fn();
return;
}
_set_value._object_ref = _set_value._fn(); // Isso aqui é para o caso de setar o objeto todo, Mas talvez não faça sentido
}, {
_object_ref: undefined,
_path: [],
_fn: fn,
_element: element,
[SETVALUE_MARKER]: true,
});
return Object.assign((object, ...path) => {
_set_value._object_ref = object;
_set_value._path = path;
effect(_set_value);
}, {
[REACTIVE_MARKER]: true,
});
}
/**
* Creates a reactive effect for updating children of a DOM node.
* Automatically monitors state changes and triggers child updates.
*
* @param fn Function that generates the child elements
* @param nodeRefId Reference identifier for the target node
* @param setChild Callback function to execute when children need to be updated
* @param element Optional HTMLElement to track subscriptions for automatic cleanup
*/
export function childs(fn, nodeRefId, setChild, element) {
const _set_child = Object.assign(setChild, {
_fn: fn,
_ref: nodeRefId,
_element: element,
[SETCHILD_MARKER]: true,
});
effect(_set_child);
}
/**
* Generates a unique hash identifier for a function.
* Takes into account special markers (SETVALUE_MARKER, SETCHILD_MARKER) to create
* unique identifiers for reactive functions with additional metadata.
*
* @param fn Function to generate hash for
* @returns Hexadecimal hash string with optional suffix based on function markers
*/
export function generateFunctionHash(fn, path) {
let suffix = "";
let _fn = fn;
if (fn[SETVALUE_MARKER]) {
suffix = `__prop:${fn._path.join(".")}`;
_fn = fn._fn;
}
if (fn[SETCHILD_MARKER]) {
suffix = `__childref:${fn._ref}`;
_fn = fn._fn;
}
if (fn[DERIVED_MARKER]) {
suffix = `${suffix}__derived:${fn._derivedId}`;
}
suffix = path ? `${suffix}__target:${path}` : suffix;
const _fn_string = _fn.toString();
let hash = 0;
for (let i = 0; i < _fn_string.length; i++) {
const char = _fn_string.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash |= 0;
}
return `${Math.abs(hash).toString(16)}${suffix ? suffix : ""}`;
}
//# sourceMappingURL=helpers.js.map