rynex
Version:
A minimalist TypeScript framework for building reactive web applications with no virtual DOM
177 lines • 4.45 kB
JavaScript
/**
* Rynex Basic Elements
* Basic HTML elements and components
*/
import { createElement } from '../dom.js';
import { effect } from '../state.js';
/**
* Div element (generic container)
*/
export function div(props, ...children) {
return createElement('div', props, ...children);
}
/**
* Span element (inline container)
*/
export function span(props, ...children) {
return createElement('span', props, ...children);
}
/**
* Text element with reactive getter support
* Usage: text('static') or text(() => `Count: ${state.count}`) or text({ class: 'foo' }, 'static') or text({ class: 'foo' }, () => `Count: ${state.count}`)
*/
export function text(props, content) {
// Case 1: text('static string')
if (typeof props === 'string') {
return createElement('span', {}, props);
}
// Case 2: text(() => reactive)
if (typeof props === 'function') {
const el = createElement('span', {});
effect(() => {
el.textContent = props();
});
return el;
}
// Case 3: text({ props }, 'static') or text({ props }, () => reactive)
const el = createElement('span', props);
if (typeof content === 'function') {
// Reactive content
effect(() => {
el.textContent = content();
});
}
else if (content) {
// Static content
el.textContent = content;
}
return el;
}
/**
* Button element with reactive text support
* Usage: button({ onClick: ... }, 'Click') or button({ onClick: ... }, () => state.show ? 'Hide' : 'Show')
*/
export function button(props, content) {
const el = createElement('button', props);
if (typeof content === 'function') {
// Reactive text content
effect(() => {
el.textContent = content();
});
}
else if (typeof content === 'string') {
// Static text content
el.textContent = content;
}
else if (content) {
// Children elements
const children = Array.isArray(content) ? content : [content];
children.forEach(child => {
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
}
else if (child instanceof HTMLElement) {
el.appendChild(child);
}
});
}
return el;
}
/**
* Input element
*/
export function input(props) {
return createElement('input', props);
}
/**
* Image element
*/
export function image(props) {
const imgProps = { ...props };
if (props.lazy) {
imgProps.loading = 'lazy';
delete imgProps.lazy;
}
return createElement('img', imgProps);
}
/**
* Link/anchor element
*/
export function link(props, ...children) {
return createElement('a', props, ...children);
}
/**
* Label element
*/
export function label(props, ...content) {
return createElement('label', props, ...content);
}
/**
* Paragraph element
*/
export function p(props, ...content) {
return createElement('p', props, ...content);
}
/**
* List element with optimized rendering
*/
export function list(props) {
const { items, renderItem, keyExtractor, ...restProps } = props;
const children = items.map((item, index) => {
const child = renderItem(item, index);
if (keyExtractor) {
child.dataset.key = String(keyExtractor(item, index));
}
return child;
});
return createElement('div', restProps, ...children);
}
/**
* Unordered list
*/
export function ul(props, ...children) {
return createElement('ul', props, ...children);
}
/**
* Ordered list
*/
export function ol(props, ...children) {
return createElement('ol', props, ...children);
}
/**
* List item
*/
export function li(props, ...content) {
return createElement('li', props, ...content);
}
/**
* Horizontal rule
*/
export function hr(props = {}) {
return createElement('hr', props);
}
/**
* Line break
*/
export function br(props = {}) {
return createElement('br', props);
}
/**
* Description list
*/
export function dl(props, ...children) {
return createElement('dl', props, ...children);
}
/**
* Description term
*/
export function dt(props, ...content) {
return createElement('dt', props, ...content);
}
/**
* Description definition
*/
export function dd(props, ...content) {
return createElement('dd', props, ...content);
}
//# sourceMappingURL=basic_elements.js.map