Framework rendering fixes

This commit is contained in:
2025-10-20 15:09:16 +02:00
parent 3e0f2fb781
commit b23ef80a5f
4 changed files with 51 additions and 18 deletions

View File

@@ -26,9 +26,9 @@ const renderer = <T extends StringIndexedObject>( data: T, template: RenderTempl
if ( template.children.length === 0 ) {
if ( template.attribute ) {
parent.innerText = String( data[ template.attribute ] );
parent.textContent = String( data[ template.attribute ] );
} else {
parent.innerText = String( data );
parent.textContent = String( data );
}
}

View File

@@ -30,7 +30,7 @@ export const listRef = <T>( parent: HTMLElement, data: T[], name: string, templa
// Yes, I know, really bad performance, etc, but it's not needed for any other use case
// here, other than a full replace of the data (no dynamic updates)
list = data;
console.log( data );
parent.textContent = '';
// Render the list based on template
for ( let i = 0; i < data.length; i++ ) {
@@ -92,6 +92,7 @@ export const listRef = <T>( parent: HTMLElement, data: T[], name: string, templa
if ( !evaluation && rendered[ index ] ) {
// can use ! here, as semantics of program tell us that this index will exist
nodes[ index ]!.remove();
rendered[ index ] = false;
} else if ( evaluation && !rendered[ index ] ) {
currentIndexInChildrenList++;
parent.insertBefore( nodes[ index ]!, children[ currentIndexInChildrenList ]! );

View File

@@ -2,6 +2,17 @@ import {
Ref
} from './rendering';
interface ConditionalElement<T> {
'element': HTMLElement;
'predicate': ( value: T ) => boolean;
}
interface ConditionalClass {
'element': HTMLElement,
'onTrue': string,
'onFalse': string
}
/**
* Responsive data (similar behaviour as in Vue.js)
* @template T - The data type you wish to use (as long as you don't want it to be a list)
@@ -10,34 +21,44 @@ import {
*/
export const ref = <T>( elements: HTMLElement[], data: T ): Ref<T> => {
let value: T = data;
let conditionalElements: HTMLElement[] = [];
const conditionalElements: ConditionalElement<T>[] = [];
const onChangeFunctions: ( () => Promise<void> )[] = [];
const conditionalClasses: {
'element': HTMLElement,
'onTrue': string,
'onFalse': string
}[] = [];
const conditionalClasses: ConditionalClass[] = [];
const boundElements: HTMLInputElement[] = [];
// ───────────────────────────────────────────────────────────────────
/**
* Bind to a further element (DOM text is updated for it)
* @param element - The element to add
*/
const addAdditionalElement = ( element: HTMLElement ) => {
elements.push( element );
};
/**
* @returns The value the ref currently holds
*/
const get = (): T => {
return value;
};
// ───────────────────────────────────────────────────────────────────
/**
* @param data - The new value of the
*/
const set = ( data: T ): void => {
value = data;
// Update normal ref elements
elements.forEach( el => {
el.innerText = String( data );
el.textContent = String( data );
} );
// Update conditional elements
conditionalElements.forEach( el => {
// convert to boolean (explicitly)
el.hidden = Boolean( data );
el.element.hidden = !el.predicate( data );
} );
conditionalClasses.forEach( el => {
@@ -54,6 +75,7 @@ export const ref = <T>( elements: HTMLElement[], data: T ): Ref<T> => {
}
};
/**
* Bind to input change of an HTMLInputElement (two way bind)
* @param element - The element to bind to (i.e. add a two-way bind to)
@@ -63,17 +85,25 @@ export const ref = <T>( elements: HTMLElement[], data: T ): Ref<T> => {
element.addEventListener( 'change', () => {
set( castFunction( element.value ) );
} );
element.value = String( value );
boundElements.push( element );
};
/**
* Add elements to be rendered conditionally on this ref. Treats type as booleanish
* @param elements - The elements that are rendered consistently
* @param element - The element that will be affected by predicate
* @param predicate - The predicate to evaluate when value is changed
*/
const setConditionalElements = ( elements: HTMLElement[] ): void => {
conditionalElements = elements;
const addConditionalElementBind = ( element: HTMLElement, predicate: ( value: T ) => boolean ): void => {
conditionalElements.push( {
'element': element,
'predicate': predicate
} );
element.hidden = !predicate( value );
};
/**
* @param element - The element to do the operation on
* @param onTrue - The classes (as strings) to set if true(ish)
@@ -107,7 +137,8 @@ export const ref = <T>( elements: HTMLElement[], data: T ): Ref<T> => {
return {
set,
get,
setConditionalElements,
addAdditionalElement,
addConditionalElementBind,
addConditionalClasses,
bind,
onChange

View File

@@ -1,7 +1,8 @@
export interface Ref<T> {
'set': ( data: T ) => void;
'get': () => T;
'setConditionalElements': ( elements: HTMLElement[] ) => void;
'addAdditionalElement': ( elements: HTMLElement, predicate: ( value: T ) => boolean ) => void;
'addConditionalElementBind': ( elements: HTMLElement, predicate: ( value: T ) => boolean ) => void;
'addConditionalClasses': ( element: HTMLElement, onTrue: string, onFalse: string ) => void;
'bind': ( element: HTMLInputElement, castFunction: ( val: string ) => T ) => void;
'onChange': ( callback: () => void ) => void;